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