ontoref/CHANGELOG.md
Jesús Pérez 13b03d6edf
Some checks failed
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
feat: mode guards, convergence, manifest coverage, doc authoring pattern
## Mode guards and convergence loops (ADR-011)

  - `Guard` and `Converge` types added to `reflection/schema.ncl` and
    `reflection/defaults.ncl`. Guards run pre-flight checks (Block/Warn);
    converge loops iterate until a condition is met (RetryFailed/RetryAll).
  - `sync-ontology.ncl`: 3 guards + converge (zero-drift condition, max 2 iter).
  - `coder-workflow.ncl`: guard (coder-dir-exists) + `novelty-check` step.
  - Rust types in `ontoref-reflection/src/mode.rs`; executor in `executor.rs`
    evaluates guards before steps and convergence loop after.
  - `adrs/adr-011-mode-guards-and-convergence.ncl` added.

  ## Manifest capability completeness

  - `.ontology/manifest.ncl`: 3 → 19 declared capabilities covering the full
    action surface (daemon API, modes, Task Composer, QA, bookmarks, etc.).
  - `sync.nu`: `audit-manifest-coverage` + `sync manifest-check` command.
  - `validate-project.ncl`: 6th category `manifest-cov`.
  - Pre-commit hook `manifest-coverage` added.
  - Migrations `0010-manifest-capability-completeness`,
    `0011-manifest-coverage-hooks`.

  ## Rust doc authoring pattern — canonical `///` convention

  - `#[onto_api]`: `description = "..."` optional when `///` doc comment exists
    above handler — first line used as fallback. `#[derive(OntologyNode)]` same.
  - `ontoref-daemon/src/api.rs`: 42 handlers migrated to `///` doc comments;
    `description = "..."` removed from all `#[onto_api]` blocks.
  - `sync diff --docs --fail-on-drift`: exits 1 on crate `//!` drift; used by
    new `docs-drift` pre-commit hook. `docs-links` hook checks rustdoc broken links.
  - `generator.nu`: mdBook `crates/` chapter — per-crate page from `//!` doc,
    coverage badge, feature flags, implementing practice nodes.
  - `.claude/CLAUDE.md`: `### Documentation Authoring (Rust)` section added.
  - Migration `0012-rust-doc-authoring-pattern`.

  ## OntologyNode derive fixes

  - `#[derive(OntologyNode)]`: `name` and `paths` attributes supported; `///`
    doc fallback for `description`; `artifact_paths` correctly populated.
  - `Core::from_value` calls `merge_contributors()` behind `#[cfg(feature = "derive")]`.

  ## Bug fixes

  - `sync.nu` drift check: exact crate path match (not `str starts-with`);
    first-path-only rule; split on `. ` not `.` to avoid `.ontology/` truncation.
  - `find-unclaimed-artifacts`: fixed absolute vs relative path comparison.
  - Rustdoc broken intra-doc links fixed across all three crates.
  - `ci-docs` recipe now sets `RUSTDOCFLAGS` and actually fails on errors.

  mode guards/converge, manifest coverage validation, 19 capabilities (ADR-011)

  Extend the mode schema with Guard (pre-flight Block/Warn checks) and Converge
  (RetryFailed/RetryAll post-execution loops) — protocol pushes back on invalid
  state and iterates until convergence. ADR-011 records the decision to extend
  modes rather than create a separate action subsystem.

  Manifest expanded from 3 to 19 capabilities covering the full action surface
  (compose, plans, backlog graduation, notifications, coder pipeline, forms,
  templates, drift, quick actions, migrations, config, onboarding). New
  audit-manifest-coverage validator + pre-commit hook + SessionStart hook
  ensure agents always see complete project self-description.

  Bug fix: find-unclaimed-artifacts absolute vs relative path comparison —
  19 phantom MISSING items resolved. Health 43% → 100%.

  Anti-slop: coder novelty-check step (Jaccard overlap against published+QA)
  inserted between triage and publish in coder-workflow.

  Justfile restructured into 5 modules (build/test/dev/ci/assets).
  Migrations 0010-0011 propagate requirements to consumer projects.
2026-03-30 19:08:25 +01:00

48 KiB
Raw Permalink Blame History

Changelog

All notable changes to ontoref are documented here. ADRs referenced below live in adrs/ as typed Nickel records.


[Unreleased]

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/<name>.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 <script> context).
  • .s-file-link click delegation updated to call srcOpen.
  • dpNav._replay type: "file" case calls srcOpen.

crates/ontoref-daemon/templates/pages/api_catalog.html

  • ensureFileModal and openFile removed.
  • srcOpen added with same logic as graph and search pages.
  • CARD_REPO / CARD_DOCS constants injected.
  • #detail-source-btn click delegation calls srcOpen.

