ontoref-code/CHANGELOG.md
2026-07-10 01:44:59 +01:00

106 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]

Governed delivery — the Work-Order unit promoted to an enforcing executor (migration 0041, ADR-066)

ADR-063's gated pattern (SOW + witness + signature) is now a built, enforcing substrate, promoted by an eight-path falsación run (.coder/2026-07-04-governed-delivery-falsacion.done.md): the run completed only after two real out-of-band human signatures, and every refutation attempt (missing/unsigned/tampered SOW, out-of-order step, status contradicting a passing check, unsigned/tampered receipt) was refused. The rule above all: where a machine check exists, the check decides — never the reporter.

Executor (reflection/modules/run.nu):

  • Run vars: modes declare vars_required; run start <mode> KEY=VALUE… refuses when one is missing, persists them in run.json, substitutes declared ${KEY} in guard/verify/postcheck cmds (undeclared ${…} passes through to the shell).
  • 'Block guards are evaluated once at run start, fail-closed — the schema's "'Block aborts execution" (ADR-011) is finally true on this path.
  • Steps declaring verify have their status derived from the check's exit code; a contradicting --status is refused; steps.jsonl records status_source and a capped output detail. Form-parameterized verifies ({word}) require an explicit --status.
  • Typed postchecks | Array { desc, cmd } run fail-closed at mode complete, which now exits 1 on any incomplete run (CI-gateable). postconditions stays prose. Latest step report supersedes earlier ones (re-run to unblock).

Witness (scripts/witness.nu): contract checks run with cwd pinned to the governed repo root (no vacuous passes from a wrong cwd); exempt-bearing contracts emit one violating path per line and exemption subtracts exact paths (exempt only when every violation is exempt); the witness never signs its own output.

Distribution (adoption surface): the mode ships in the installed reflection tree; the witness is projected by install.nu §3b-bis into reflection/bin/witness.nu (single source, never vendored by copy); opt-in SOW validation contract at ontology/schemas/sow.ncl; agent front-end skill .claude/skills/work-order/; instance data lives in the governed repo's .governance/ (SOW + witness.pub + receipts with a tracked/untracked allowlist).

  • Migration 0041-governed-delivery (protocol 0.1.17 → 0.1.18), opt-in; check passes for non-adopters.
  • ADR-066 (root spine .ontoref/adrs/) records the semantics and their falsación; discharges ADR-063's promotion-gated-on-second-instance.
  • Tests: reflection/tests/test_run_{vars,guards,verify}.nu, test_mode_postchecks.nu, test_witness_exempt.nu — 58 checks.
  • Fix (peer drift, unrelated): auth::Role::Editor added in stratumiops broke the daemon's role bridge — mapped Editor → Viewer (least privilege; registry.rs).

repo_kind enum — register the domain kinds (migration 0040)

ontology/schemas/manifest.ncl's repo_kind_type enum gained 'Tool, 'KnowledgeBase and 'ContentProject — values the domain extensions' repo_kinds.txt already used (framework: Tool; librosys / knowledge-works: KnowledgeBase + ContentProject) but the enum had never declared. Additive — existing manifests validate unchanged.

  • Migration 0040-repo-kind-domain-kinds (protocol 0.1.16 → 0.1.17), additive enum.
  • Relates to ADR-064 (root spine .ontoref/adrs/) — the authoring/knowledge door + the content-vehicle-convergence gate membrane (positioning + ontology; no shipped-surface change).

Docsite projection — mdBook from the ontology (spine-local)

The project projects itself as a navigable mdBook, modeled on the cdci-dao theme (ds-theme chrome + tera/admonish/toc/codeblocks preprocessors) and servable as static HTML by docserver under a serv_paths url_path. The chrome is fixed; the content is regenerated on every build from .ontoref/ so the docs cannot drift from the protocol state they describe — hybrid static Tera chrome plus pre-rendered per-ADR / per-mode pages, identity read from card.ncl.

  • New module reflection/modules/docsite.nudocsite generate [--serve-path] [--restricted]: Tera context + dynamic pages + SUMMARY; dev build (relative links) and dist build (site-url baked to the docserver mount via a surgical one-line swap); fence-aware angle-bracket escaping so <token> notation in ADR prose is not swallowed.
  • New mode reflection/modes/generate-docsite.ncl (project-and-build → dist-and-register).
  • generator.nu gains one export docs data (the composed record, reused — no re-extraction).
  • just docsite [serve-path] recipe in code/justfiles/dev.just.
  • Promoted to the protocol surface: the chrome now ships under reflection/templates/mdbook/ (with the reflection tree — no install.nu change); docsite init materialises it into a consumer's .ontoref/docsite/ (idempotent), and generate-docsite gained a materialize-template step.
  • Ontology: Practice node docsite-projection ('Spiral / 'Act, adrs=['adr-060'])
    • 5 edges; recorded on the self-description-coverage dimension.
  • ADR-060 — mdBook Docsite as the standard projected documentation surface (4 constraints, 3 anti-patterns; formalization-vs-adoption kept Soft per ondaod).
  • Migration 0039 mdbook-docsite — opt-in adoption; protocol-version 0.1.15 → 0.1.16.
  • Brand-neutral chrome: docsite generate injects identity from card.ncl and an optional project-local .ontoref/docsite-brand.ncl (palette → generated brand.css, author, logo override); absent → neutral defaults. No project carries another's brand.
  • generate-mdbook kept as an alias delegating to docsite generate (not retired); generate-docsite is canonical. The bare docs generate --fmt mdbook renderer is unchanged.

[0.1.7] — current release

The constellation-memory, viability, and honest-limits arc

Sessions 2026-06-08 → 06-10

