# Changelog All notable changes to ontoref are documented here. ADRs referenced below live in `adrs/` as typed Nickel records. --- ## [Unreleased] ### MCP tool catalog via proc-macro, validate ADR-018 mode hierarchy, UI vault/registry context **Session 2026-05-12** **`#[onto_mcp_tool]` proc-macro — link-time MCP catalog registration (`ontoref-derive`)** - New attribute macro that registers an MCP tool unit-struct in the catalog at link time via `inventory::submit!(McpToolEntry{...})`. The annotated item is emitted unchanged — `ToolBase` and `AsyncTool` impls remain on the struct. Required keys: `name`, `description`, `input_schema`. - All 34 MCP tools migrated from manual `catalog()` wiring to `#[onto_mcp_tool]`. The `catalog()` function is now generated automatically by `inventory::collect!`. - Tool count: 29 → 34 (net: `ontoref_list_projects`, `ontoref_search`, `ontoref_describe`, `ontoref_list_ontology_extensions`, `ontoref_get_ontology_extension` added). **`validate modes` — ADR-018 level hierarchy and strategy compliance (`reflection/modules/validate.nu`)** - `validate modes [--check]` — reads `reflection/defaults/workflow.ncl::level_hierarchy` and checks every `.ncl` mode file against the declared levels: level declared, strategy declared, delegate chain coherent, compose `extends` references valid. - `mode resolve ` — prints which hierarchy level handles the given mode id and why. - `validate modes --self-test` — generates synthetic mode fixtures in a temp dir and runs checks against them; fast CI-safe smoke test for the validator itself. **`validate run-cargo` — two-step Cargo.toml resolution** - Resolves `Cargo.toml` in workspace layout first (`crates//Cargo.toml`), then falls back to single-crate root when `[package].name` matches or `check.crate` equals the repo basename. Lets the same ADR constraint shape apply to workspace repos (stratumiops) and single-crate projects without per-repo special cases. **UI — vault and registry context in project_picker** - Each project card in the project picker now surfaces OCI state inline: - Registry badge (`⟳ `) when `manifest.ncl::registry_provides` is declared. - Vault badge (`⛁ · N`) coloured green (declarative) or amber (legacy) when `project.ncl::sops.enabled` is true. - Expanded project details panel: collapsible **Registry** section listing namespaces, endpoint, and push/pull capability per namespace. **UI — runtime service toggles in manage page** - `manage.html` gains a **Runtime Services** card: MCP and GraphQL can be toggled on/off via HTMX `POST /ui/manage/services/{service}/toggle` without restarting the daemon. - `insert_mcp_ctx` helper injects MCP and GraphQL runtime state + daemon version into every Tera template context that needs it. **Manifest schema — registry topology contract (`ontology/schemas/manifest.ncl`)** - New `registry_topology_type` contract: declares multi-registry coordination (which registries the project participates in, push targets, participant scopes, and per-namespace capability). - `manifest_type` gains optional `registry_topology` field. **Requirements — OCI tooling declared in `reflection/requirements/base.ncl`** - `oras ≥ 1.2.0` (Hard), `cosign ≥ 2.0.0` (Hard), `sops ≥ 3.9.0` (Hard), `age ≥ 1.1.0` (Hard), `restic` (Soft) added as named requirements with `check_cmd`, `version_extract`, and `install_hint`. Surfaces in `describe requirements` and `ontoref_guides`. **describe.nu + sync.nu expansion** - `describe capabilities` JSON output now includes `registry_topology` and `vault_state` per project when declared. - `sync diff --docs` drift check extended to detect `//!` absence on new crates added this session. --- ### Per-file recipient routing for tenant isolation (ADR-019) **Session 2026-05-03** — credential vault model extended to support per-file recipient routing, closing the multi-tenant gap without multi-vault. **Schema additions** (`install/resources/schemas/ontoref-project.ncl`) - `sops.recipient_groups` (record of group → list of age public keys, optional) - `sops.recipient_rules` (array of `{ path, groups }` records, optional) **Bootstrap behaviour** - When `recipient_rules` declared, `secrets-bootstrap` generates `/.sops.yaml` with sops `creation_rules` mapping each path_regex to the union of declared groups. - Default `registry/ro+rw.sops.yaml` pair is skipped in declarative mode — the operator defines files matching their tenancy scheme (e.g. `clientA-ro.sops.yaml`). - Legacy mode (no `recipient_rules`) keeps `SOPS_AGE_RECIPIENTS` env-var path. **Operational locks** - `secrets-add-key` and `secrets-remove-key` error in declarative mode and direct the operator to edit `project.ncl::sops.recipient_groups` plus `secrets-rekey`. - `secrets-rekey` regenerates `.sops.yaml` from `project.ncl` then runs `sops updatekeys` on every `*.sops.yaml` in the vault. **Adoption templates** (`install/resources/templates/sops/`) - `single-team/` — one team, no tenant separation (legacy / Path A) - `multi-tenant/` — clientA/clientB groups + path-routed credentials - `agent-first/` — admin/developer/agents with `agent-readonly.sops.yaml` for AI access **Integration templates** (`install/resources/templates/integration/`) - `domain-producer/` — contract.ncl + example.json + manifest.ncl scaffold - `mode-producer/` — provisioning.ncl + domains.lock.ncl + manifest.ncl scaffold - `mode-consumer/` — cabling.ncl scaffold for binding pulled modes to workspace values **Audit checks** (`secrets-audit`) — three new checks for ADR-019 constraints: - `recipient-routing-coherent` — every group referenced by a rule must be declared; every rule must resolve to ≥ 1 recipient - `recipient-routing-coverage` — every `*.sops.yaml` in the vault must match at least one declared rule - `no-multi-vault` — rejects `sops.vaults =` declaration (multi-vault not implemented) **FAQ entries** (`reflection/qa.ncl`) — six entries with diagrams: - `credential-vault-best-practice` — layered model with data-flow diagram - `credential-vault-templates` — three adoption paths (A/B/C) - `credential-vault-troubleshooting` — 15 named errors and recovery steps - `integration-what-and-why` — federated OCI artifacts (ADR-042) overview with diagram - `integration-how-to-implement` — producer / consumer / both, with templates - `integration-troubleshooting` — push/pull/invoke common failures **ADR-019: Per-File Recipient Routing for Tenant Isolation in lieu of Multi-Vault** Documents the decision, alternatives (multi-vault explicitly rejected), and 6 machine-checkable constraints. Each constraint is wired to either `secrets-audit` (NuCmd), `Grep`, or `FileExists` — verifiable from CLI without a custom validator. **Tests** — `reflection/tests/test_secrets.nu` covers 14/14 named errors of the helper contract end-to-end (`sops-decrypt-failed` excluded — requires real age keypair plumbing). **Bug fixes** - `_find-capabilities-ncl`: glob malformation when walking up to filesystem root - cosign `--tlog-upload=false` deprecated in cosign 2+ → use `--signing-config` with `rekorTlogUrls`/`rekorTlogConfig` stripped - cosign `sign` needed `DOCKER_CONFIG` to fetch manifest before signing - Cache hit in `domain-pull` / `mode-pull` bypassed authorization gate (reordered) - Per-file `(...)` interpolation traps in nu strings inside error messages - `add-key` / `remove-key` only mutated `access.sops.yaml` instead of all sops files in the vault --- ### VCS abstraction layer and agent workspace orchestration #### `'Framework` RepoKind - `ontology/schemas/manifest.ncl`: `'Framework` added to `repo_kind_type` enum. Reserved for projects that define protocol schemas — no consumer obligation, no domain activation. - `.ontology/manifest.ncl`: `repo_kind` corrected from `'DevWorkspace` to `'Framework`. ontoref is the protocol definition; the provisioning domain activating for its own repo was semantically incorrect. #### VCS abstraction layer (`reflection/modules/vcs.nu`) - New module exporting a uniform VCS API over jj and git: `detect`, `is-repo`, `show-committed`, `restore-file`, `remote-url`, `current-branch`, `uncommitted-files`, `commit-count`. - Detection is filesystem-based (`.jj/` vs `.git/`) — no config, no env var. - `reflection/modules/opmode.nu` and `reflection/hooks/git-event.nu` migrated to consume `vcs.nu` instead of hardcoded `^git` calls. - jj is strictly opt-in: all commands degrade to git when `.jj/` is absent. `jj` and `rad` are NOT listed as requirements in ontoref's manifest — they belong in the manifest of orchestration projects (e.g. vapora) that depend on them. #### Agent workspace orchestration (`reflection/bin/jjw.nu`) - New orchestration wrapper: `jjw agent create | step | publish | merge | discard`. Wraps jj workspace commands, `ontoref run/step` calls, and optional `rad patch open`. - `jjw agent create`: creates a jj workspace at `.agents//`, writes `.ontoref-run` metadata, starts an ontoref run for the given mode. - `jjw agent publish`: validates uncommitted changes, pushes to remote, opens a Radicle patch if a `rad` remote is configured; falls back to `git push` otherwise. - `jjw agent merge`: advances main, cleans the workspace, marks the ontoref run complete. - `reflection/bin/jjw-ncl-merge.nu`: jj custom merge tool for `.ontology/` NCL conflicts. Register via `~/.config/jj/config.toml` `[merge-tools.ncl]` — not auto-installed. - `reflection/bin/init-repo.nu`: VCS-aware repo initializer called by the `new_project` mode `init_repo` step. Detects jj/git state; defaults to `jj git init --colocate` (preferred for Radicle) when no VCS is present. #### ADR-013 - `adrs/adr-013-vcs-abstraction-layer.ncl`: documents the decision, two hard constraints (no direct ^git/^jj outside vcs.nu; jj/rad must not be required=true in ontoref manifest), and three rejected alternatives (env var, per-module inline detection, command-translation shim). #### on+re update - `core.ncl`: `vcs-abstraction` (adrs: ["adr-013"]) and `agent-workspace-orchestration` Practice nodes added with `artifact_paths` and edges into `reflection-modes`, `project-onboarding`, `no-enforcement`. - `manifest.ncl`: `vcs-abstraction` and `agent-workspace-orchestration` capabilities added (21 total). `reflection/bin/init-repo.nu` added to `project-onboarding` artifacts. --- ### Rust doc authoring pattern — canonical `///` convention #### `#[onto_api]` — `description` now optional - `description = "..."` parameter is no longer required when a `///` doc comment exists above the handler. The proc-macro reads the first `///` line as the fallback description. - Same fallback applied to `#[derive(OntologyNode)]` — `///` first line used when `description` attribute is absent. - `ontoref-daemon/src/api.rs`: 42 handlers migrated — `description = "..."` removed from all `#[onto_api]` blocks, canonical `///` first line added above each handler. #### `sync diff --docs --fail-on-drift` - New `--fail-on-drift` flag on `sync diff`: exits 1 when any crate `//!` has drifted from its ontology node description. Intended for pre-commit enforcement; without the flag, the command remains non-destructive and returns the table as before. #### mdBook `crates/` chapter - `generator.nu`: two helpers added — `read-crate-module-doc` (parses `//!` from `lib.rs`/`main.rs`) and `count-pub-coverage` (ratio of documented pub items). - `render-mdbook` generates `docs/src/crates/.md` per workspace member: `//!` content, pub item coverage badge, feature flags from `Cargo.toml`, and which practice nodes list the crate as primary `artifact_paths`. Missing `//!` renders a warning block. - `SUMMARY.md` gains a `# Crates` section with links to all generated pages. #### Pre-commit hooks - `.pre-commit-config.yaml`: `docs-links` hook runs rustdoc broken-link check (`RUSTDOCFLAGS` with `-D rustdoc::broken-intra-doc-links`) on `.rs` changes. - `.pre-commit-config.yaml`: `docs-drift` hook runs `sync diff --docs --fail-on-drift` on `.rs` changes. #### Agent and developer directives - `.claude/CLAUDE.md`: `### Documentation Authoring (Rust)` section added — three-layer table, four authoring rules, agent discovery commands (`describe workspace`, `describe features`, `sync diff --docs`), crate registration procedure. #### Migration - `0012-rust-doc-authoring-pattern`: consumer projects receive the `### Documentation Authoring (Rust)` section for their `CLAUDE.md` and optional pre-commit hooks (`docs-links`, `docs-drift`). --- ### Mode guards, convergence loops, and manifest coverage enforcement #### Mode schema extension (ADR-011) - **Guard type** added to `reflection/schema.ncl`: pre-flight executable checks with `Block` (abort) or `Warn` (continue) severity. Guards run before any step — the protocol pushes back on invalid state instead of failing silently mid-execution. - **Converge type** added to `reflection/schema.ncl`: post-execution convergence loop with `condition` command, `max_iterations` cap, and `RetryFailed`/`RetryAll` strategy. Modes iterate until a condition is met rather than running once blindly. - Both types exposed in `reflection/defaults.ncl` as `Guard` and `Converge`. - Reference implementation: `sync-ontology.ncl` gains 3 guards (ontology-exists, nickel-available, manifest-capabilities) and converge (iterate until zero drift, max 2 iterations). - `coder-workflow.ncl` gains guard (coder-dir-exists) and new `novelty-check` step (anti-slop Jaccard overlap detection between pending entries and published+QA). - Nushell executor (`reflection/nulib/modes.nu`): guard execution before steps, convergence loop after steps. - Rust types: `Guard`, `GuardSeverity`, `Converge`, `ConvergeStrategy` in `ontoref-reflection/src/mode.rs`. - Rust executor: guards evaluated pre-execution (Block returns error, Warn logs), convergence loop post-execution. - Backward compatible: `guards` defaults to `[]`, `converge` is optional. All 19 existing modes export unchanged. #### Manifest capability completeness (19 capabilities) - `.ontology/manifest.ncl` expanded from 3 to 19 declared capabilities covering the full action surface: protocol spec, daemon API, reflection modes, run/step tracking, Agent Task Composer, backlog graduation, notifications, coder process memory, QA store, form system, template generation, describe query layer, drift detection, quick actions, protocol migration, config surface, search bookmarks, project onboarding, web presence. - `audit-manifest-coverage` function in `reflection/modules/sync.nu`: cross-references Practice nodes, reflection modes, and daemon UI pages against declared capabilities. - `sync manifest-check` exported command for pre-commit hooks and CI. - `validate-project.ncl` gains 6th validation category: `manifest-cov`. - Pre-commit hook `manifest-coverage`: fires on `.ontology/`, `reflection/modes/`, `reflection/forms/` changes. - SessionStart hook (`session-context.sh`): shows manifest coverage status at session start. - Agent consumption mode description updated in manifest. #### Bug fixes - `find-unclaimed-artifacts` in `sync.nu`: fixed absolute vs relative path comparison for modes and forms. `path relative-to $root` applied before `starts-with` check. 19 phantom MISSING items resolved. - `audit-claude` session-hook check: accepts both `.claude/hooks/session-context.sh` and legacy `.claude/ontoref-session-start.sh`. - `describe mode` now shows guards and converge sections. - `scan-reflection-mode-dags` JSON output for agents now includes guards, converge, preconditions, postconditions, and step-level cmd/on_error/verify. #### Infrastructure - Justfile restructured: `justfiles/build.just`, `justfiles/test.just`, `justfiles/dev.just` added. CI recipes delegated to canonical modules. Manifest justfile convention updated to `Import` system with 5 modules. - Manifest `claude` baseline declared: `["rust", "nushell", "nickel"]` guidelines, session_hook enabled. - `.ontology/core.ncl`: `ci-pipelines` Practice node added. `reflection/forms/` added to `reflection-modes` artifact_paths. #### Migrations - `0010-manifest-capability-completeness`: consumer projects must declare ≥3 capabilities. - `0011-manifest-coverage-hooks`: consumer projects must add pre-commit and SessionStart hooks for manifest coverage. #### on+re update | Artifact | Change | |----------|--------| | `.ontology/manifest.ncl` | 3 → 19 capabilities; justfile/claude baselines declared; agent consumption mode updated | | `.ontology/core.ncl` | `ci-pipelines` node; `reflection/forms/` in reflection-modes; adr-011 in adr-lifecycle | | `.ontology/state.ncl` | protocol-maturity catalyst updated (ADR-011, 19 caps, migrations 0010-0012); self-description-coverage catalyst updated (session 2026-03-30) | | `adrs/adr-011-mode-guards-and-convergence.ncl` | New ADR: guards and converge extend mode schema rather than separate action subsystem | | Health | 43.2% → 100.0% (31 OK / 0 MISSING / 0 STALE) | --- ### Browser-style panel navigation + repo file routing Graph, search, and api_catalog pages now share a uniform browser-style navigation model: back/forward history stack with cursor-into-array semantics. File artifact paths open in external browser tabs rather than being loaded inline. #### `crates/ontoref-daemon/templates/pages/graph.html` - `.artifact-link` click handler changed from removed `openFile()` to `srcOpen()`. - `panelNav._replay` `type: "file"` case changed to `srcOpen(e.id)`. #### `crates/ontoref-daemon/templates/pages/search.html` - `openFileInPanel` async function removed entirely (was loading file content inline via `/api/file`). - `srcOpen(path)` function added: opens `{card_repo}/src/branch/main/{path}` for most files; opens `card_docs` for `.rs` files when configured. - `CARD_REPO` / `CARD_DOCS` JS constants injected via Tera (`| safe` filter required — Tera auto-escapes all `{{ }}` interpolations regardless of `