crates/ontoref-daemon/src/ui/handlers.rs

  • insert_brand_ctx reads card.repo and card.docs from config NCL and injects card_repo / card_docs into the Tera context for all pages.

card.ncl

  • repo = "https://repo.jesusperez.pro/jesus/ontoref" added.

reflection/migrations/0007-card-repo-field.ncl — new migration

  • Check: card.ncl absent → pass (not applicable); present + repo = found → pass; present without repo = → pending.
  • Instructions: add repo and optionally docs fields; explains how srcOpen uses both.

on+re update

Artifact Change
.ontology/core.ncl ontoref-daemon description updated — browser-style panel nav, file routing via card.repo/card.docs
.ontology/state.ncl self-description-coverage catalyst updated with session 2026-03-29

Protocol Migration System — progressive NCL checks for consumer project upgrades (ADR-010)

Replaces the template-prompt approach with an ordered, idempotent migration system. Applied state determined by check result alone — no state file. 6 migrations shipped; runtime ships migrate list/pending/show with interactive group dispatch.

reflection/migrations/ — 6 ordered migrations

  • 0001-ontology-infrastructure.ontology/manifest.ncl and connections.ncl present.
  • 0002-adr-typed-checks — no check_hint in ADR instance files (adr-[0-9][0-9][0-9]-*.ncl); check narrowed from adrs/ broad scan to exclude schema/template infrastructure files.
  • 0003-manifest-self-interrogationcapabilities[] and requirements[] non-empty in manifest.ncl.
  • 0004-just-convention — justfile validates against canonical module convention (pending in this repo — documented gap).
  • 0005-mode-step-schema — all reflection mode steps declare actor, on_error, depends_on.
  • 0006-claude-agent-entrypointAgent Entry-Point Protocol section present in .claude/CLAUDE.md.

All NuCmd checks rewritten from bash to valid Nushell: && removed, $env.VAR replacing $VAR, no bash-style redirects. Grep checks on ADR files use adr-[0-9][0-9][0-9]-*.ncl glob.

reflection/modules/migrate.nu — new module

  • migrate list [--fmt] [--actor] — all migrations with applied/pending status; JSON for agents.
  • migrate pending [--fmt] [--actor] — pending only.
  • migrate show <id> [--fmt] — runtime-interpolated instructions; accepts short ids (0020002).
  • Applied state: run-migration-check dispatches over FileExists | Grep | NuCmd.
  • No state file — idempotent by construction.

reflection/nulib/interactive.nu + help.numigrate group wired

  • group-command-infomigrate case added (list, pending, show).
  • run-group-commandmigrate dispatch added.
  • help-groupmigrate help section added; fallback "Available groups" updated.

reflection/bin/ontoref.nu — shims + aliases

  • main migrate, main migrate list/pending/show added.
  • Short aliases: mg, mg l, mg p.

reflection/schemas/justfile-convention.ncl — export fix

  • Removed Module and ModuleSystem from the exported record (open contract fields with no default value caused nickel export to fail). Both remain as let bindings for internal NCL use.

on+re update

Artifact Change
adrs/adr-010-...ncl Created — protocol migration system, progressive NCL checks
.ontology/core.ncl protocol-migration-system node added; adopt-ontoref-tooling artifacts updated; adr-lifecycle updated with ADR-010; 4 new edges
.ontology/state.ncl protocol-maturity catalyst updated (10 consumers, all features complete); blocker narrowed to ontoref.dev not yet published

Manifest Self-Interrogation Layer — capabilities, requirements, critical deps (ADR-009)

Three new typed arrays in manifest_type answering operational self-knowledge queries distinct from ontology Practice nodes. describe requirements new subcommand; describe guides extended.

