Files
Aura/docs/design/contracts/c24-blueprint-data.history.md
T
claude 8688a60ded docs(ledger): split the design ledger into an INDEX map, per-contract live files, and history sidecars
The single-file ledger had grown to 2968 lines / ~42k tokens, mixing
current design law with accreted history: 59 cycle-stamped realization
blocks, 18 [HISTORY] passages, 22 supersession markers, and the C10 /
C22 / C24 reframe sagas layered several supersessions deep. A
code-grounding audit (31 agents, adversarially verified) confirmed 11
defects stated as current truth: stale crate homes from the C28 #288
roster split (cost nodes, PositionManagement, PositionEvent, Session),
the renamed InputSpec->PortSpec, the pre-#241 project model in C16 and
the open-threads section, a stale HarnessKind retirement deferral in
C24, and three C28-internal inconsistencies.

New shape, per the ailang precedent:

- INDEX.md stays the sole addressable entry point: foundation, external
  components, a C-id-keyed contract map (one line per contract), and
  only the genuinely open architectural threads.
- contracts/cNN-<slug>.md carries each contract's current truth only:
  Guarantee / Forbids / Why with ratified refinements integrated, plus
  a code-anchored Current state. All confirmed defects are fixed here;
  crate anchors were re-verified against the tree.
- contracts/cNN-<slug>.history.md (18 sidecars) and INDEX.history.md
  preserve every superseded block verbatim, stamps and issue refs
  intact, under a frozen-record banner. Nothing was deleted: superseded
  design intent remains an addressable working-tree artifact, off the
  per-cycle audit walk.
- Ledger discipline is now stated in INDEX.md: live files are edited in
  place at cycle close, superseded text moves verbatim to the sidecar,
  and a supersession marker in a live file is itself an audit finding.

Every contract file was verified against its old text by an independent
zero-loss pass (statement-by-statement) plus a code-accuracy spot check;
C-ids and contract titles are unchanged, so existing C-id citations in
code, tests, and issues resolve as before.
2026-07-21 16:40:36 +02:00

14 KiB
Raw Blame History

C24 — The blueprint is a serializable, World-owned data value (the topology data format): history

FROZEN HISTORICAL RECORD. Each block below was true as of its cycle/date stamp and may be superseded; this file is NOT current truth and NOT a grounding surface. Current contract: c24-blueprint-data.md.