Nine ADRs (049057) and five migrations (00340038), built on the substrate-view engine (ADR-046) and scheme-tagged witnesses (ADR-047). One unifying discipline: every mechanism here notices, proposes, or verifies — none applies, asserts, or rules on truth. Authoritative state changes only through the witnessed approve path (ADR-024). Version bump 0.1.6 → 0.1.7.

ADR-049 — Criteria as a substrate-view describe level (Accepted) + migration 0035

Criteria — the conditions a project holds itself to (release gates, quality bars, coherence rules) — become a first-class describe level mounted through the substrate-view engine (ADR-046), distinguished by typed provenance. Every criterion carries kind: 'Normative (declared up front, ontology axis) or 'Discovered (harvested from insights + the interaction trace, reflection axis); a discovered criterion MUST record the provenance it was graduated from. Promotion to normative is GATED behind a novelty-check plus human approval — recurrence alone never promotes; demotion is likewise a proposal, never silent. Registered in levels.ncl with kind = 'Describe, eligibility = 'Learned, so a project declaring no criteria mounts nothing and pays zero (ADR-029). Migration 0035 ships the criteria level. Engages ontology-vs-reflection (the typed tag is the legibility seam between asserted and observed) and formalization-vs-adoption (opt-in absence).

ADR-050 — Witnessed validators: structural decidability, never truthfulness (Accepted)

A criterion is eligible to become an executable validator ONLY if it reduces to a bounded, structurally-decidable slice query plus the state_root commitment. Truthfulness criteria ("the positioning is honest", "the architecture is sound") are rejected at the eligibility gate and remain QA entries (ADR-049), never validators — a pass/fail verdict on such a claim would be the engine deciding truth. Every ValidatorDecl declares a slice_query naming exactly the nodes/edges/fields it reads; the #[onto_validator] predicate may read ONLY that slice + state_root. A validator over a 'Spiral-poled tension MUST be 'Soft and report direction of motion, never a Hard biconditional (the ondaod prohibition, applied to validators). Each run emits a witness binding the verdict to the state_root (ADR-024). 4 anti-patterns; no migration (internal validator architecture).

ADR-051 — Chronicle-to-proof-candidate seam (Accepted)

A one-directional, propose-only seam from the chronicle (companion-NCL milestones, harvested insights, the interaction trace ADR-037, ADRs-by-date) to the positioning Proof layer (ADR-043). coder chronicle --as-proof-candidates emits accepted ADRs and completed milestones as CANDIDATE proofs wired to the four-element framework — a candidate is a proposal, never an accepted Proof, materialized only through positioning's own acceptance path. The positioning audit's five rules verify candidates (one creating a DanglingRef / UnprovenValidatedAudience / AnchorDrift is surfaced, not accepted): the chronicle proposes, the audit verifies, a human accepts. Orphan milestones (shipped work with no positioning home) WARN, never erase — internal work the positioning layer never intended to claim is a legitimate half-state. The seam is outreach-read-only. Engages ontology-vs-reflection (history is reflection; a Proof is an ontology-side claim — auto-asserting would collapse the duality).

ADR-052 — Memory feedback loop: propose, never apply (Accepted)