ontology/schemas/manifest.ncl — three new types

  • capability_typeid, name, summary, rationale, how, artifacts[], adrs[], nodes[]. nodes[] cross-references ontology node IDs; adrs[] cross-references ADR IDs.
  • env_target_type'Production | 'Development | 'Both classification axis for requirements.
  • requirement_kind_type'Tool | 'Service | 'EnvVar | 'Infrastructure.
  • requirement_typeid, name, env, kind, version, required, impact, provision.
  • critical_dep_typeid, name, ref, used_for, failure_impact (required), mitigation.
  • manifest_type gains description | String | default = "" (bug fix — collect-identity was reading a field that didn't exist), capabilities[], requirements[], critical_deps[] (all default = []).
  • New exports: EnvTarget, RequirementKind, Capability, Requirement, CriticalDep.

ontology/defaults/manifest.ncl — three new builders

  • make_capability, make_requirement, make_critical_dep added alongside existing builders.
  • New type re-exports: EnvTarget, RequirementKind, Capability, Requirement, CriticalDep.

reflection/modules/describe.nu — new subcommand + extended outputs

  • describe requirements — renders requirements grouped by env (Production / Development / Both) and critical deps table (name, ref, used_for, failure_impact, mitigation). --environment flag filters.
  • describe capabilities extended — loads manifest.capabilities? and renders a PROJECT CAPABILITIES (manifest) section with name, summary, artifacts per entry.
  • describe guides output gains capabilities, requirements, critical_deps keys — agents on cold start via ontoref_guides MCP tool receive full self-interrogation context without extra tool calls.
  • Bug fix: collect-identity was reading manifest.kind? (field absent from schema, always returned "") — changed to manifest.repo_kind?. Same fix for manifest.description? (now exists).

.ontology/manifest.ncl — ontoref self-described

  • description field populated.
  • 3 capabilities: protocol-spec, daemon-api, reflection-modes — each with rationale, how, artifacts, adrs, nodes cross-references.
  • 5 requirements: nushell (both), nickel (both), rust-nightly (dev), surrealdb (prod optional), stratumiops (dev optional) — each with impact and provision.
  • 3 critical deps: nickel-lang, inventory, axum — each with failure_impact and mitigation.

on+re update

Artifact Change
adrs/adr-009-...ncl Created — manifest self-interrogation layer, three semantic axes
.ontology/core.ncl manifest-self-description node added (29 nodes, 59 edges); adr-lifecycle updated with ADR-009
.ontology/state.ncl protocol-maturity blocker + self-description-coverage catalyst updated

Config Surface — typed config, NCL contracts, override-layer mutation

Per-project config introspection, coherence verification, and audited mutation. NCL contracts are the single validation gate; config mutation never modifies source NCL files.

crates/ontoref-daemon/src/config.rs — typed DaemonNclConfig (parse-at-boundary)

  • DaemonNclConfig — top-level deserialize target for nickel export .ontoref/config.ncl | daemon --config-stdin; fields: nickel_import_paths, ui: UiConfig, log: LogConfig, mode_run: ModeRunConfig, nats_events: NatsEventsConfig, actor_init: Vec<ActorInit>, quick_actions: Vec<QuickAction>, daemon: DaemonRuntimeConfig. #[cfg(feature = "db")] db: DbConfig. All #[serde(default)].
  • Each section struct derives #[derive(Deserialize, ConfigFields)] + #[config_section(id, ncl_file)] — emits inventory::submit!(ConfigFieldsEntry{...}) at link time.
  • DaemonRuntimeConfig — optional port, timeouts, sweep intervals, notification_ack_required: Vec<String>.

crates/ontoref-daemon/src/main.rs — 3-tuple bootstrap block

  • Bootstrap block changed to (nickel_import_path, loaded_ncl_config, stdin_raw)loaded_ncl_config: Option<DaemonNclConfig> replaces raw Option<serde_json::Value>. stdin_raw: Option<serde_json::Value> retained only for service-mode projects extraction.
  • apply_stdin_config now deserializes JSON to DaemonNclConfig before applying CLI overrides; apply_ui_config signature changed from &serde_json::Value to &UiConfig.
  • load_config_overrides returns (Option<String>, Option<DaemonNclConfig>) — all .get("daemon").and_then(...) chains replaced with typed field access (ncl.daemon.port, etc.).
  • NATS call site updated to loaded_ncl_config.as_ref().map(|c| &c.nats_events).
  • resolve_asset_dir gated with #[cfg(feature = "ui")]; #[allow(unused_variables)] on bootstrap tuple for --no-default-features.

crates/ontoref-derive/src/lib.rs#[derive(ConfigFields)] macro

  • New proc_macro_derive ConfigFields with helper attribute config_section(id, ncl_file). Extracts serde-renamed field names; emits inventory::submit!(ConfigFieldsEntry{section_id, ncl_file, struct_name, fields}).
  • Extracted serde_rename_of(field) helper to fix clippy::excessive_nesting (depth was 6). Field names collected via .iter().map(|f| serde_rename_of(f).unwrap_or_else(|| f.ident...)).filter(|s| !s.is_empty()).

crates/ontoref-daemon/src/config_coherence.rs — clippy fixes

  • and_then(|_| full_export.as_ref()).and(full_export.as_ref()) (unnecessary lazy evaluation).
  • Extracted merge_meta_into_section helper to reduce nesting depth for _meta_* record merging.

crates/ontoref-daemon/src/api.rsindex_section_fields helper

  • Extracted index_section_fields to fix clippy::excessive_nesting at the cross-project field indexing loop. Skips _meta_* and _overrides_meta keys; indexes (section_id, field) → Vec<(slug, value)>.

.ontoref/contracts.ncl — new file

NCL contracts for ontoref's own config sections using std.contract.from_validator (not the deprecated fun label value => pattern):

  • LogLevel — enum validator: error | warn | info | debug | trace
  • LogRotation — enum validator: daily | hourly | never
  • PositiveIntvalue > 0 && is_number
  • Portvalue >= 1 && value <= 65535
  • LogConfig — applies per-field contracts + defaults (level = "info", rotation = "daily", max_files = 7)
  • DaemonConfig — all fields optional (override-only); port, timeouts, intervals, notification_ack_required

.ontoref/config.ncl — contracts applied

  • let C = import "contracts.ncl" added at top.
  • log | C.LogConfig = { ... } — contract enforced before JSON reaches Rust.

.ontology/manifest.ncl — config surface enriched

  • contracts_path = ".ontoref" added to config_surface.
  • log section: contract = "contracts.ncl → LogConfig" added.
  • New daemon section: contract = "contracts.ncl → DaemonConfig", consumer daemon-config pointing to crates/ontoref-daemon/src/config.rs → DaemonRuntimeConfig with 7 declared fields.

Protocol

  • ADR-007 extended: #[derive(ConfigFields)] is a second application of the inventory::submit! / inventory::collect! linker registration pattern first established by #[onto_api]. Both are now referenced from the config-surface node.
  • ADR-008 accepted: NCL-first config validation and override-layer mutation. NCL contracts are the single validation gate; Rust structs are contract-trusted with #[serde(default)]. Config mutation writes {section}.overrides.ncl with _overrides_meta audit record; original NCL source files are never modified. nickel export validates the merged result before commit; contract violations revert the override file. (adr-008)

Self-Description — on+re Update

.ontology/core.ncl — new Practice node, updated nodes, 6 new edges:

Change Detail
New node config-surface Yang — typed DaemonNclConfig, ConfigFields inventory registry, override-layer mutation API, NCL contracts, multi-consumer manifest schema; adrs = ["adr-007", "adr-008"]
Updated adr-lifecycle ADR-007 + ADR-008 added to artifact_paths and adrs list (now 8 ADRs)

New edges: config-surface → ontoref-daemon (ManifestsIn/High), config-surface → ontoref-ontology-crate (DependsOn/High — ConfigFieldsEntry lives in zero-dep crate), config-surface → api-catalog-surface (Complements/High — shared inventory pattern), config-surface → dag-formalized (ManifestsIn/High), config-surface → self-describing (Complements/High — ontoref validates its own config with its own contracts), config-surface → adopt-ontoref-tooling (Complements/Medium).

.ontology/state.nclprotocol-maturity blocker updated to record config surface completion. self-description-coverage catalyst updated with session 2026-03-26 additions.

Previous: 4 axioms, 2 tensions, 27 practices. Current: 4 axioms, 2 tensions, 28 practices.


API Catalog Surface — #[onto_api] proc-macro

Annotated HTTP surface discoverable at compile time via inventory.

  • crates/ontoref-derive/src/lib.rs#[proc_macro_attribute] onto_api(method, path, description, auth, actors, params, tags) emits inventory::submit!(ApiRouteEntry{...}) for each handler; auth validated at compile time (none | viewer | admin); param entries parsed as name:type:constraint:description semicolon-delimited
  • crates/ontoref-daemon/src/api_catalog.rsApiRouteEntry + ApiParam structs (&'static str fields for process lifetime); inventory::collect!(ApiRouteEntry); catalog() returns sorted Vec<&'static ApiRouteEntry>
  • GET /api/catalog — annotated with #[onto_api]; returns all registered routes as JSON sorted by path+method; no auth required
  • GET /projects/{slug}/ontology/versions — per-file reload counters as BTreeMap<filename, u64>; counter bumped on every watcher-triggered NCL cache invalidation
  • describe api [--actor] [--tag] [--auth] [--fmt json|text] — queries /api/catalog, groups by first tag, renders auth badges, param detail per route; available as onref da alias
  • describe diff [--file <ncl>] [--fmt json|text] — semantic diff of .ontology/ files vs HEAD via git show HEAD:<rel> | mktemp | nickel export; diffs nodes by id, edges by from→to[kind] key; available as onref df alias
  • ontoref_api_catalog MCP tool — calls api_catalog::catalog() directly; filters by actor/tag/auth; returns { routes, total }
  • ontoref_file_versions MCP tool — reads ProjectContext.file_versions DashMap; returns per-filename counters
  • Web UI: /{slug}/api page — table with client-side filtering (path, auth, method) + expandable detail panel; linked from nav and dashboard
  • Dashboard: "Ontology File Versions" section showing per-file counters; "API Catalog" card
  • insert_mcp_ctx in handlers.rs updated: 15 → 28 tools (previously stale for qa, bookmark, action, ontology extensions, validate, impact, guides)
  • HelpTool JSON updated: 8 entries added (validate_adrs, validate, impact, guides, bookmark_list, bookmark_add, api_catalog, file_versions)
  • MCP ServerHandler::get_info() instructions updated to mention ontoref_guides, ontoref_api_catalog, ontoref_file_versions, ontoref_validate

Protocol Update Mode

  • reflection/modes/update_ontoref.ncl — new mode bringing existing ontoref-adopted projects to protocol v2; 9-step DAG: 5 parallel detect steps (manifest, connections, ADR check_hint scan, ADRs missing check, daemon /api/catalog probe), 2 parallel update steps (add-manifest, add-connections — both idempotent via test -f || sed), 2 validate steps (nickel export with explicit import paths), 1 aggregate report step
  • templates/ontology/manifest.ncl — consumer-project stub; imports ontology/defaults/manifest.ncl via import-path-relative resolution
  • templates/ontology/connections.ncl — consumer-project stub; imports connections schema; empty upstream/downstream/peers with format docs
  • reflection/modes/adopt_ontoref.ncl — updated: adds copy_ontology_manifest and copy_ontology_connections steps (parallel, 'Continue, idempotent); validate_ontology depends on both with 'Always
  • reflection/templates/update-ontology-prompt.md — 8-phase reusable prompt for full ontology enrichment: infrastructure update, audit, core.ncl nodes/edges, state.ncl dimensions, manifest.ncl assets, connections.ncl cross-project, ADR migration, final validation

CLI — describe group extensions and aliases

  • main describe diff and main describe api wrappers in reflection/bin/ontoref.nu
  • main d diff, main d api — short aliases within d group
  • main df, main da — toplevel aliases (consistent with d, ad, bkl pattern)
  • QUICK REFERENCE: describe diff, describe api, run update_ontoref entries added
  • help describe description updated to include diff, api surface

Self-Description — on+re Update

.ontology/core.ncl — 1 new Practice node, 3 updated nodes, 3 new edges:

Change Detail
New node api-catalog-surface Yang — #[onto_api] proc-macro + inventory catalog; GET /api/catalog; describe api; ApiCatalogTool; /ui/{slug}/api page
Updated describe-query-layer Description extended: describe diff (semantic vs HEAD) and describe api (annotated surface)
Updated adopt-ontoref-tooling Description extended: update_ontoref mode, manifest/connections templates, enrichment prompt; artifact_paths updated
Updated ontoref-daemon 11 pages, 29 MCP tools, per-file versioning, API catalog endpoint; artifact_paths: api_catalog.rs, api_catalog.html, crates/ontoref-derive/
New edge api-catalog-surface → ontoref-daemon ManifestsIn/High
New edge api-catalog-surface → describe-query-layer Complements/High
New edge api-catalog-surface → protocol-not-runtime Complements/Medium — catalog is link-time, no runtime

.ontology/state.nclself-description-coverage catalyst updated (session 2026-03-23). protocol-maturity blocker updated to reflect protocol v2 completeness.

Previous: 4 axioms, 2 tensions, 20 practices. Current: 4 axioms, 2 tensions, 21 practices.


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.nclBookmarkEntry (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.rsadd_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)

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.nclself-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.


ADRNode 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<String> and adrs: Vec<String>, 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=<slug> endpoint — reads adrs/<stem>.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 ◆ <adr-id> 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")].

  • KeyEntry gains label: String (#[serde(default)]) — audit trail for key-based sessions. NCL schema install/resources/schemas/ontoref-project.ncl updated accordingly.
  • verify_keys_list returns Option<KeyMatch { role, label }> instead of Option<Role>.
  • SessionEntry gains id: String — stable public identifier distinct from the bearer token, safe to expose in list responses. Prevents session enumeration by admins.
  • SessionStore gains secondary id_index: DashMap<id, token> for O(1) revoke_by_id.
  • New SessionStore methods: list_for_slug, list_all, revoke_all_for_slug, revoke_by_id(id, acting_slug, acting_role) -> RevokeResult.
  • POST /sessions — key → UUID v4 token exchange. Accepts project keys or daemon admin password (project: "_daemon"). Rate-limited. No authentication required (it is the credential exchange endpoint).
  • GET /sessions?project=slug — list active sessions for a project (viewer+). Without ?project= param requires daemon admin and returns all sessions.
  • DELETE /sessions/{id} — revoke by public id. Project admin: own project only. Daemon admin: any.
  • require_session() helper: validates UUID v4 Bearer → SessionEntry, error boxed (Box<Response>) to satisfy clippy::result_large_err.
  • check_primary_auth fast-path: UUID v4 bearer → session lookup (O(1)) before argon2 fallback (~100ms).
  • project_update_keys (PUT /projects/{slug}/keys) now calls sessions.revoke_all_for_slug in addition to actor deregistration. All in-flight UI sessions for the rotated project are immediately invalidated.
  • Daemon admin: ONTOREF_ADMIN_TOKEN_FILE (preferred — hash not visible in ps aux) or ONTOREF_ADMIN_TOKEN. Sessions use virtual slug "_daemon".
  • manage_login_page / manage_login_submit / manage_logout handlers for /ui/manage/login and /ui/manage/logout.
  • AdminGuard redirects to /ui/manage/login when daemon_admin_hash is set.

CLI Bearer Token

  • bearer-args exported from reflection/modules/store.nu: returns ["-H" "Authorization: Bearer $token"] when ONTOREF_TOKEN is set, [] otherwise.
  • http-get, http-post-json, http-delete (new) in store.nu use ...$auth — Bearer injected transparently, no behavior change when ONTOREF_TOKEN is unset.
  • notify-daemon-project-add and notify-daemon-project-remove in reflection/bin/ontoref.nu use bearer-args.

Project Setup & Onboarding

  • ontoref setup is now the primary onboarding command (replaces manual cp templates/ pattern).
  • --kind <K> flag: Service (default) | Library | DevWorkspace | PublishedCrate | AgentResource | Mixed.
  • --parent <path> flag: generates manifest with implementation layer + <slug>-framework layer and <slug>-browse op mode for implementation children.
  • Logo auto-detection: setup scans assets/ for <slug>-logo.svg, <slug>.svg, logo.svg (and .png variants); inserts ui.logo into generated config.ncl when found.
  • --gen-keys ["admin:label" "viewer:label"] flag: idempotent bootstrap — skips if role = already present in project.ncl. Hashes via ontoref-daemon.bin --hash-password; prints passwords once to stdout.
  • All mkdir calls in setup guarded by if not (path | path exists).

Self-Description — on+re Update

.ontology/core.ncl — 3 new Practice nodes, updated ontoref-daemon description and artifact_paths:

Node Pole Description
unified-auth-model Yang Key→session token exchange; session.id ≠ bearer; revoke on key rotation
project-onboarding Yang ontoref setup — idempotent scaffold, --kind, --parent, --gen-keys

ontoref-daemon node updated: auth/session management added to description and artifact_paths (session.rs, auth.rs, login.rs).

New edges: unified-auth-model → ontoref-daemon, unified-auth-model → no-enforcement (Contradicts/Low — auth is opt-in), ontoref-daemon → unified-auth-model (Contains), project-onboarding → unified-auth-model (DependsOn), project-onboarding → adopt-ontoref-tooling (Complements), project-onboarding → daemon-config-management (DependsOn).

.ontology/state.nclself-description-coverage transitions to current_state = "fully-self-described". Blocker resolved: reflection/backlog.ncl created, ADR-005 recorded.

reflection/backlog.ncl — created with 6 items: bl-001 (ontoref.dev), bl-002 (first external project), bl-003 (ontoref keys CLI), bl-004 (session UI views), bl-005 (Syntaxis migration), bl-006 (ADR-001 acceptance).

Previous state: 4 axioms, 2 tensions, 13 practices. Current: 4 axioms, 2 tensions, 15 practices.

Protocol

  • ADR-004 accepted: NCL pipe bootstrap pattern — nickel export config.ncl | ontoref-daemon.bin --config-stdin. Stages: Nickel evaluation → optional SOPS/Vault merge → binary via stdin. (adr-004)
  • ADR-005 accepted: unified key-to-session auth model across CLI, UI, and MCP. Opaque UUID v4 tokens, session.id ≠ bearer, revocation on key rotation, daemon admin via _daemon slug. (adr-005)

Install Infrastructure

  • install/ directory reorganized: binaries, bootstrapper, global CLI, resources, and validation scripts co-located.
  • Binary installed as ontoref-daemon.bin; public entrypoint bootstrapper installed as ontoref-daemon. Users never call .bin directly.
  • install/ontoref-daemon-boot (renamed from ontoref-daemon-start) — NCL pipe bootstrapper implementing ADR-004. Stages: nickel export config.ncl → optional SOPS/Vault secret merge → ontoref-daemon.bin --config-stdin. Supports --dry-run, --sops, --vault.
  • install/ontoref-daemon-boot sets NICKEL_IMPORT_PATH (config dir + platform data dir schemas) and NATS_STREAMS_CONFIG (default ~/.config/ontoref/streams.json) before launching the binary.
  • install/install.nu — installs binary, bootstrapper, global ontoref CLI (ONTOREF_ROOT baked in at install time), UI assets, config skeleton, and global NATS topology. Hash-checked — unchanged files are not overwritten.
  • install/config-setup.nu — standalone validation script: nickel typecheck + nickel export, path existence checks, DB and NATS liveness probes (nc -z -w2).
  • install/check-config-sync.nu — CI guard asserting that every nickel_path-bearing field in reflection/forms/config.ncl has a matching {{ name }} reference in reflection/forms/config.ncl.j2, and vice versa. Wired into just ci-lint and just ci-full.

Config Management

  • install/resources/config.ncl — default global config skeleton with full Nickel contracts (Port, LogLevel, Rotation, Actor, Severity). Covers: daemon, db, nats_events, log, cache, ui, mode_run, actor_init, quick_actions, nickel_import_paths.
  • install/resources/streams.json — global default NATS JetStream topology: ECOSYSTEM stream (ecosystem.>, 30-day retention), no project-specific consumers. Installed to ~/.config/ontoref/streams.json.
  • nats/streams.json — ontoref project-local topology with daemon-ontoref and cli-notifications consumers on ECOSYSTEM stream.
  • reflection/forms/config.ncl + reflection/forms/config.ncl.j2 — typedialog roundtrip for browser-based config editing (ontoref config-edit). Form populates fields from existing config via nickel_path; Tera template reconstructs full NCL with all contracts on save.
  • reflection/nulib/bootstrap.nu — Nu bootstrapper helper updated: nats-streams-config function resolves NATS_STREAMS_CONFIG default; env var passed to daemon process via with-env.
  • Daemon nats.rs: empty streams_config string → None, activating TopologyConfig::load fallback to NATS_STREAMS_CONFIG env var. Projects with a local nats/streams.json set streams_config explicitly in their config.

Daemon Fixes

  • --config-stdin now exclusively skips .ontoref/config.ncl — project config is never loaded when stdin config is active. Previously both paths could run.
  • DB connection (stratum-db) only established when db.enabled = true in config. Previously connected regardless of enabled flag.
  • NATS connection (platform-nats) only established when nats_events.enabled = true. "Connecting to NATS..." log moved after the enabled check.
  • NatsPublisher::connect signature changed from config_path: &PathBuf (re-read file) to config: Option<&serde_json::Value> (already-loaded JSON). Eliminates double file read and ensures NATS uses the same config source as the rest of the daemon.
  • load_config_overrides returns (Option<String>, Option<serde_json::Value>) — nickel import path and parsed config JSON returned together. apply_stdin_config returns serde_json::Value directly.

Self-Description — on+re Update

.ontology/core.ncl — 1 new Practice node, updated ontoref-daemon description and artifact_paths:

Node Pole Description
daemon-config-management Yang Install + config form/template roundtrip, CI guard, global NATS topology, config-setup validation

New edges: daemon-config-management → ontoref-daemon (DependsOn), daemon-config-management → adopt-ontoref-tooling (Complements).

.ontology/state.ncloperational-mode dimension description updated to reference ADR-004 bootstrap and NATS_STREAMS_CONFIG mechanism. protocol-maturity blocker updated to reflect install pipeline completion.

.ontology/manifest.ncltooling layer paths updated to include install/ and nats/.

Previous state: 4 axioms, 2 tensions, 12 practices. Current: 4 axioms, 2 tensions, 13 practices.

Protocol

  • ADR-001 accepted: ontoref extracted as a standalone protocol project, independent of stratumiops versioning and release cycle. Consumer projects adopt via scripts/ontoref wrapper + .ontoref/config.ncl. (adr-001)
  • ADR-002 accepted: ontoref-daemon introduced as optional persistent daemon for NCL export caching (keyed by path+mtime), actor registry (developer/agent/CI), and notification barrier (pre-commit hook, fail-open). Supersedes stratumiops ADR-007. (adr-002)
  • ADR-003 accepted: Q&A and accumulated operational knowledge persist to reflection/qa.ncl — typed NCL, git-versioned, accessible via MCP tools and HTTP endpoints. localStorage eliminated. Q&A entries survive session boundaries and are queryable by any actor. (adr-003)

Crates

  • ontoref-ontology: Rust crate for loading .ontology/*.ncl as typed structs (Core, Gate, State). Zero stratumiops dependencies.
  • ontoref-reflection: Rust crate for loading, validating, and executing Reflection modes as NCL DAG contracts. Optional nats feature (path dep: platform-nats).
  • ontoref-daemon: Rust crate providing HTTP API (axum), DashMap-backed NCL export cache, notify-based file watcher, and actor registry. Optional db feature (path dep: stratum-db) and nats feature (path dep: platform-nats).

Daemon — Q&A NCL Persistence (crates/ontoref-daemon/src/ui/qa_ncl.rs)

Line-level NCL surgery for reflection/qa.ncl — same pattern as backlog_ncl.rs. No AST parsing, no nickel-lang-core dependency.

  • add_entry — appends a typed QaEntry block before ], array close; generates sequential qa-NNN ids
  • update_entry — in-place field mutation via bidirectional scan (question + answer fields)
  • remove_entry — removes the full block by id using backward scan for { and forward scan for },

HTTP endpoints (all under #[cfg(feature = "ui")] except read-only GET):

  • GET /qa-json — export all Q&A entries as JSON (read-only, always enabled)
  • POST /qa/add — append new entry; returns generated id
  • POST /qa/delete — remove entry by id; invalidates NCL cache
  • POST /qa/update — mutate question + answer fields by id; invalidates NCL cache
  • GET /actions/run / POST /actions/run — execute a quick action by id; spawns ./ontoref <mode>

Server-side hydration: qa.html receives entries as Tera context variable, embeds SERVER_ENTRIES JSON literal in the page <script> — no fetch round-trip on load.

Daemon — MCP Tools (crates/ontoref-daemon/src/mcp/mod.rs)

Four new MCP tools exposed to AI agents:

Tool Description
ontoref_qa_list List Q&A entries with optional filter substring match. Never triggers ontology sync.
ontoref_qa_add Append a new Q&A entry to reflection/qa.ncl; invalidates NCL cache.
ontoref_action_list List all quick actions from .ontoref/config.ncl export.
ontoref_action_add Create a new reflection mode at reflection/modes/<id>.ncl and register it as a quick action.

Constraint: ontoref_qa_list and ontoref_qa_add never trigger apply steps or modify .ontology/ files (enforced by ADR-003).

Daemon — Passive Drift Observation (crates/ontoref-daemon/src/ui/drift_watcher.rs)

Background observer bridging Yang code artifacts with Yin ontology declarations:

  • Watches crates/, .ontology/, adrs/, reflection/modes/ via notify file watcher
  • 15-second debounce window before triggering scan
  • Spawns ./ontoref sync scan && ./ontoref sync diff as read-only subprocesses
  • Parses stdout for MISSING / STALE / DRIFT / BROKEN markers
  • Emits ontology_drift notification via push_custom when any drift is found
  • Never applies changes automatically — apply remains a deliberate human or agent act

Started from main.rs under #[cfg(feature = "ui")]; failure to start is non-fatal (logged as warning).

Tooling

  • reflection/modules/: 16 Nushell operational modules (adr.nu, backlog.nu, coder.nu, describe.nu, sync.nu, etc.)
  • reflection/modes/: 10 NCL DAG operational modes including adopt_ontoref, sync-ontology, coder-workflow, create-pr
  • reflection/forms/: 7 interactive NCL forms for ADR lifecycle, backlog, and adoption
  • templates/: Consumer-facing adoption templates (ontoref-config.ncl, ontology/, scripts-ontoref)
  • ./ontoref: Bash entry point with actor auto-detection, advisory file locking, and Nushell version guard (>= 0.110.0)

Self-Description — on+re Update

.ontology/core.ncl updated with 3 new Practice nodes and 9 new edges:

Node Pole Description
qa-knowledge-store Yin Q&A entries as typed NCL — accumulated knowledge queryable by any actor
quick-actions Yang Runnable shortcuts over reflection modes; configured in .ontoref/config.ncl
drift-observation Spiral Passive bridge between Yang code artifacts and Yin ontology declarations

New edges: qa-knowledge-store → dag-formalized, qa-knowledge-store → coder-process-memory, ontoref-daemon → qa-knowledge-store, quick-actions → reflection-modes, quick-actions → ontoref-daemon, describe-query-layer → quick-actions, drift-observation → ontoref-daemon, drift-observation → ontology-vs-reflection, drift-observation → reflection-modes.

Previous state: 4 axioms, 2 tensions, 9 practices. Current: 4 axioms, 2 tensions, 12 practices.

reflection/schemas/qa.nclQaStore and QaEntry types (id, question, answer, actor, created_at, tags, related, verified). reflection/qa.ncl — typed store file, conforms to QaStore contract, Nickel typecheck must pass.


ontoref uses its own ADR system to track decisions. Architectural rationale lives in adrs/, not in this file.