diff --git a/CLAUDE.md b/CLAUDE.md index aa14e20..3ce2f2c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -159,6 +159,16 @@ design decision, not a refactor, and belongs in the ledger. harness and is an execution viewer / trace explorer (structure before, live streams during, recorded traces after) — never a scene editor; topology is grown in Rust + hot-reload, runtime params are UI-tunable. +13. **Self-description: every surface explains itself.** Every closed- + vocabulary entry the binary exposes (nodes, metrics, tap slots, folds, + blocks) carries a one-line meaning, enforced at its entry seam — + compile/unit for engine-shipped entries, load for native node crates, + register for the content-addressed store (documents: an optional gated + `description`). The gate is deterministic string shape (`doc_gate`), + never content judgement: the engine never evaluates description text + (no freetext logic hole, invariant 10), descriptions never influence + execution, determinism (C1), or identity ids, and registered artifacts + are never retroactively invalidated. (C29) ## HTML surfaces diff --git a/docs/design/INDEX.md b/docs/design/INDEX.md index 1790c51..a04a7c6 100644 --- a/docs/design/INDEX.md +++ b/docs/design/INDEX.md @@ -194,6 +194,13 @@ the repo, not session memory, is the source of truth. measurement/strategy → backtest → execution) beside a process column, an assembly position, and an import-only shell — the import direction enforced structurally by the full-workspace `c28_layering` guard. +- **[C29 — Self-description: every surface explains itself](contracts/c29-self-description.md)** — + Every closed-vocabulary entry carries a one-line meaning behind one shared + shape gate (`doc_gate`) at three seams — compile/unit (engine-shipped), + load (native node crates), register (the content-addressed store, incl. an + optional gated document `description`); descriptions never influence + execution or identity ids, and registered artifacts are never + retroactively invalidated. --- diff --git a/docs/design/contracts/c29-self-description.md b/docs/design/contracts/c29-self-description.md new file mode 100644 index 0000000..c841eef --- /dev/null +++ b/docs/design/contracts/c29-self-description.md @@ -0,0 +1,61 @@ +# C29 — Self-description: every surface explains itself + +**Guarantee.** Every closed-vocabulary entry the binary exposes carries a +one-line meaning, enforced at the seam where the entry enters the system; +everything entering the content-addressed store describes itself; a refusal +for a missing description names the entry, the field, and the rule. One +shared deterministic gate — `doc_gate` in aura-core, importable by every +seam per [C28](c28-stratification.md); it fails on an empty/whitespace doc +and on a doc that normalizes to the entry's own name +(`DocGateFault::{Empty, RestatesName}`) — guards three seams: + +1. **Compile/unit seam (engine-shipped).** `NodeSchema.doc` is a required + field, so the compiler enumerates every construction site; metrics and + tap slots are schema carriers (`MetricSchema` / `TapSchema`, id + doc); + blocks (`BlockSchema.doc`, the pre-existing model) and tap folds (the + registry roster, [C27](c27-declared-taps.md)) already carried theirs. + The coverage walk (`aura-cli/tests/self_description.rs`) asserts the + gate over all five vocabularies — the engine satisfies its own law. +2. **Load seam (extension).** `load_crate` walks every charter-checked + type id and gates the resolved schema's doc; a fault refuses the load + naming type and rule (`ProjectError::UndescribedVocabularyEntry`). + Field presence is compile-enforced for any crate built against the new + core; the load gate catches the shape violations the compiler cannot + see across the cdylib boundary — the empty-string alibi and the name + restatement. +3. **Register seam (data plane).** The registry's public `put_blueprint` + parses the canonical bytes and requires a gate-passing doc on the root + composite and on every named nested composite — the gate guards the + store boundary itself, so the register verb, every register-then-run + sugar path, and any future caller are gated by construction. The + op-script vocabulary carries the `doc` op as the builder `.doc(...)`'s + twin ([C25](c25-role-model.md): a closed, typed metadata construct). + Process/campaign documents take an additive-optional top-level + `description`, gated only when present (`DocFault::BadDescription`). + +**Id treatment.** Description fields that serialize participate in the +content id and are blanked for the identity id, exactly as `Composite.doc` +(`strip_debug_symbols`); `NodeSchema` is not serialized +([C24](c24-blueprint-data.md)), so node docs move no id. Documents have no +identity projection — their pair is: absent `description` is byte-identical +to the field-less form (existing content ids stable), present participates. + +**Forbids.** The engine evaluating description text — the gate is +deterministic string shape, never content judgement (no freetext logic +hole; C17 / domain invariant 10 untouched). A description influencing +execution, identity ids, or determinism (C1). Retroactive invalidation of +already-registered artifacts — the gate guards the write path only (the +raw in-crate write survives as the store-mechanics and back-compat +witness: pre-C29 doc-less entries stay readable). Machine-invented meaning +lines — an authored text is corrected against the source, never weakened +to an empty string or a name restatement. + +**Why.** The audience is headless LLM agents and scripts (#319 ruling), +for whom the binary is the only always-present teacher. Field evidence +2026-07-22 (#314): an agent holding only the release binary had to recover +execution semantics and document schemas by CAS forensics — the removed +failure class is exactly that forensic recovery. + +Rendering of the carried texts on the help/introspection surfaces is #315; +the generated agent bootstrap card is #267; a fold introspection surface +is blocked on #310.