Status (2026-06-29; first cut shipped — cycle 0087 / #155, d5602ec; construction service shipped — cycle 0088 / #157). The principle is settled (this contract, ratified in an in-context design discussion — the #109 resolution). The first cut now ships: a Composite blueprint serializes to a canonical, versioned data value (format_version envelope, omit-defaults JSON) and loads back (data → blueprint → FlatGraph) via blueprint_to_json / blueprint_from_json (aura-engine::blueprint_serde), referencing nodes by compiled-in type identity through an injected resolver whose concrete closed match over the aura-std vocabulary lives outside the engine (aura-std::std_vocabulary) — the engine stays domain-free, no node registry (invariant 9). Acceptance met: a serialized blueprint runs bit-identical (C1) to its Rust-built twin. model_to_json (C9) remains the render half; this closes the loop for the round-trippable vocabulary. Cycle 0088 (#157) adds the introspectable construction service: a declarative, replayable by-identifier op-script (aura graph build / introspect over a JSON op-list, the engine GraphSession / replay) builds a runnable blueprint through validated ops — the engine's construction gates split into eager per-op checks (name resolution, edge kind-match, the double-wire arm, param bind, and acyclicity — a connect that would close a cycle is rejected eagerly, #161) and holistic finalize checks (wiring totality, param-namespace injectivity, root-role boundness), both cadences calling the same extracted predicates (edge_kind_check, the shared resolution helpers, check_root_roles_bound — no second validator) — plus build-free introspection over the closed vocabulary (types, a node's ports/kinds, a partial document's unwired slots). It emits the #155 blueprint; acceptance met: a graph built purely through the ops compiles identical (C1) to its Rust-built twin, an invalid op is rejected at the op naming the cause, introspection answers without a build. The engine Op stays serde-free (the wire DTO is CLI-side); the vocabulary's enumerable companion (std_vocabulary_types) lives in aura-std (no registry, invariant 9). Cycle 0089 follow-up (#161 / #162, after the cycle-0088 fieldtest). The eager acyclicity gate above (GraphSession::closes_cycle, a reachability check at the closing connect) closed a fieldtest-found hole where graph build accepted a non-DAG op-list (invariant 5 / C9). Lockstep: it is a second home of invariant-5 alongside the bootstrap Kahn sort (harness.rs, BootstrapError::Cycle); the two must co-evolve when the explicit delay/register node — invariant-5's sole legal feedback — lands, or a valid delay-feedback graph the bootstrap accepts would be rejected at construction. The holistic finalize faults now also read by-identifier (#162): finish() translates the index-carrying CompileErrors (UnconnectedPort / RoleKindMismatch / UnboundRootRole) into by-identifier OpError variants — still calling the unchanged holistic gates (the no-second-validator lockstep preserved), only translating their result. Cycle 0090 (#156) codifies the forward-compat two-tier discipline. Tier-1 (additive-optional) is serde-default silent-ignore with no format_version bump (a new optional field defaults to prior behaviour, C1) — now proven by unknown_optional_field_is_tolerated_byte_identically (an unknown optional key loads byte-identically and runs bit-identically). Tier-2 (must-understand: a new node type, edge semantics, or structural-axis kind) bumps format_version so an old reader refuses cleanly (LoadError::UnsupportedVersion / UnknownNodeType, already green). The per-section required-flag scheme is deferred (no current Tier-2 section to validate it; recorded on #156). Pre-ship dormancy (#61, 2026-07-10): until the first external ship there are no out-of-repo readers — reader and writer change atomically in one commit — so the Tier-2 bump discipline is dormant and structurally-semantic additions (the gangs section) land as additive-optional fields of v1; the first ship consciously freezes v1, gangs included, and activates the bump discipline.

Milestone delivered — 2026-06-30, cycle 0090 — the serializable format + loader + construction service. A green end-to-end milestone fieldtest (fieldtests/milestone-topology-as-data/) proves the full author → serialize → load → construct → introspect → reproduce story from the public surface alone, 0 behavioural bugs; the round-trippable format (#155), the construction service (#157), and the forward-compat two-tier discipline (#156) all shipped. Polish filed forward: op-script grammar docs + a stale example (#163), the canonical trailing-newline / Composite value ergonomics (#164), CLI discoverability of build/introspect (#159).

Realization (2026-06-30, cycle 0092 — runs are built FROM blueprint-data, #165). aura run <blueprint.json> now loads a serialized signal blueprint (blueprint_from_json → the closed std_vocabulary; an unknown type fails clean as UnknownNodeType, the data-plane face of invariant 9), wraps it in the r-sma run scaffolding (sinks / broker / data supplied at run, not serialized — C24's deferred set), runs it, and emits a RunReport bit-identical (C1) to its Rust-built twin — proven by loaded_signal_runs_bit_identical_to_rust_built. The RunManifest now carries a topology_hash: SHA256 of the canonical (#164) blueprint_to_json, the #158 reproducibility anchor, a Tier-1 optional field (#156). The hash + helper live research-side (aura-cli + sha2), off the frozen engine (invariant 8). This is the keystone of the World/C21 milestone: topology-as-data is now runnable, not only serializable. The harness wrap was made shareable — r_sma_graph() = wrap_r(sma_signal(...)), so the Rust path and the data path are the same seam over the same signal (a behaviour-preserving C19/C23 restructure). Scope note: the hash covers the signal only (the fixed scaffolding is identified by commit); a content-id distinguishing harness-structural variants is a #158/#166 concern once scaffolding varies.

Realization (2026-07-01, cycle 0093 — the World orchestrates FAMILIES from blueprint-data, #166). aura sweep <blueprint.json> --axis <name>=<csv> loads an open signal blueprint, grids the by-name axes against its param_space(), builds each member through cycle-1's wrap_r seam, and aggregates to a FamilyKind::Sweep family — byte-identical in shape to the hard-wired sweep (append_family / sweep_member_reports reused verbatim). This is the C21 step beyond a single run: the World now constructs and orchestrates families of harnesses from topology-data, not just one. Each member manifest carries the shared topology_hash (one signal topology, only params vary; member_key distinguishes members) — reproducible per C18. Two design facts: a sweep needs an open blueprint (a fully-bound one has an empty param_space, distinct from cycle-1's bound run fixture), and the signal is re-loaded per member from its serialized doc (the Composite is !Clone — its PrimitiveBuilders hold Box<dyn Fn> build closures, #164 — and bootstrap_with_cells consumes the graph). Monte-Carlo over a loaded blueprint shipped (cycle 0095, #170). aura mc <blueprint.json> --seeds N runs a closed blueprint across N seeds — each seed a distinct synthetic price walk (synthetic_walk_sources, the mc_family SyntheticSpec pattern), the draws disjoint-parallel via the engine monte_carlo seam (invariant 1) — and aggregates to a FamilyKind::MonteCarlo family with one stored blueprint per family (the C18 hook), so it aura reproduces bit-identically (C1). MC binds no axis, so it needs a closed blueprint (the sweep's open/closed distinction inverted); an open one returns a named Err (rendered exit-2 at the run_blueprint_mc boundary, the sweep sibling's contract — no hidden exit in the pure builder). IS-refit walk-forward shipped (cycle 0097, #173). aura walkforward <blueprint.json> --axis <name>=<csv> [--select argmax|plateau:mean|plateau:worst] re-optimizes the loaded blueprint's params over the user --axis grid (the #169 prefixed names) on each 24/12/12 IS window, selects the winner by sqn_normalized (the hard-wired arm's metric + select_winner reused verbatim), runs it out-of-sample, and aggregates to a FamilyKind::WalkForward family — persisted + content-addressed + aura reproduce bit-identical (the read-side WalkForward branch rebuilds each OOS window from manifest.window). One substitution deep from the hard-wired r-sma WF arm (the loaded blueprint via blueprint_axis_probe replaces the built-in strategy); a bad --axis is a clean in-closure exit 2, never a panic. This is Arm A (the settled direction): the loaded IS-optimizing form honestly carries the walkforward name. Reduce-mode members are R-measured (oos_r the meaningful summary; stitched pip-equity empty, C10). The synthetic-walk DGP is the machinery, not trader-grade MC statistics; a real-data block-bootstrap — and the synthetic_walk_sources len:60↔warm-up coupling it retires (a deep-lookback closed blueprint warms poorly → silent-vacuous draws today) — ride #172. Axis-name discovery shipped (cycle 0096, #169): aura sweep <blueprint.json> --list-axes lists a loaded blueprint's open sweepable knobs (one <name>:<kind> per line, param_space() order), then exits — the names it prints are exactly what --axis binds. Every listed name is mandatory on a sweep / walkforward: the blueprint must be fully bound before it runs, so a subset grid is refused with the missing knob named (BindError::MissingKnob) and there is no default — pin a knob you do not want to vary with a single-value axis (--axis <name>=<one-value>). A single blueprint_axis_probe helper now single-sources the wrapped probe (wrap_r(loaded_signal).param_space()) for the sweep terminal, the MC closed-check, AND the listing (three former inline copies → one), so listed == swept by construction (and stays so across #159's harness retirement — the listing tracks whatever the sweep actually resolves, never a second source of truth). The names are prefixed by the current r-sma wrapping (sma_signal.fast.length, the nested-composite prefix), not the raw param_space — which is why the discovery lives on the sweep verb (it owns the wrapping), not graph introspect. CLI --trace is refused on all verbs (#168 for sweep/walkforward; run/mc already refused); the live trace-writer is the campaign presentation.persist_taps (persist_campaign_traces), and restoring per-member CLI traces is tracked by #224. [Delivered 2026-07-11 (#224): sweep/walkforward --trace write per-member traces on the real-data campaign path (depth-2 fan-out, chartable by the printed family handle); only the synthetic path still refuses.]

Content-addressed reproduction shipped (cycle 0094, #158, C18): topology_hash landed cycle 0092; re-deriving a member's FlatGraph from a stored manifest + the content-addressed blueprint store (aura reproduce) shipped cycle 0094 (see C18 Realization). What remains is a content-id that covers structural-axis / whole-harness variants (the scaffolding is not yet blueprint-data); the debug-name-in-id question is settled by cycle 0104's identity id (#171: blueprint_identity_json + graph introspect --identity-id, an additive sibling — the byte-exact content id keeps the store/reproduce roles; introspection-only until a dedup consumer exists). Still deferred: retiring the pre-C24 hard-wired aura-cli harnesses (HarnessKind, run_r_sma, *_sweep_family) once the project-as-crate layer lands (#159, paired with #157's data-authoring surface). Out of the first cut's round-trippable set (deliberate; fails clean as UnknownNodeType, never a silent wrong graph): recording sinks (capture an mpsc::Sender — runtime identity, not param-generic data, C19) and construction-arg builders (LinComb / CostSum / SimBroker / Session — structural-axis args, a C20 concern), additively addable later (#156). The project-as-crate load boundary landed in cycle 0102 (Aura.toml discovery + cdylib loading + merged project std vocabulary — see the C13 realization note; the aura new scaffolder followed in cycle 0103 — one command emits a buildable project whose blueprint runs through the merged vocabulary); of the two layers this paragraph used to name as sequencing-coupled, what remains open is the composable-orchestration thread (#109): topology-as-data is the substrate it stands on. Canonical project shape (#181, resolved 2026-07-02): the aura new templates (scaffold.rs) are the canonical authoring shape and evolve with the engine; the cycle-0102 demo-project fixture is an intentionally frozen known-good twin for the load-boundary tests. The two are deliberately not lockstep-guarded: no consumer requires them to match, each is e2e-guarded on its fitness for purpose (build → descriptor load → charter check → deterministic run — blueprint wiring content is pinned in neither, stated honestly), and an equality guard would convert every deliberate template improvement into forced churn of the frozen fixture — the same cross-purpose coupling that rules out regenerating the fixture from the scaffolder.

[C26, 2026-07-10 (#231): the single-price data weld inside the surviving wrap_r scaffolding is retired — input roles bind archive columns by name; the wrapper's remaining R-scaffolding retirement stays #159.] (From the C24 Forbids clause as of that date; the single-price weld was retired at #231/C26, but wrap_r itself survives — its full R-scaffolding retirement stays deferred, #159.)