docs(ledger): C24 enforcement shift — invariant 9 moves from structural to resolver-seam

A cycle-0091 design analysis (adversarially verified) of "does invariant 9
survive lifting blueprints onto the data plane?" records a load-bearing finding
in the C24 entry.

Pre-C24 a blueprint referencing another project's node was a compile error
(topology was in-process Rust — structurally impossible). Post-C24 it is a
type-id string refused only by the injected resolver's closed set
(UnknownNodeType). The anti-NIH rationale survives (logic stays cargo+Gitea-only;
the format distributes topology-as-content, never logic, C17) and std_vocabulary
stays a compiled-in dispatch table, not a registry — but enforcement of the
engine/project boundary degrades from compiler-guaranteed to resolver-seam
discipline. Two consequences recorded: #160 becomes the data-plane face of that
boundary (no longer droppable; its own drift still fails safe), and the injected
per-project resolver is the genuinely new, deferred invariant-9 surface (a
project can express a marketplace one layer above the engine contract) — a
World/C21-layer charter point. Invariant 8 (frozen) is reframed alongside:
runtime topology generation (research plane) + frozen deploy artifact +
deterministic-once-instantiated (C1).

refs #160
This commit is contained in:
2026-06-30 17:27:11 +02:00
parent 4a3ae05db2
commit df228986c4
+24
View File
@@ -1883,6 +1883,30 @@ non-printable; equality could only be defined over the serialized *data*, of whi
a drift hazard against the very form #158 content-addresses). The loader stays lenient
(a trailing newline on input still parses, Tier-1 robustness).
**Enforcement shift — invariant 9 on the data plane (2026-06-30, cycle-0091 analysis,
adversarially verified).** Lifting topology onto the data plane relocates *where* the
engine/project boundary (invariant 9, no bespoke node registry/marketplace) is enforced,
without changing what it forbids. **Pre-C24** a blueprint referencing another project's
node was a **compile error** — topology was in-process Rust, so cross-boundary node
resolution was *structurally impossible*, compiler-guaranteed for free. **Post-C24** that
same reference is a **type-id string in a serialized blueprint**, refused only by the
injected resolver's closed set (`UnknownNodeType`). The anti-NIH rationale survives intact
(node *logic* stays cargo+Gitea-only; the format distributes **topology-as-content**, never
logic — C17), and `std_vocabulary` stays a compiled-in dispatch table, not a registry — but
its enforcement **degrades from compiler-guaranteed to resolver-seam discipline**. Two
consequences: (1) **#160** (the guard that the closed vocabulary stays honest) is no longer
droppable hygiene — it guards the data-plane face of the boundary (its own drift direction
still fails *safe*, `UnknownNodeType`). (2) The **injected per-project resolver** (C16) is
the genuinely new, *deferred* invariant-9 surface: nothing structurally stops a project
resolver from accepting arbitrary type-ids, or a project from layering a blueprint
*marketplace* (store + type-discovery API) **on top of** the format — one layer *above* the
engine contract. Invariant 9 holds **at the engine**; the project/ecosystem boundary (what
an injected resolver may resolve, where closed-set discipline draws the line) is a
**World/C21-layer charter point**, not an engine fix. Invariant 8 (frozen) is likewise
reframed by C24/C21: from "topology baked at build time" to "the World may *generate*
topology at runtime (research plane), the chosen blueprint is frozen into the deploy
artifact, and any run is deterministic once instantiated" (C1).
---
## Open architectural threads not yet resolved