At mode complete the memory feedback loop emits PROPOSED deltas and never applies them. A proposal hook in run.nu surfaces three kinds — FSM-transition proposals against state.ncl, backlog-close proposals, and proof-citation proposals (ADR-051) — each via backlog propose-status, never a direct mutation. The ONLY path to authoritative state is the witnessed approve operation (ADR-024); the loop has no write path that bypasses it. Intent-vs-reality divergence (a dimension's blocker gone but catalyst unmet; a milestone shipped that no proof claims) is DESCRIBED as a half-state and proposed, never collapsed or fabricated. The hook always RUNS and SURFACES even when nothing is accepted, so the opposite collapse — decide-and-commit blind to drift — is structurally prevented. Engages ontology-vs-reflection (memory is reflection; state/backlog/proofs are ontology).

ADR-053 — Presentation-spec: config-driven panels (Accepted) + migration 0036

A presentation-spec (reflection/schemas/presentation.ncl) becomes the single declarative panel model the engine reads generically, so adding a panel is dropping an NCL file, never editing Rust. A Panel declares { id, title, kind ('Timeline | 'Gantt | 'Graph | 'Table | 'Board), data_source (op + params naming a catalog operation), surfaces, reference_links, filters, actors }; the render path branches on kind, not panel identity, through the existing NclCache → JSON pipeline (the graph.html precedent). Panels declared as presentation/panel-*.ncl, referenced from config.ncl quick_actions, or surfaced from a substrate-view all normalize to one panel list. A data_source MUST name a declared catalog operation — a panel is a projection of declared knowledge, never an independent Rust query. Domain projects extend by shipping their own panel NCL with no engine fork. Migration 0036 ships the presentation-spec schema.

ADR-054 — Desktop/mobile native shell as a consumer surface (Accepted)

Session 2026-06-09

Permits a Tauri native shell (ontoref-desktop, same lib targeting desktop and mobile) as a strictly separate consumer of the daemon — modeled on provisioning-desktop. The shell wraps the existing daemon /ui/ in a webview and adds the four browser-impossible capabilities: system tray, native OS notifications, local-daemon supervision, and native keyring. No version bump: internal architecture decision, no migration (governs ontoref's own development, not the consumer-visible protocol surface).

  • Dependency direction (Hard): the arrow is shell → daemon only. ontoref-ontology, ontoref-reflection, and ontoref-daemon must never depend on the desktop crate (C1C3, typed Cargo checks) — preserves Protocol-Not-Runtime (ADR-001)
  • Placement (Hard): the shell lives as its own constellation sub-repo (ADR-048) or a workspace crate excluded from the installed/adopted footprint; consumes the daemon over HTTP/NATS only, may depend on ontoref-ui for presentation (C4)
  • Capture seam (Soft, directional): when the native surface occupies the openness-vs-sustainability seam it does so as a declared positioning consumer audience; tier-0 protocol adoption (ADR-029) stays free and unmetered (C5) — ondaod: Spiral tension gets a direction-reporting Soft constraint, never a Hard biconditional
  • Differentiator: the drift-watcher (Passive Drift Observation) + notification barrier (ADR-002) give native notifications a first-class event source — the reason the host is more than a reskinned browser
  • 3 anti-patterns: host-inside-adoption-surface, native-view-surface-fork, metered-protocol-capture
  • ondaod: engages openness-vs-sustainability (claim-only → populating: first declared occupant of the capture seam), ontology-vs-reflection (pure reflection-axis consumer), formalization-vs-adoption (optional layer, lowers daemon-run friction)
  • on+re: core.ncl tension openness-vs-sustainability updated (synthesis state + adrs=['adr-043','adr-054']); state.ncl self-description-coverage catalyst records the incorporation; no Practice node added (shell is unbuilt — avoids a placeholder node)

ADR-055 — Positioning viability seam: compensation as a second costura (Accepted)

Session 2026-06-09

Adds the ViabilityPath kind to the positioning layer — a second costura parallel to Proof, not a fourth orthogonal axis. Where a Proof answers "is the claim real?", a ViabilityPath answers "does the claim sustain its maker?". It converges PARA QUIÉN × CÓMO × (QUÉ×QUIÉN), directness ('Direct/'Indirect) binds the two poles of openness-vs-sustainability, and a one-directional realized ⇒ realized_outcome gate keeps compensation honest. Purely additive, opt-in (ADR-029), no migration (same precedent as ADR-043's four-element kinds — all fields defaulted, zero adoption cost).

  • Number-collision reconciliation: authored concurrently with ADR-054 (both took 054, the repo's second double-NNN after the double adr-039). The desktop shell kept adr-054; the viability seam took adr-055; the two are cross-linked as occupant ↔ kind — ADR-054 declared the desktop/mobile surface as the first capture-seam occupant but had no element to model it with, ADR-055 supplies that element
  • Schema/defaults (ontology/{schemas,defaults}/positioning.ncl): ViabilityPath + Directness/FlowKind enums; make_viability_path with 4 cross-field invariants — converge-three-axes, anchor-to-graph, one-directional realized⇒outcome (Soft, never a Hard biconditional — ondaod), Live⇒evidence_adr
  • 3 dogfood paths (.ontoref/positioning/viability/, all 'Draft — present state is claim-only): via-001 (Direct/HostedService governance-audit tail), via-002 (Indirect/Funnel personal-open visibility), via-003 (Direct/Product native-shell occupant citing adr-054 — closes the gap ADR-054's own negative consequence named)
  • Rust walker (ontoref-ontology): ViabilityPath/Directness/FlowKind/ViabilityConverges types, PositioningConfig.viability_paths, Positioning runtime view with DanglingConverges referential-integrity checks + viability_path_by_id lookup + viability dir in the cold-load walk. Daemon GET /api/positioning surfaces the list + viability_paths/realized_viability_paths counts. 39 ontology tests pass; ontoref-ontology clippy clean
  • Coherence (positioning.nu): load-all-local loads viability/; 7th rule DanglingConverges/RealizedWithoutOutcome; positioning validate covers the viability subdir
  • constraints: 3 Hard (seam-not-axis, converges-three, anchored-to-graph) + 2 Soft on the Spiral question (realized-gate-one-directional, capture-stays-off-protocol-surface); 4 anti-patterns (viability-as-fourth-axis, realized-without-outcome, meter-the-protocol, hard-biconditional-on-viability)
  • on+re: core.ncl positioning-layer node (adrs += adr-055, viability/ dir, second-costura description) + tension node (adrs=['adr-043','adr-054','adr-055'], "no viability axis" clause corrected); state.ncl catalyst records the incorporation

ADR-056 — Sufficient verification over complete knowledge (Accepted)

Names a trust model that had been operating across the protocol without ever being stated as one: no actor — human or agent — holds the whole project, and recording everything to approach completeness overflows context and produces more confusion than clarity. A trust model resting on "know it all, keep it all current" fails in both directions. Trust instead rests on local, partial verification of sufficient knowledge — accredited, not generated: you verify the slice you need by witness, without holding the whole. It is the only model that scales to real humans and to agent context windows that cannot hold the entire project. Formalises the basis the verifiable substrate (ADR-023) and the witness seam (ADR-031) already assumed.

ADR-057 — Difusión reveal architecture (Accepted)

Makes the outreach discipline architectural: route each door to a live graph, never argue the core. Outward communication reveals itself through the same queryable substrate — the positioning graph projected via spine.ncl + a generator — rather than bespoke prose, converting per-conversation human mediation into a reproducible projection. Publishing a real personal graph as the rung-3 mediation artifact is a per-artifact privacy decision (cleared for the jpl graph 2026-06-10, never automatic for others). Anchors the outreach/site projection work.

Migrations 00340038

  • 0034 substrate-views — the substrate-view engine (ADR-046): disciplines mount scoped slices of levels.
  • 0035 criteria-level — the criteria describe level (ADR-049).
  • 0036 presentation-spec — the config-driven panel model (ADR-053).
  • 0037 memory-surface-fan-out — the memory loop's proposal surface (ADR-052).
  • 0038 coder-workflow-harvest-criteria — the coder harvest that graduates discovered criteria (ADR-049/052).

[0.1.6]

Protocol delta 0.1.5 → 0.1.6 — OCI distribution (migration 0029)

Session 2026-06-03

Migration 0029 (oci-distribution) gate closed: reflection/defaults/workflow.ncl carries ContainerRegistry in the distributions catalog. Version bump applied.

Bug fix: migrate.nu:migrations-dir used $env.ONTOREF_ROOT instead of project-root, causing onre migrate list to return [] on constellation layouts (post-ADR-048 spine at parent). Fixed to (project-root) — migrations now resolve from the spine regardless of whether the spine is inside or outside ONTOREF_ROOT.


[0.1.5]

ADR-048 — Constellation layout: spine at parent, code as sub-repo (Accepted)

Session 2026-06-02

Formalizes the decision to move .ontoref/ from inside code/ to the constellation parent directory, establishing code/ as one independent git sub-repo among several (outreach/, vault/) under a non-versioned umbrella.

  • Bash wrapper (code/ontoref): derives SPINE_DIR as SCRIPT_DIR/../.ontoref/; sets ONTOREF_PROJECT_ROOT to the parent
  • env.nu: ONTOREF_ROOT assignment guarded with is-empty — preserves the bash wrapper's value at module load time
  • config.ncl nickel_import_paths: .ontoref/ entries prefixed with ../ (relative to ONTOREF_ROOT=code/)
  • NCL imports in .ontoref/: card.ncl and ontology/{core,state,gate,manifest}.ncl use ../../code/ontology/ for the data-dir companion
  • Cargo path deps: peer projects at Development/ level now resolve via ../../../../ (four hops); stratumiops crates gain code/ segment (../../../../stratumiops/code/crates/)
  • install.nu: repo_root derived from $env.CURRENT_FILE — robust to arbitrary CWD; constellation fallback for reflection_src and bootstrap_src
  • Asset sync: just sync-assets / onre sync assets materialises assets/code/assets/; onre sync assets check as CI drift gate; ProjectCard schema gains optional synced_assets { source, digest, synced_at }
  • 4 constraints (all Hard): spine-at-parent-not-inside-code, env-nu-guards-ontoref-root, nickel-import-paths-use-parent-prefix, ncl-imports-reference-code-ontology
  • 3 anti-patterns: spine-as-satellite, unconstrained-env-nu-override, three-hop-cross-project-deps
  • ondaod verdict: 'Safe — tensions formalization-vs-adoption (toward Yang, Yin preserved) and ontology-vs-reflection (static, duality made explicit at filesystem level)

ADR-045 — Recursive level chains and domain co-tenancy (Accepted) + migration 0033

Session 2026-06-02

A three-level architecture surfaced in the field (Rustelo builds a website-mode over a Torred domain; the resulting websites are hosted inside a Provisioning workspace) that ADR-018's absolute Base/Domain/Instance triad could not express. Two generalisations, both opt-in and backward-compatible — a depth≤3 single-chain repo declares nothing new.

  • Relative recursive levels. level.index is reinterpreted as a role in a sliding window of three relative to an observation point, not an absolute coordinate. Actual depth is derived by walking level.parent to a 'Base and is uncappedbase → Torred → Rustelo → website-mode → website-instance is a valid depth-5 chain. A depth≤3 chain derives 'Base/'Domain/'Instance identical to the legacy declaration.
  • Domain co-tenancy. manifest.ncl gains an optional hosts array ({ chain, mount, digest? }). One repo may host foreign chains from other projects, carrying only their Layer-3 wiring under mount, resolved by witness not clone (ADR-028/030). The terminal instance of one chain may re-host another chain's instance (instance-as-host is well-formed).
  • Mutation sovereignty (load-bearing). A host runtime must not mutate a hosted chain's authoritative state — enforced by validate hosts --check mutation-sovereignty (no local op may render_paths into a hosted mount). Hosting is placement + wiring, not ownership (protects ADR-024).
  • Observable traversal. validate.nu gains validate hosts (five checks — chain-ref, mutation-sovereignty, chain-root Hard; layer3-tag, derived-index Soft; with a 5-assertion --self-test) and mode resolve now reports the full traversal path and chain scope, not a single hop. Schema: ontology/schemas/manifest.ncl gains host_entry_type/HostEntry and the relative-level reinterpretation.
  • ADR-045 carries 5 constraints (3 Hard, 2 Soft — Soft on the formalization-vs-adoption Spiral per ondaod), ontology_check verdict 'Safe (invariants at risk: internal-coherence-enforced, protocol-not-runtime, voluntary-adoption — all preserved), and 3 anti-patterns (host-owns-hosted-state, absolute-level-flattening, implicit-hosting). Migration 0033 propagates the schema (protocol-version 0.1.9 → 0.1.10). Graduates the bl-009 level-axis open question; level-hierarchy-resolution core node updated with adrs=['adr-018','adr-045'] and a new → formalization-vs-adoption (Resolves) edge.

ADR-043 — Positioning as a four-element framework (Accepted)

Session 2026-06-02

The positioning layer (ADR-035) is reframed from three entangled artefact kinds into a four-element framework: three orthogonal axes bound by a validation seam. The work began as a strategic exercise — positioning ontoref against knowledge-graph competitors — and converged on a model that mirrors the protocol's own constitutive duality (ADR-031).

  • Three orthogonal axes, each a first-class typed kind. QUÉ — Differentiator (one file per area of differential value) + Competitor (what they do / how ontoref differs). PARA QUIÉN — Audience (gains status: Hypothesis until a Proof validates it). CÓMO — DifusionMechanism (kind: Web | DocsSite | McpServer | Repo | Content | Talk | Event; persistent vs event). Difusión is the category; a Campaign is one time-boxed coordination within it, not the whole of it.
  • The fourth element is the costura, not a fourth axis. VALIDACIÓN — Proof: the convergence of a differentiator, an audience and a difusión mechanism, signed by a real outcome. It references the other three axes; nothing references it — self-similar to the witness-as-axis-seam. ValueProp is the QUÉ×QUIÉN seam (gains differentiator_ids).
  • The marketing surface is governed by the mechanism it sells. ore positioning audit now runs five coherence rules (local-first, daemon-independent): AnchorDrift, UnprovenValidatedAudience, Live-convergence, DanglingRef, CoverageGap. ADR-drift severity is gated by value-prop status — a Draft claim citing a Proposed ADR is informational; only Validated/Live must cite Accepted ADRs (mirroring _live_requires_evidence_adrs). Coverage gaps are explicit reminders, never silent.
  • Schema + contractsontology/schemas/positioning.ncl gains Differentiator, Competitor, DifusionMechanism, Proof (+ enums MechanismKind, ProofKind, AudienceStatus); ontology/defaults/positioning.ncl gains make_* constructors with five rejecting contracts (_diff_requires_anchor, _diff_requires_vs, _mechanism_non_empty, _proof_converges_all, _live_requires_differentiator). Purely additive: every new field is defaulted, so existing positioning files validate unchanged.
  • ontoref dogfood — instantiated under .ontoref/positioning/: 5 differentiators (witness-seam, reflexive-no-drift, graduated-adoption, domain-transversality, agent-native), 5 competitors (Knowledge Graph Guys, Backstage/Port, ADR tooling, GraphRAG/KG-DBs, supply-chain attestation), the latent personal-ontology audience (Yin pole — content/design/research/career), 6 difusión mechanisms, and 4 Proofs (provisioning, personal-ontoref, gestión-proyectos, dogfooding).
  • Daemonontoref-ontology gains the four structs and the walker loads differentiators/, competitors/, difusion/, proofs/; from_config enforces Proof referential integrity (rule 4) at load. GET /api/positioning serves the new kinds with counts (HTTP + MCP).
  • ADR-043 carries 5 constraints (4 Hard, 1 Soft), ontology_check verdict 'Safe (engaged tensions ontology-vs-reflection, formalization-vs-adoption — no invariant broken; self-describing reinforced), and 4 anti-patterns (re-entangle-axes, proof-without-convergence, validated-audience-without-proof, marketing-prose-bypass).
  • No migration required — the schema change is additive and fully defaulted; the positioning layer remains opt-in (ADR-029). A migration is only warranted if the four-element framework is to be actively propagated to consumer projects.

ADR-038 — OCI distribution and installer (Accepted) + migration 0029

Session 2026-05-29

ontoref now ships itself through the OCI registry along two paths from one build, modeled entirely in the workflow layer (not standalone scripts). The load-bearing tension was "Protocol, Not Runtime": a runnable daemon image must not make ontoref a runtime dependency. The synthesis (ADR-029): the daemon image is an optional accelerator; the curl|sh installer installs a daemon-less-capable CLI, so the bundle (protocol surface) and the image (optional service) stay decoupled.

  • Runnable multi-arch image reg.librecloud.online/ontoref/ontoref-daemon:VERSION (linux amd64+arm64) — for running the daemon as a service. Assembled with buildah FROM the cross-compiled musl binary (no recompile, no docker buildx/QEMU/docker-in-docker), cosign-signed with an attested SBOM.
  • curl … | shinstall/install.sh — detects OS/arch, pulls the per-platform bundle from the anonymous-pull ontoref/dist namespace via oras (curl fallback to the OCI Distribution API), verifies the .sha256 sidecar, and installs mirroring install.nu's layout (binary + data layer + wrappers with baked ONTOREF_ROOT + bundled nickel). Linux amd64+arm64 only; macOS gets source-build/container guidance. Flags: --prefix, --version, --data-dir, --uninstall/--purge.
  • Build-oncecross compiles each arch once; both the bundle and the image consume that same binary.
  • Workflow-layer modelbuild_kind gains 'Bundle (reflection/schemas/workflow.ncl); reflection/defaults/workflow.ncl gains builds (release-musl-arm64, bundle-linux-{x86,arm64}, oci-image-build), the smoke-bundle publish gate, and the distributions catalog (oci-image, oci-bundle-linux-{x86,arm64}, installer); ontology/workflow.ncl gains the release layer (trigger 'OnTag). A 4th generator generate-distribution in reflection/modules/workflow.nu (alongside PreCommit/Woodpecker/Justfile) emits .woodpecker/release.yml, renders install/install.sh from install/install.sh.tmpl (tokens from the catalog), and writes justfiles/release.just. Regenerate with ore workflow generate --layer release — never hand-edit the artifacts.
  • Assembler install/assemble-bundle.nu — packages a cross-compiled binary into ontoref-<os>-<arch>.tar.gz (+ .sha256); smoke subcommand extracts and runs the binary (the release gate).
  • Registrymanifest.ncl::registry_provides namespaces extended with ontoref/ontoref-daemon/ and ontoref/dist/ (the bundle namespace is anonymous-pull so curl|sh needs no credentials). Publishing secrets (cosign key, RW credential) come from the src-vault (ADR-017; self-hosted CI has no Fulcio → key-based signing).
  • Dockerfile — root Dockerfile marked dev/local-only; the release image path is .woodpecker/release.yml via buildah.
  • ADR-038 carries 6 constraints (5 Hard, 1 Soft), ontology_check verdict 'Safe (engaged tensions protocol-not-runtime, voluntary-adoption, formalization-vs-adoption — the rare case where more formalization lowers adoption friction), and 4 anti-patterns (daemon-as-mandatory-runtime, hand-maintained-distribution-scripts, recompile-per-arch-image, bundle-carries-project-config).
  • Migration 0029 oci-distribution — additive, opt-in; a project with no release layer is unaffected. Protocol delta 0.1.5 → 0.1.6.
  • FAQreflection/qa.ncl::oci-distribution-and-install documents both install paths, the build-once principle, the workflow-layer model, and the forbidden patterns.

ADR-037 — Interaction trace (Accepted) + migration 0028

Session 2026-05-28

Parse-first record of an agent/human session segment, stored as JSONL so reviews filter typed fields (jq, nu where) instead of mining prose. The opening framing — make the agent emit a typed and validated contract over its reasoning — was consciously narrowed: the goal is parseability, not validation of reasoning (undecidable, and an invitation to schema theatre). Typing is kept for filtering; content of free prose is never validated.

  • Schema reflection/schemas/interaction.nclInteractionRecord + Event, Decision, Action, InteractionInsight, WitnessRef and the EventKind/Status/Outcome/ActionKind enums. Reuses coder.ncl vocabularies (ActorKind, Kind, Domain, optional Category) via import rather than forking. Every filterable dimension is an enum or typed array; free prose is confined to summary, Decision.rationale, Event.note — never a filter axis.
  • Module reflection/modules/interaction.nuore interaction record|validate|list|filter|decisions|insights (alias ix). Two emission paths: record (validated append — forced) and direct JSONL write audited post-hoc by validate (CI/pre-commit gate). The structural validator derives enum allowlists from the schema files at runtime (single source of truth); validation is structural only and never inspects prose content.
  • Optional witness (WitnessRef: op_id/state_root/signature) makes the layer tier-orthogonal: absent at tier-0 (review aid), present at tier-1/2 (reflection-side companion of witnessed acts — the ADR-031 seam). Opt-in per ADR-029; projects that never emit interaction JSONL pay zero adoption cost.
  • Decision materialises the adr? criteria as filterable data (alternatives_rejected, reversible, adr_candidate, tensions_engaged) — ADR candidates surface across sessions in one query.
  • Migration 0028 interaction-record-schema ships the schema to consumer data dirs (additive, opt-in) — lands within 0.1.5, no version bump of its own.
  • Ontology core.ncl gains the interaction-trace Practice node (pole = 'Spiral, axis = 'Act, 6 edges including Complements to coder-process-memory and SpiralsWith from witness-as-axis-seam).
  • ADR-037 carries 5 constraints (3 Hard, 2 Soft), ontology_check verdict 'Safe, and 3 anti-patterns (prose-truthfulness-gate, prose-as-filter-axis, forked-session-vocabulary). All three Hard constraints pass ore adr validate.
  • Web surfaceinteraction export-html renders assets/web/interactions.html (parse-first: structural fields only, never prose); src/index.html gains an 8th protocol-layer card (rose) linking to it. .coder/interactions.jsonl seeded with this session's own three real records (the feature documenting itself).
  • FAQreflection/qa.ncl::interaction-trace-howto (queryable via ore q interaction trace): emission paths, minimal record, filtering, adoption, and the FORBIDDEN structural-only discipline.
  • Bug fix (ADR-032 drift)describe.nu::qa search loaded (project-root)/reflection/qa.ncl; ADR-032 moved the store under .ontoref/, so it now resolves via (instance-root) like coder.nu. The whole Q&A knowledge base was unreachable via ore q in self-hosted layout; one line restores it. Runtime change (reflection/modules/), no migration needed.

cargo update --workspace --offline confirms all 14 crates resolve to 0.1.5.


Version bump 0.1.0 → 0.1.5 — single workspace source of truth

Session 2026-05-27

  • [workspace.package].version = "0.1.5" added to Cargo.toml; all 14 member crates switched to version.workspace = true (also edition and license).
  • .ontoref/card.ncl no longer declares a version field — the daemon and downstream renderers read the canonical version from Cargo.toml. ProjectCard schema's version | String | default = "" makes the field optional.
  • Accumulated protocol-surface deltas now reflected in machine-readable artefacts:
    • 0.1.0 → 0.1.1 — migration 0023 (layout consolidation, ADR-032)
    • 0.1.1 → 0.1.2 — migration 0024 (tier transition, ADR-033)
    • 0.1.2 → 0.1.3 — migration 0025 (catalog kind field, ADR-034)
    • 0.1.3 → 0.1.4 — migration 0026 (ADR anti-patterns field; version delta narrative added)
    • 0.1.4 → 0.1.5 — migration 0027 (positioning layer, ADR-035; version delta narrative added)
    • within 0.1.5 — migration 0028 (interaction record schema, ADR-037; additive, no further bump)
  • cargo metadata --no-deps confirms all 14 crates resolve to 0.1.5.

Resolves the coherence gap where migrations narrated version bumps but Cargo.toml and card.ncl remained at 0.1.0. Future bumps land in one place: [workspace.package].version in the root Cargo.toml.


ADR-035 — Positioning layer (Accepted)

Session 2026-05-26/27

ADR-035 — Positioning Layer: Marketing as Queryable Protocol Surface (Accepted)

  • Outward-facing surface formalised as queryable NCL. Three artefact kinds: Audience, ValueProp, Campaign — typed by schemas installed to the user data dir, instantiated per-project under .ontoref/positioning/.
  • LaunchCheck tagged record ('Grep | 'NuCmd | 'ApiCall | 'FileExists) — structurally identical to ConstraintCheck in .ontoref/adrs/adr-schema.ncl; lift-out tracked as soft constraint shared-check-lift-out-pending.
  • Cross-field contracts in ontology/defaults/positioning.ncl: non_empty_audience_ids, live_requires_evidence_adrs, retired_has_date, superseded_implies_retired, each_launch_check_well_formed. Enforced at nickel-export time via make_audience / make_value_prop / make_campaign helpers.
  • ProjectCard schema extended with optional primary_value_prop_id field — zero-migration: every existing card.ncl typechecks unchanged. When present, MUST resolve to .ontoref/positioning/value-props/<id>.ncl.
  • 6 Hard + 1 Soft constraint: positioning-schema-installed, positioning-defaults-installed, audiences-not-inlined-in-value-props (Grep on primary_pain in value-props), card-primary-vp-resolves-when-set, live-value-props-cite-evidence-adrs, narrative-paths-resolve-when-declared, shared-check-lift-out-pending (Soft).
  • Anti-patterns recorded: live-claim-without-evidence, audience-inlining, marketing-architecture-drift. The drift anti-pattern is closed by ore positioning audit cross-referencing evidence_adrs against ADR status.

Witness-seam (per ADR-031)

  • evidence_adrs on every Live value-prop is the substance-anchoring seam. A Live claim without evidence_adrs is a structural contract violation, not a stylistic concern. This is what distinguishes positioning-as-protocol-layer from positioning-as-CMS.

Migration 0027 — positioning-layer

  • Schema additions to data dir (ontology/schemas/positioning.ncl, ontology/defaults/positioning.ncl).
  • Optional extension to local project-card.ncl schemas (primary_value_prop_id field). Projects that import the protocol-shipped schema via NICKEL_IMPORT_PATH receive the extension automatically.
  • Adopting the positioning layer (creating .ontoref/positioning/{audiences,value-props,campaigns,narratives}/) is OPT-IN per ADR-029. Tier-0 floor cost unchanged.

Consumer layout — .ontoref/positioning/

  • audiences/audience-platform-engineer.ncl — seed audience (channels, evidence, linked_nodes = [voluntary-adoption, self-describing, describe-query-layer, domain-extension-system]).
  • value-props/vp-001-structure-that-remembers.ncl — seed value-prop with 5 evidence_adrs (adr-001, adr-003, adr-009, adr-031, adr-035) and 3 launch_criteria checks.
  • narratives/vp-001-structure-that-remembers.md — prose body for the value-prop claim.

Card integration

  • .ontoref/card.ncl declares primary_value_prop_id = "vp-001-structure-that-remembers", tagline = "Structure that remembers why.". Identity (tagline, stable) and positioning (claim, audience-targeted, evolves) cohabit without conflict.

Tooling surface

  • .ontoref/reflection/modules/positioning.nuore describe positioning [--audience <id>] [--status Live], ore positioning validate, ore positioning audit.
  • .ontoref/reflection/bin/ontoref.nu — dispatcher registers positioning subcommand group.
  • .ontoref/reflection/nulib/help.nu — help text + capabilities surface include positioning.
  • assets/web/positioning.html — landing page for the positioning surface (hand-edited until a follow-up generator ADR replaces it with Jinja from the NCL tree, per ADR-035 §ASSETS/WEB/ DERIVATION).

On+re update

  • .ontoref/ontology/core.ncl — new positioning-layer Practice node (axis=Act, adrs=['adr-035']) with artifact paths to schemas, defaults, consumer layout, module, migration, card, and web page. 11 edges anchor it to: reflection-axis-act (ManifestsIn), witness-as-axis-seam (ManifestsIn via evidence_adrs), formalization-vs-adoption (Resolves), ontology-vs-reflection (Resolves), voluntary-adoption (ManifestsIn), dag-formalized (ManifestsIn), adr-node-linkage (Complements), describe-query-layer (ManifestsIn), mcp-surface (Complements), domain-extension-system (Complements), personal-ontology-schemas (Complements). Plus reverse edge from tier-coexistence-permanent-design (Complements) — positioning is the canonical example of an additive opt-in layer admitted by ADR-029.
  • .ontoref/ontology/state.nclprotocol-maturity blocker extended with session 2026-05-26/27 entry (positioning-layer addition, schema + defaults + migration 0027 + consumer instances + Nu module). self-description-coverage catalyst extended; total ADR count: 35 (ADR-021 → ADR-035 since session 2026-05-01).

Ondaod synthesis (recorded in ADR-035 ontology_check)

  • formalization-vs-adoption (Spiral, Tension) engaged. Synthesis state: realised — opt-in tier-orthogonal layer raises formalisation ceiling without raising the tier-0 floor. voluntary-adoption axiom preserved.
  • ontology-vs-reflection (Spiral, Tension) engaged. Synthesis state: realised — positioning lives on the reflection axis; evidence_adrs deposits the witness-seam to substance. Per ADR-031, the seam extends outward to the marketing surface. Both Spirals stay open; verdict 'Safe.

Cluster B — ADR-033 + ADR-034 design + catalog-extension examples

Session 2026-05-26

ADR-033 — Tier Transition Mechanism (Proposed)

  • Dual-surface transition_tier: ontoref tier set <T> CLI (every tier) + tier-2 catalogued op, both routing through a single Rust function that invokes enforce_tier_transition_guard from crates/ontoref-daemon/src/tier_guard.rs (the pure validator already shipped under ADR-029).
  • Downgrade behaviour: substrate (oplog, commit_layer, state_root, signing keys) marked dormant immutable; past witnesses verify forever. Tier-2 descent emits a final tier_descent Ed25519 witness as the closing event.
  • Transactional atomicity per direction — every transition produces exactly one of two outcomes: the project is at the requested tier OR at the original tier. No intermediate partial-substrate state ever visible.
  • 8 Hard constraints + 1 Soft. piloto-declares-its-tier couples the mechanism to its canonical instance: ontoref's own .ontoref/config.ncl declares ops.tier = 'Tier2 as part of this ADR (deferred to implementation per 'Proposed status).

ADR-034 — Catalog Extensibility Beyond Rust (Proposed)

  • Schema-level kind discriminator on OperationDecl / ValidatorDecl admitting 'Rust (default, executable today), 'NclTransform, 'Wasm, 'Sidecar. Per-kind body shape validated structurally; executive impls trigger-deferred per ADR-030.
  • Hard constraint non-rust-kinds-require-ondaod-pre: every non-Rust op MUST list "evaluate_ondaod" in constraints.pre. Enforced as a Nickel contract at typecheck time — ADR-024 ondaod discipline becomes structural rather than behavioural for the non-Rust path.
  • wasmtime MUST NOT enter the default daemon build (wasmtime-not-in-default-daemon-build) — protocol-not-runtime axiom (invariant=true) preserved.
  • Declarable-not-executable returns HTTP 501 (non-rust-kinds-declarable-not-executable-without-flag) — silent 404 is forbidden.

Migrations

  • reflection/migrations/0024-tier-transition-mechanism.ncl — documents the CLI + op surfaces, recommends explicit ops block in .ontoref/config.ncl. Protocol bump 0.1.1 → 0.1.2.
  • reflection/migrations/0025-catalog-kind-field.ncl — schema bump for the four kinds with default 'Rust. Backward-compatible: existing declarations typecheck unchanged. Protocol bump 0.1.2 → 0.1.3.

QA additions

  • reflection/qa.ncl::ontoref-catalog-extension-howto — end-to-end how-to covering all four paths with decision tree, authoring steps, hard rules, witness-shape honesty per kind, when-you're-blocked triage.
  • Reverse links added: ontoref-tier-transition, ontoref-tier-downgrade-asymmetry, ontoref-multi-tier-management, ontoref-catalog-discovery-shared-domain now reference ADR-033 / ADR-034 in their related arrays.

Examples folder — examples/catalog-extension/

  • 16 files demonstrating all four kinds end-to-end.
  • schema-future.ncl co-locates the post-migration-0025 contract so all four examples typecheck today, even though the protocol schema is still pre-bump. Ondaod-pre Hard contract verified to fire on the negative case.
  • 01-rust/ — declaration + handler skeleton for greet_actor.
  • 02-sidecar/ — declaration + standalone axum sidecar binary (cargo check clean) on :7902 implementing send_email_notification; mirrors ADR-030 mechanism #6 wire shape.
  • 03-ncl-transform/ — declaration of rename_ontology_node; declarable today, dispatch returns 501.
  • 04-wasm/ — declaration of render_provisioning_report + WIT interface skeleton; declarable today, dispatch returns 501 until ADR-030 T3/T4/T5 fires.

Ondaod synthesis (recorded in both ADRs' ontology_check)

  • ADR-033 engages ontology-vs-reflection (tier change is an act mutating substance; witness emitted at tier-2 boundaries is the seam) and formalization-vs-adoption (dual-surface CLI+op preserves both poles). Both Spirals stay open.
  • ADR-034 engages formalization-vs-adoption (Rust strongest guarantees, NCL/Wasm/Sidecar lower barrier with weaker guarantees — schema admits all four without collapse) and the protocol-not-runtime axiom (preserved by deferring executive impls per ADR-030 triggers). Both poles continue in dialectic.

γ-posture lift-out validation — second-consumer gate, ontoref-compute constructors, on+re tracking

Session 2026-05-12

Second-consumer validation of ontoref-auth, ontoref-ui, ontoref-compute, ontoref-dns

  • γ-auth: SUCCESS — lian-build delegates password hashing and session creation to ontoref_auth::password::*; SessionStore and AuthUser re-exported unchanged.
  • γ-ui: SUCCESS — lian-build and ontoref-panel both adopt ontoref_ui::init_tera; TeraEnv::Deref<Tera> means zero call-site changes in either consumer.
  • γ-compute: PARTIAL — lifecycle surface (spawn/destroy/status/list/health) validated by two consumers; ScriptProvider tagged-enum envelope structurally incompatible with lian-build's flat-JSON Nu scripts (documented gap, adapter path exists).
  • γ-dns: SUCCESS — orchestrator replaces coredns_client.rs with Arc<dyn DnsProvider>; two independent consumers confirmed; trait locked.

ontoref-compute — public constructors for non-exhaustive structs

  • Added Instance::new(handle, provider), ProviderHealth::healthy(latency_ms), ProviderHealth::unhealthy(latency_ms, reason) to resolve E0639 (#[non_exhaustive] blocks struct literal construction in external crates).
  • Named constructors are the stable external API; #[non_exhaustive] retained so future optional fields do not break consumers.

ontoref-panel C.5 — static asset pipeline and deployment architecture

  • public_dir and templates_dir added to DaemonConfig; surfaced as PANEL_PUBLIC_DIR / PANEL_TEMPLATES_DIR env vars and CLI args.
  • ServeDir mounted at /public in Axum router (tower-http); attached before .with_state(state) in routes builder.
  • UnoCSS + DaisyUI + HTMX build pipeline: package.json, uno.config.ts, multi-stage Dockerfile (node-build + rust-build + runtime). Docker build context must be the parent directory of all sibling repos — required for path deps to resolve.
  • AssetUrls path contract: /public/css/app.css, /public/vendor/htmx.min.js.

ADRs authored

  • lian-build/adrs/adr-008-ontoref-foundation-migration.ncl — migration rationale, γ verdicts per crate, ScriptProvider partial finding
  • ontoref-compute/adrs/adr-001-non-exhaustive-constructors.ncl — named constructor contract for non-exhaustive output types
  • ontoref-panel/adrs/adr-007-static-asset-pipeline.md — UnoCSS+DaisyUI choice, Docker build context contract, AssetUrls path binding
  • provisioning/adrs/adr-043-ontoref-foundation-orchestrator.ncl — orchestrator γ-posture adoption (DnsProvider + ComputeProvider + federation manifest endpoint)

Self-Description — on+re Update

.ontology/state.nclprotocol-stable transition note: γ-posture validation results recorded per consumer; ScriptProvider envelope gap documented as known partial finding with adapter path (LianBuildScriptProvider).

.ontology/core.nclunified-auth-model updated with γ-posture verdicts for all four foundation crates; ontoref-daemon updated with handlers/ split note, TeraEnv migration note, panel C.5 CSS pipeline description.


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 <id> — 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/<check.crate>/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 (⟳ <participant>) when manifest.ncl::registry_provides is declared.
    • Vault badge (⛁ <vault_id> · 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 <vault_dir>/.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.

Testsreflection/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/<run_id>/, 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/<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.