From a7ee8dee6f73397d442ae3d994554d2a4bed0a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20Pe=CC=81rez?= Date: Mon, 16 Mar 2026 01:48:17 +0000 Subject: [PATCH] feat: personal/career schemas, content modes, search bookmarks, Nu 0.111 compat (ADR-006), commit optimize --- .cargo/config.toml | 7 + .gitignore | 2 + .ontology/core.ncl | 97 +++- .ontology/state.ncl | 4 +- .ontoref/config.ncl | 2 + .ontoref/project.ncl | 5 +- .pre-commit-config.yaml | 2 +- CHANGELOG.md | 115 +++++ README.md | 24 +- ...shell-0111-string-interpolation-compat.ncl | 76 +++ assets/presentation/slides.md | 12 +- assets/web/index.html | 2 +- assets/web/public/keys-diagram.svg | 181 ++++++++ assets/web/src/index.html | 195 ++++++-- card.ncl | 25 + crates/ontoref-daemon/src/api.rs | 161 ++++++- crates/ontoref-daemon/src/main.rs | 124 ++++- crates/ontoref-daemon/src/mcp/mod.rs | 320 +++++++++++++ crates/ontoref-daemon/src/ui/handlers.rs | 243 +++++++++- crates/ontoref-daemon/src/ui/login.rs | 38 +- crates/ontoref-daemon/src/ui/mod.rs | 14 + .../src/ui/search_bookmarks_ncl.rs | 285 ++++++++++++ .../ontoref-daemon/templates/pages/graph.html | 88 ++++ .../ontoref-daemon/templates/pages/login.html | 31 ++ .../templates/pages/project_picker.html | 83 +++- .../templates/pages/search.html | 217 ++++++--- crates/ontoref-ontology/src/types.rs | 4 + install/gen-projects.nu | 22 +- install/install.nu | 53 ++- install/ontoref-daemon-boot | 2 +- install/ontoref-global | 82 +++- ontology/defaults/career.ncl | 23 + ontology/defaults/personal.ncl | 14 + ontology/defaults/project-card.ncl | 9 + ontology/schemas/career.ncl | 121 +++++ ontology/schemas/core.ncl | 3 +- ontology/schemas/manifest.ncl | 4 + ontology/schemas/personal.ncl | 85 ++++ ontology/schemas/project-card.ncl | 36 ++ ontoref | 82 +++- reflection/bin/ontoref.nu | 139 +++++- reflection/modes/draft-application.ncl | 76 +++ reflection/modes/draft-email.ncl | 55 +++ reflection/modes/generate-article.ncl | 73 +++ reflection/modes/update-cv.ncl | 68 +++ reflection/modes/write-cfp.ncl | 73 +++ reflection/modules/adr.nu | 2 +- reflection/modules/describe.nu | 439 +++++++++++++++++- reflection/modules/env.nu | 1 + reflection/nulib/fmt.nu | 2 +- reflection/nulib/help.nu | 87 +++- reflection/nulib/interactive.nu | 2 +- reflection/nulib/modes.nu | 11 +- reflection/schemas/search_bookmarks.ncl | 20 + reflection/search_bookmarks.ncl | 5 + 55 files changed, 3723 insertions(+), 223 deletions(-) create mode 100644 adrs/adr-006-nushell-0111-string-interpolation-compat.ncl create mode 100644 assets/web/public/keys-diagram.svg create mode 100644 card.ncl create mode 100644 crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs create mode 100644 ontology/defaults/career.ncl create mode 100644 ontology/defaults/personal.ncl create mode 100644 ontology/defaults/project-card.ncl create mode 100644 ontology/schemas/career.ncl create mode 100644 ontology/schemas/personal.ncl create mode 100644 ontology/schemas/project-card.ncl create mode 100644 reflection/modes/draft-application.ncl create mode 100644 reflection/modes/draft-email.ncl create mode 100644 reflection/modes/generate-article.ncl create mode 100644 reflection/modes/update-cv.ncl create mode 100644 reflection/modes/write-cfp.ncl create mode 100644 reflection/schemas/search_bookmarks.ncl create mode 100644 reflection/search_bookmarks.ncl diff --git a/.cargo/config.toml b/.cargo/config.toml index 8f53d51..43796db 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -18,6 +18,13 @@ lto = false panic = "unwind" incremental = true +[profile.clippy] +# Lint-only profile: no debug info, no codegen — clippy only needs MIR/HIR. +# Used by pre-commit to avoid bloating target/debug with DWARF/dSYM artifacts. +inherits = "dev" +debug = 0 +incremental = true + [profile.release] # Release profile - slow compilation, optimized binary opt-level = 3 diff --git a/.gitignore b/.gitignore index 96550bb..89c9375 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ CLAUDE.md .claude +logs +logs-archive utils/save*sh .fastembed_cache presentaciones diff --git a/.ontology/core.ncl b/.ontology/core.ncl index 8a43841..8aa492f 100644 --- a/.ontology/core.ncl +++ b/.ontology/core.ncl @@ -68,7 +68,7 @@ let d = import "../ontology/defaults/core.ncl" in name = "ADR Lifecycle", pole = 'Yang, level = 'Practice, - description = "Architectural decisions follow: Proposed → Accepted → Superseded. Superseded ADRs retain constraints for historical reconstruction. Active Hard constraints drive the constraint set.", + description = "Architectural decisions follow: Proposed → Accepted → Superseded. Superseded ADRs retain constraints for historical reconstruction. Active Hard constraints drive the constraint set. Nodes declare which ADRs validate them via the adrs field — surfaced by describe and the daemon graph UI.", artifact_paths = [ "adrs/schema.ncl", "adrs/reflection.ncl", @@ -78,8 +78,10 @@ let d = import "../ontology/defaults/core.ncl" in "adrs/adr-003-qa-and-knowledge-persistence-as-ncl.ncl", "adrs/adr-004-ncl-pipe-bootstrap-pattern.ncl", "adrs/adr-005-unified-auth-session-model.ncl", + "adrs/adr-006-nushell-0111-string-interpolation-compat.ncl", "CHANGELOG.md", ], + adrs = ["adr-001", "adr-002", "adr-003", "adr-004", "adr-005", "adr-006"], }, d.make_node { @@ -105,7 +107,7 @@ let d = import "../ontology/defaults/core.ncl" in name = "Describe Query Layer", pole = 'Yang, level = 'Practice, - description = "describe.nu aggregates all project sources and answers self-knowledge queries: what IS this, what can I DO, what can I NOT do, what tools exist, what is the impact of changing X.", + description = "describe.nu aggregates all project sources and answers self-knowledge queries: what IS this, what can I DO, what can I NOT do, what tools exist, what is the impact of changing X. Renders Validated by section when a node declares adrs — surfacing declared ADR constraints alongside source, examples, and connections.", artifact_paths = ["reflection/modules/describe.nu"], }, @@ -114,8 +116,9 @@ let d = import "../ontology/defaults/core.ncl" in name = "Ontoref Ontology Crate", pole = 'Yang, level = 'Practice, - description = "Rust implementation for loading and querying .ontology/ NCL files as typed structs. Provides the Core, Gate, and State types for ecosystem-level introspection.", + description = "Rust implementation for loading and querying .ontology/ NCL files as typed structs. Provides Core, Gate, and State types for ecosystem-level introspection. Node carries artifact_paths (Vec) and adrs (Vec) — both serde(default) for zero-migration backward compatibility.", artifact_paths = ["crates/ontoref-ontology/"], + adrs = ["adr-001"], }, d.make_node { @@ -146,6 +149,31 @@ let d = import "../ontology/defaults/core.ncl" in ], }, + d.make_node { + id = "ontology-three-file-split", + name = "Ontology Three-File Split", + pole = 'Yang, + level = 'Practice, + description = "The .ontology/ directory separates three orthogonal concerns into three files. core.ncl captures what the project IS — invariant axioms and structural tensions; touching invariant=true nodes requires a new ADR. state.ncl captures where it IS vs where it wants to BE — current and desired state per dimension. gate.ncl defines when it is READY to cross a boundary — active membranes protecting key conditions. reflection/ reads all three and answers self-knowledge queries. This separation lets an agent understand a project without reading code — only by consulting the declarative graph.", + invariant = false, + artifact_paths = [".ontology/core.ncl", ".ontology/state.ncl", ".ontology/gate.ncl"], + }, + + d.make_node { + id = "adr-node-linkage", + name = "ADR–Node Declared Linkage", + pole = 'Yang, + level = 'Practice, + description = "Nodes declare which ADRs validate them via the adrs field (Array String). This makes the ADR→Node relationship explicit in the graph rather than implicit in prose. describe surfaces a Validated by section per node. The daemon graph UI renders each ADR as a clickable link opening the full ADR via GET /api/adr/{id}. Field is serde(default) and Nickel default=[] — zero migration cost for existing nodes.", + artifact_paths = [ + "ontology/schemas/core.ncl", + "crates/ontoref-ontology/src/types.rs", + "reflection/modules/describe.nu", + "crates/ontoref-daemon/templates/pages/graph.html", + "crates/ontoref-daemon/src/api.rs", + ], + }, + d.make_node { id = "web-presence", name = "Web Presence", @@ -174,6 +202,7 @@ let d = import "../ontology/defaults/core.ncl" in "crates/ontoref-daemon/src/session.rs", "crates/ontoref-daemon/src/ui/auth.rs", "crates/ontoref-daemon/src/ui/login.rs", + "crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs", "justfiles/ci.just", ], }, @@ -257,6 +286,53 @@ let d = import "../ontology/defaults/core.ncl" in ], }, + d.make_node { + id = "personal-ontology-schemas", + name = "Personal Ontology Schemas", + pole = 'Yin, + level = 'Practice, + description = "Typed NCL schema layer for personal and career artifacts: career.ncl (Skills, WorkExperience, Talks, Positioning, CompanyTargets, PublicationCards), personal.ncl (Content and Opportunity lifecycle — BlogPost to CV to Application, Job to Conference to Grant), project-card.ncl (canonical display metadata for portfolio and cv_repo publication). All types carry linked_nodes referencing .ontology/core.ncl node IDs — bridging career artifacts into the DAG.", + invariant = false, + artifact_paths = [ + "ontology/schemas/career.ncl", + "ontology/schemas/personal.ncl", + "ontology/schemas/project-card.ncl", + "ontology/defaults/career.ncl", + "ontology/defaults/personal.ncl", + "ontology/defaults/project-card.ncl", + ], + }, + + d.make_node { + id = "content-modes", + name = "Content & Career Reflection Modes", + pole = 'Yang, + level = 'Practice, + description = "NCL DAG modes for personal content and career operations: draft-application (job/grant/collaboration application anchored in personal ontology — gate alignment check, node selection, career trajectory render), draft-email, generate-article, update-cv, write-cfp. Each mode queries personal.ncl and core.ncl nodes to ground output in declared project artifacts rather than free-form prose.", + invariant = false, + artifact_paths = [ + "reflection/modes/draft-application.ncl", + "reflection/modes/draft-email.ncl", + "reflection/modes/generate-article.ncl", + "reflection/modes/update-cv.ncl", + "reflection/modes/write-cfp.ncl", + ], + }, + + d.make_node { + id = "search-bookmarks", + name = "Search Bookmarks", + pole = 'Yin, + level = 'Practice, + description = "Persistent bookmark store for search results over the ontology graph. Entries typed as BookmarkEntry (id, node_id, kind, title, level, term, actor, created_at, tags) and persisted to reflection/search_bookmarks.ncl via line-level NCL surgery — same atomic-write pattern as qa_ncl.rs. IDs are sequential sb-NNN, zero-padded. Concurrency-safe via NclWriteLock. Supports add and remove; accessible from the daemon search UI.", + invariant = false, + artifact_paths = [ + "reflection/search_bookmarks.ncl", + "reflection/schemas/search_bookmarks.ncl", + "crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs", + ], + }, + d.make_node { id = "drift-observation", name = "Passive Drift Observation", @@ -283,6 +359,8 @@ let d = import "../ontology/defaults/core.ncl" in { from = "no-enforcement", to = "formalization-vs-adoption", kind = 'Resolves, weight = 'Medium }, { from = "protocol-not-runtime", to = "no-enforcement", kind = 'Implies, weight = 'High }, { from = "adr-lifecycle", to = "reflection-modes", kind = 'Complements, weight = 'Medium }, + { from = "adr-node-linkage", to = "adr-lifecycle", kind = 'ManifestsIn, weight = 'High }, + { from = "adr-node-linkage", to = "describe-query-layer", kind = 'Complements, weight = 'High }, { from = "describe-query-layer", to = "dag-formalized", kind = 'DependsOn, weight = 'High }, { from = "coder-process-memory", to = "describe-query-layer", kind = 'Complements, weight = 'Medium }, { from = "ontoref-daemon", to = "ontoref-ontology-crate", kind = 'Complements, weight = 'High }, @@ -319,6 +397,19 @@ let d = import "../ontology/defaults/core.ncl" in { from = "drift-observation", to = "reflection-modes", kind = 'DependsOn, weight = 'High, note = "Invokes sync-ontology mode steps (scan, diff) as read-only sub-processes." }, + # Personal Ontology Schemas edges + { from = "personal-ontology-schemas", to = "dag-formalized", kind = 'ManifestsIn, weight = 'High, + note = "Career and personal artifacts are typed NCL records with linked_nodes — DAG connections into the core ontology." }, + { from = "personal-ontology-schemas", to = "self-describing", kind = 'Complements, weight = 'Medium, + note = "Personal/career schemas let projects describe not just what they ARE but who built them and for what trajectory." }, + { from = "content-modes", to = "reflection-modes", kind = 'ManifestsIn, weight = 'High }, + { from = "content-modes", to = "personal-ontology-schemas", kind = 'DependsOn, weight = 'High, + note = "Content and career modes query personal.ncl and core.ncl to ground output in declared artifacts." }, + { from = "search-bookmarks", to = "qa-knowledge-store", kind = 'Complements, weight = 'High, + note = "Both are NCL persistence layers using the same atomic-write surgery pattern. Q&A is for accumulated knowledge; bookmarks are for search navigation state." }, + { from = "search-bookmarks", to = "ontoref-daemon", kind = 'ManifestsIn, weight = 'High }, + { from = "ontoref-daemon", to = "search-bookmarks", kind = 'Contains, weight = 'High }, + # Unified Auth Model edges { from = "unified-auth-model", to = "ontoref-daemon", kind = 'ManifestsIn, weight = 'High }, { from = "unified-auth-model", to = "no-enforcement", kind = 'Contradicts, weight = 'Low, diff --git a/.ontology/state.ncl b/.ontology/state.ncl index 4200cce..69c8d8f 100644 --- a/.ontology/state.ncl +++ b/.ontology/state.ncl @@ -25,7 +25,7 @@ let d = import "../ontology/defaults/state.ncl" in to = "protocol-stable", condition = "ADR-001 accepted, ontoref.dev published, at least two external projects consuming the protocol.", catalyst = "First external adoption.", - blocker = "ontoref.dev not yet published; no external consumers yet. Auth model complete (session exchange, CLI Bearer, key rotation invalidation). Install pipeline: config form roundtrip and NATS topology operational; check-config-sync CI guard present.", + blocker = "ontoref.dev not yet published; no external consumers yet. Auth model complete. Install pipeline complete. Personal/career schema layer present; content modes operational. Nu 0.111 compat fixed (ADR-006). Syntaxis syntaxis-ontology crate has pending ES→EN migration errors.", horizon = 'Months, }, ], @@ -52,7 +52,7 @@ let d = import "../ontology/defaults/state.ncl" in from = "modes-and-web-present", to = "fully-self-described", condition = "At least 3 ADRs accepted, reflection/backlog.ncl present, describe project returns complete picture.", - catalyst = "ADR-001–ADR-004 authored (4 ADRs present, 3+ threshold met). Auth model, project onboarding, and session management nodes added to core.ncl in session 2026-03-13.", + catalyst = "ADR-001–ADR-006 authored (6 ADRs present). Auth model, project onboarding, and session management nodes added in 2026-03-13. Personal/career/project-card schemas, 5 content modes, search bookmarks, and ADR-006 (Nu 0.111 compat) added in session 2026-03-15.", blocker = "none", horizon = 'Weeks, }, diff --git a/.ontoref/config.ncl b/.ontoref/config.ncl index 020b6cd..5b4cafc 100644 --- a/.ontoref/config.ncl +++ b/.ontoref/config.ncl @@ -66,4 +66,6 @@ actors = ["developer", "agent"], }, ], + + card = import "../card.ncl", } diff --git a/.ontoref/project.ncl b/.ontoref/project.ncl index 95e92f2..da36af7 100644 --- a/.ontoref/project.ncl +++ b/.ontoref/project.ncl @@ -3,6 +3,9 @@ let s = import "ontoref-project.ncl" in s.make_project { slug = "ontoref", root = "/Users/Akasha/Development/ontoref", - nickel_import_paths = ["/Users/Akasha/Development/ontoref"], + nickel_import_paths = [ + "/Users/Akasha/Development/ontoref", + "/Users/Akasha/Development/ontoref/ontology", + ], keys = [], } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a1319c9..90cf45c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: rust-clippy name: Rust linting (cargo clippy) - entry: bash -c 'cargo clippy --all-targets -- -D warnings' + entry: bash -c 'CARGO_TARGET_DIR=target cargo clippy --all-targets --no-deps --profile clippy -- -D warnings' language: system types: [rust] pass_filenames: false diff --git a/CHANGELOG.md b/CHANGELOG.md index ccb459c..363fbca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,121 @@ ADRs referenced below live in `adrs/` as typed Nickel records. ## [Unreleased] +### Personal Ontology Schemas & Content Modes + +Three new typed NCL schema families added to `ontology/schemas/` and `ontology/defaults/`: + +| Schema | Types exported | +| --- | --- | +| `career.ncl` | `Skill`, `WorkExperience`, `Talk`, `Positioning`, `CompanyTarget`, `PublicationCard`, `CareerConfig` | +| `personal.ncl` | `Content` (BlogPost / ConferenceProposal / CV / Application / Email / Thread), `Opportunity` (Job / Conference / Grant / Collaboration / Podcast), `PersonalConfig` | +| `project-card.ncl` | `ProjectCard` — canonical display metadata (name, tagline, status, tags, tools, features, sort_order) for portfolio and cv_repo publication | + +All types carry `linked_nodes | Array String` referencing `.ontology/core.ncl` node IDs. +`PublicationCard` is a career overlay referencing a canonical `project_node` from the portfolio repo. + +Five NCL DAG reflection modes added to `reflection/modes/`: + +| Mode | Purpose | +| --- | --- | +| `draft-application` | Job/grant/collaboration application anchored in personal ontology — gate alignment check, node selection, career trajectory render, status update | +| `draft-email` | Context-grounded email composition using ontology nodes as evidence | +| `generate-article` | Blog post / thread generation from project nodes and tensions | +| `update-cv` | CV refresh loop querying current career.ncl and core.ncl state | +| `write-cfp` | Conference proposal from Practice/Project nodes with gate alignment check | + +### Search Bookmarks + +Bookmark persistence for search results over the ontology graph. Mirrors Q&A NCL pattern (ADR-003). + +- `reflection/schemas/search_bookmarks.ncl` — `BookmarkEntry` (id, node_id, kind, title, level, term, actor, created_at, tags) and `BookmarkStore` contracts +- `reflection/search_bookmarks.ncl` — typed store file; conforms to `BookmarkStore` contract +- `crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs` — `add_entry` / `remove_entry` via + line-level NCL surgery; auto-incremented `sb-NNN` ids; concurrency-safe via `NclWriteLock` + +Tests: `next_id_empty`, `next_id_increments`, `insert_into_empty_store`, `delete_first_entry`, +`delete_second_entry`, `delete_missing_id_errors`, `escape_quotes_and_backslashes`, +`concurrent_add_produces_unique_ids` (tokio, 6 concurrent tasks, asserts unique ids). + +### Protocol + +- ADR-006 accepted: Nushell 0.111 string interpolation compatibility fix. Four print statements in + `reflection/bin/ontoref.nu` used `(identifier: expr)` patterns inside `$"..."` — parsed as + command calls by Nu 0.111 parser. Fix: bare `identifier: (expr)` for label-value pairs; plain + strings (no `$`) for zero-interpolation prints. Hard constraint: no `(label: expr)` inside + `$"..."` in any `.nu` file. Soft constraint: zero-interpolation strings must not use `$"..."`. + ([adr-006](adrs/adr-006-nushell-0111-string-interpolation-compat.ncl)) + +### Self-Description — on+re Update + +`.ontology/core.ncl` — 3 new Practice nodes, updated `adr-lifecycle` and `ontoref-daemon` nodes: + +| Change | Detail | +| --- | --- | +| New node `personal-ontology-schemas` | Yin — career/personal/project-card typed NCL schemas with linked_nodes DAG bridges | +| New node `content-modes` | Yang — 5 NCL DAG modes for personal content and career operations | +| New node `search-bookmarks` | Yin — bookmark persistence layer; NCL surgery via search_bookmarks_ncl.rs | +| `adr-lifecycle` | ADR-006 added to `artifact_paths` and `adrs` list | +| `ontoref-daemon` | `search_bookmarks_ncl.rs` added to `artifact_paths` | + +New edges: `personal-ontology-schemas → dag-formalized` (ManifestsIn/High), +`personal-ontology-schemas → self-describing` (Complements/Medium), +`content-modes → reflection-modes` (ManifestsIn/High), +`content-modes → personal-ontology-schemas` (DependsOn/High), +`search-bookmarks → qa-knowledge-store` (Complements/High), +`search-bookmarks → ontoref-daemon` (ManifestsIn/High), +`ontoref-daemon → search-bookmarks` (Contains/High). + +`.ontology/state.ncl` — `self-description-coverage` catalyst updated to include 2026-03-15 session +additions. `protocol-maturity` blocker updated to reflect Nu 0.111 fix and personal schema layer +completion. + +Previous: 4 axioms, 2 tensions, 17 practices. Current: 4 axioms, 2 tensions, 20 practices. + +--- + +### ADR–Node Declared Linkage + +- `Node` schema extended with `adrs | Array String | default = []` (Nickel `ontology/schemas/core.ncl` + and inline `CoreConfig` type). +- Rust `Node` struct gains `artifact_paths: Vec` and `adrs: Vec`, both + `#[serde(default)]` — zero migration cost for existing nodes that omit the fields. +- `describe.nu` `build-howto` populates `adrs` from the node record; `render-howto` (ANSI), + `render-howto-md`, and `howto-to-md-string` (clipboard) all emit a **Validated by** section + when `adrs` is non-empty. +- New `GET /api/adr/{id}?slug=` endpoint — reads `adrs/.ncl`, exports via NCL + cache, returns JSON. No auth required (read-only, loopback boundary). +- Graph UI (`graph.html`): `adrs` field passed into Cytoscape node data. Detail panel renders + "Validated by" section with clickable `◆ ` buttons that open a DaisyUI modal + fetching full ADR content via the new endpoint. +- Fixed glob pattern error in `describe.nu:build-howto`: `glob $"($full)/*.rs"` replaced with + `glob ($full | path join "*.rs")` — eliminates `//` in pattern when path has trailing separator. + +### Self-Description — on+re Update + +`.ontology/core.ncl` — new node, updated nodes, new edges: + +| Change | Detail | +| --- | --- | +| New node `adr-node-linkage` | Practice: declares `adrs` field pattern, lists all 5 modified artifacts | +| `adr-lifecycle` | Description updated; `adrs = ["adr-001"…"adr-005"]` declared | +| `describe-query-layer` | Description updated to mention Validated by rendering | +| `ontoref-ontology-crate` | Description updated to mention `artifact_paths` + `adrs` fields; `adrs = ["adr-001"]` | +| New edge `adr-node-linkage → adr-lifecycle` | ManifestsIn/High | +| New edge `adr-node-linkage → describe-query-layer` | Complements/High | + +Previous: 4 axioms, 2 tensions, 16 practices. Current: 4 axioms, 2 tensions, 17 practices. + +### Ontology Three-File Split + +- New Practice node `ontology-three-file-split` in `.ontology/core.ncl`: documents the + `core.ncl` (what IS) / `state.ncl` (where we ARE vs want to BE) / `gate.ncl` (when READY + to cross a boundary) separation and the role of `reflection/` in answering self-knowledge + queries without reading code. +- `assets/presentation/slides.md` speaker note updated to English with reflection mention. +- `assets/web/src/index.html` "Scattered Project Knowledge" solution bullets updated (bilingual) + to express the three-file split and `reflection/` self-knowledge layer. + ### Auth & Session Model (ADR-005) Unified key-to-session token exchange across all surfaces. All work gated on `#[cfg(feature = "ui")]`. diff --git a/README.md b/README.md index 9f90899..1004259 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,9 @@ crates/ Rust implementation — typed struct loaders and mode executo | Crate | Purpose | | --- | --- | -| `ontoref-ontology` | `.ontology/` NCL → typed Rust structs: Node, Edge, Dimension, Gate, Membrane. Graph traversal, invariant queries. Zero deps. | +| `ontoref-ontology` | `.ontology/` NCL → typed Rust structs: Node, Edge, Dimension, Gate, Membrane. `Node` carries `artifact_paths` and `adrs` (`Vec`, both `serde(default)`). Graph traversal, invariant queries. Zero deps. | | `ontoref-reflection` | NCL DAG contract executor: ADR lifecycle, step dep resolution, config seal. `stratum-graph` + `stratum-state` required. | -| `ontoref-daemon` | HTTP UI (10 pages), actor registry, notification barrier, MCP (19 tools), search engine, SurrealDB, NCL export cache. | +| `ontoref-daemon` | HTTP UI (10 pages), actor registry, notification barrier, MCP (21 tools), search engine, search bookmarks, SurrealDB, NCL export cache. | `ontoref-daemon` caches `nickel export` results (keyed by path + mtime), reducing full sync scans from ~2m42s to <30s. The daemon is always optional — every module falls back to direct @@ -54,8 +54,8 @@ automatically. **Q&A Knowledge Store** — accumulated Q&A entries persist to `reflection/qa.ncl` (typed NCL, git-versioned). Not localStorage. Any actor — developer, agent, CI — reads the same store. -**MCP Server** — 19 tools over stdio and streamable-HTTP. Categories: nodes, ADRs, modes, -backlog, Q&A, sessions, search, notifications. Representative subset: +**MCP Server** — 21 tools over stdio and streamable-HTTP. Categories: nodes, ADRs, modes, +backlog, Q&A, sessions, search, bookmarks, notifications. Representative subset: | Tool | What it does | | --- | --- | @@ -68,6 +68,22 @@ backlog, Q&A, sessions, search, notifications. Representative subset: | `ontoref_describe` | Describe project ontology and constraints | | `ontoref_sync_scan` | Scan for ontology drift | +**Search Bookmarks** — search results persist to `reflection/search_bookmarks.ncl` (typed NCL, +`BookmarkEntry` schema). Same atomic-write pattern as Q&A. IDs are sequential `sb-NNN`. +Concurrency-safe via `NclWriteLock`. Add and remove from the daemon search UI. + +**Personal Ontology Schemas** — `ontology/schemas/career.ncl`, `personal.ncl`, `project-card.ncl` +provide typed contract layers for career and content artifacts (Skills, WorkExperience, Talks, +Content lifecycle, Opportunities, PublicationCards). All types carry `linked_nodes` referencing +core ontology node IDs — bridging career artifacts into the DAG. Five content/career reflection +modes (`draft-application`, `draft-email`, `generate-article`, `update-cv`, `write-cfp`) query +these schemas to ground output in declared project artifacts rather than free-form prose. + +**ADR–Node Linkage** — nodes declare which ADRs validate them via `adrs: Array String`. +`describe` surfaces a **Validated by** section per node (CLI and `--fmt md`). The graph UI +renders each ADR as a clickable link that opens the full ADR content in a modal via +`GET /api/adr/{id}`. + **Passive Drift Observation** — background file watcher that detects divergence between Yang code artifacts and Yin ontology. Watches `crates/`, `.ontology/`, `adrs/`, `reflection/modes/`. After a 15s debounce runs `sync scan + sync diff`; emits an `ontology_drift` notification when diff --git a/adrs/adr-006-nushell-0111-string-interpolation-compat.ncl b/adrs/adr-006-nushell-0111-string-interpolation-compat.ncl new file mode 100644 index 0000000..0359aea --- /dev/null +++ b/adrs/adr-006-nushell-0111-string-interpolation-compat.ncl @@ -0,0 +1,76 @@ +let d = import "adr-defaults.ncl" in + +d.make_adr { + id = "adr-006", + title = "Nushell 0.111 String Interpolation Compatibility Fix", + status = 'Accepted, + date = "2026-03-14", + + context = "Nushell 0.111 introduced a breaking change in string interpolation parsing: expressions inside `$\"...\"` that match the pattern `(identifier: expr)` are now parsed as command calls rather than as record literals or literal text. This broke four print statements in reflection/bin/ontoref.nu that used patterns like `(kind: ($kind))`, `(logo: ($logo_file))`, `(parents: ($parent_slugs))`, and `(POST /actors/register)`. The bug manifested when running `ontoref setup` and `ontoref hooks-install` on any consumer project using Nu 0.111+. The minimum Nu version gate (>= 0.110.0) did not catch 0.111 regressions since it only guards the lower bound.", + + decision = "Fix all four affected print statements by removing the outer parentheses from label-value pairs inside string interpolations, or by removing the `$` prefix from strings that contain no variable interpolation. The fix is minimal and non-semantic: `(kind: ($kind))` becomes `kind: ($kind)` (literal label + variable), and `$\"(POST /actors/register)\"` becomes `\"(POST /actors/register)\"` (plain string). The fix is applied to both the dev repo (reflection/bin/ontoref.nu) and the installed copy (~/.local/bin/ontoref via just install-daemon). The minimum version gate remains >= 0.110.0 but 0.111 is now the tested floor.", + + rationale = [ + { + claim = "Minimal-diff fix over workarounds", + detail = "The broken patterns were purely cosmetic print statements. The fix removes one level of parens — no logic change. Alternatives that added escape sequences or string concatenation would obscure the intent.", + }, + { + claim = "Plain string for zero-interpolation prints", + detail = "Strings with no variable interpolation (like the POST endpoint hint) should never use `$\"...\"`. Removing the `$` prefix makes them immune to any future interpolation parsing changes and is the correct Nushell idiom.", + }, + { + claim = "just install-daemon as the sync mechanism", + detail = "The installed copy at ~/.local/bin/ontoref is managed via just install-daemon. Patching both the dev repo and the installed copy via install-daemon is the established update path and keeps them in sync.", + }, + ], + + consequences = { + positive = [ + "ontoref setup and hooks-install work correctly on Nushell 0.111+", + "All consumer projects (vapora, typedialog, evol-rustelo) can run setup without errors", + "Plain-string fix removes implicit fragility from zero-interpolation print statements", + ], + negative = [ + "The 0.111 regression was not caught by the version gate — the gate only guards >= 0.110.0 and does not test 0.111 compatibility proactively", + ], + }, + + alternatives_considered = [ + { + option = "Raise minimum Nu version to 0.111 and document the breaking change", + why_rejected = "Does not fix the broken syntax — just makes the breakage explicit. Consumer projects already on 0.111 would still fail until the print statements are fixed.", + }, + { + option = "Use escape sequences or string concatenation to embed literal parens", + why_rejected = "Nushell has no escape for parens in string interpolation. String concatenation (e.g. `'(kind: ' + $kind + ')'`) works but is significantly less readable than bare `kind: ($kind)`.", + }, + ], + + constraints = [ + { + id = "no-label-value-parens-in-interpolation", + claim = "String interpolations in ontoref.nu must not use `(identifier: expr)` patterns — use bare `identifier: (expr)` instead", + scope = "ontoref (reflection/bin/ontoref.nu, all .nu files)", + severity = 'Hard, + check_hint = "rg '\\([a-z_]+: \\(' reflection/bin/ontoref.nu", + rationale = "Nushell 0.111 parses (identifier: expr) inside $\"...\" as a command call. The fix pattern (bare label + variable interpolation) is equivalent visually and immune to this parser behaviour.", + }, + { + id = "plain-string-for-zero-interpolation", + claim = "Print statements with no variable interpolation must use plain strings, not `$\"...\"`", + scope = "ontoref (all .nu files)", + severity = 'Soft, + check_hint = "rg '\\$\"[^(]*\"' reflection/ | grep -v '\\$('", + rationale = "Zero-interpolation `$\"...\"` strings are fragile against future parser changes and mislead readers into expecting variable substitution.", + }, + ], + + related_adrs = [], + + ontology_check = { + decision_string = "Fix four Nu 0.111 string interpolation regressions in ontoref.nu; enforce no (label: expr) inside interpolations; use plain strings for zero-interpolation prints", + invariants_at_risk = [], + verdict = 'Safe, + }, +} diff --git a/assets/presentation/slides.md b/assets/presentation/slides.md index ba58823..35a8867 100644 --- a/assets/presentation/slides.md +++ b/assets/presentation/slides.md @@ -743,10 +743,14 @@ Es un grafo consultable que el sistema y los agentes leen.