Files
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

4.6 KiB

C26 — Harness input binding: role names bind archive columns

Guarantee. A strategy blueprint declares WHICH data it consumes as the NAMES of its root input roles: a role whose name is in the closed column vocabularyopen, high, low, close, spread, volume, plus price as the backward-compatible alias of close — binds by default to that column of the campaign cell's (or run invocation's) instrument. A campaign document may override the name default per role via the additive data.bindings block (role name → column name; serde default + skip-if-empty, so binding-less documents keep their content ids) — the 6b rebind seam: the blueprint's content identity never changes.

Resolution (aura-runner's binding module, resolve_binding) produces ONE ordered plan consumed by BOTH halves of the old weld: the columns are opened (aura_ingest::open_columns, the generalization of open_ohlc/#92) and the wrapped root roles declared (aura-runner::member's wrap_r) in the same canonical orderM1Field declaration order (open, high, low, close, spread, volume), filtered to the consumed set — which is the C4 merge tie-break order, so role i receives source i by construction. A close column is always part of the plan (shared when the strategy consumes close/price, else opened for the broker/executor pair alone).

The vocabulary is Blockly-litmus-clean (C25): role-name slots draw from a closed enum, the bindings block is typed role → column with no free-form holes, and validation is two-tier — values against the column vocabulary in the intrinsic tier (validate_campaign, aura-research), keys against the strategies' input_roles() in the resolver tier (validate_campaign_refs, aura-registry).

Forbids. Guessing a column for an unknown role name (refuse with the vocabulary

  • the override remedy, never default); opening columns in any order other than the canonical declaration order (the C4 tie-break contract); free-form or logic-bearing binding values (the C17/C25 line — a binding value is a typed column reference, nothing else); fabricating synthetic OHLC when a multi-column strategy meets synthetic data (the walk generates a close series only — refuse with the --real remedy).

Why. The single-price weld — wrap_r's hard-wired price←close and the six M1Field::Close-only open sites — made every strategy monocular regardless of what its blueprint declared. Binding by role name keeps the blueprint the single source of its own data needs (C24: topology-as-data carries its input contract), lets a campaign re-aim a strategy without touching its content id (C18 identity), and pins opening and declaring to one shared, canonically-ordered plan so the two halves cannot drift (C1/C4 determinism).

Current state

resolve_binding lives in aura-runner's binding module (crates/aura-runner/src/binding.rs), moved out of the shell with #295; it takes the strategy name, its input_roles(), and the campaign override map and returns one ResolvedBinding plan. Column opening is aura_ingest::open_columns (crates/aura-ingest; the M1Field enum fixes the declaration order open/high/low/close/spread/volume); role declaration is wrap_r in aura-runner::member. Both validation tiers are realized: validate_campaign (crates/aura-research) checks binding values against the column vocabulary; validate_campaign_refs (crates/aura-registry) checks binding keys against the strategy's declared roles.

Extension point (deferred). When recorded non-price sources land (the #71 Source seam), the binding VALUE-space grows additively from archive columns to recorded-stream references — a root role like sentiment becomes bindable to a recorded stream then, and until then refuses with the vocabulary-naming message. The role-name key-space and the campaign bindings carrier are unchanged by that growth.

See also

  • C4 — the merge tie-break order that is the canonical open/declare order
  • C24 — topology-as-data carrying its own input contract
  • C18 — the content-id identity a rebind must not touch
  • C25 — the Blockly litmus the vocabulary satisfies; the 6b rebind seam
  • C1 — the determinism the shared plan protects
  • C27 — the output-side twin (taps to input_roles)