8688a60ded
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.
74 lines
4.6 KiB
Markdown
74 lines
4.6 KiB
Markdown
# 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 vocabulary** —
|
|
`open`, `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 order** — `M1Field` declaration order (open, high, low, close, spread,
|
|
volume), filtered to the consumed set — which is the [C4](c04-cycle-granularity.md)
|
|
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](c25-role-model.md)): 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](c04-cycle-granularity.md) tie-break contract);
|
|
free-form or logic-bearing binding values (the [C17](c17-authoring-surface.md)/[C25](c25-role-model.md)
|
|
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](c24-blueprint-data.md): topology-as-data carries its
|
|
input contract), lets a campaign re-aim a strategy without touching its content id
|
|
([C18](c18-registry.md) identity), and pins opening and declaring to one
|
|
shared, canonically-ordered plan so the two halves cannot drift
|
|
([C1](c01-determinism.md)/[C4](c04-cycle-granularity.md) 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](c04-cycle-granularity.md) — the merge tie-break order that is the canonical open/declare order
|
|
- [C24](c24-blueprint-data.md) — topology-as-data carrying its own input contract
|
|
- [C18](c18-registry.md) — the content-id identity a rebind must not touch
|
|
- [C25](c25-role-model.md) — the Blockly litmus the vocabulary satisfies; the 6b rebind seam
|
|
- [C1](c01-determinism.md) — the determinism the shared plan protects
|
|
- [C27](c27-declared-taps.md) — the output-side twin (`taps` to `input_roles`)
|