Process & campaign document vocabularies: parse, validate, introspect, content-address (no executor) #189

Closed
opened 2026-07-03 12:38:03 +02:00 by Brummel · 3 comments
Owner

Define the two research-artifact document types from the #188 role-model design pass — the process document (role 5: a named, versionable validation/eval methodology) and the campaign document (role 6b: persisted experiment intent — data windows × strategy references × axes × process reference × data-level presentation) — as closed-vocabulary, typed, serialized data, with parsing, validation, the introspection contract, and content-addressing. No executor in this cycle.

Design basis (all on #188): the issue body (role model, resolved forks 1–4), the addendum comments (introspection contract from day one; P1 control-flow tier: axes / gates / ladders), the fork-triage comment (decided items 1–8), and the resolution comment (user decisions A–C). Key constraints fixed there:

  • Canonical JSON with a format_version envelope; content id through the same hashing primitive blueprints use; documents stored content-addressed beside blueprints in the registry store pattern.
  • Campaign documents reference processes and strategies by id only (reference-only process slot; content/identity ids as the role-6a↔6b interface).
  • The v1 process vocabulary is a thin named layer over shipped primitives (R-metrics reduction, argmax/plateau/deflated selection, cross-instrument generalization, R-bootstrap Monte-Carlo) — no invented taxonomy.
  • P1 control constructs only: axes (bounded loops over declared finite sets), gates (predicate filters over declared metrics between stages), ladders (finite value ladder + stop predicate). No variables, no general recursion, no unbounded iteration.
  • Presentation in the campaign document is data-level only (which taps to persist, which metrics/comparison tables to emit).
  • Block ids are namespaced (node-type-id pattern); the vocabulary contract is extension-ready, but this cycle ships the compiled-in std set only.
  • Both document types ship the op-script-precedent introspection surface: enumerate the vocabulary, describe one block's typed slots, validate a partial document, list open slots (the Blockly litmus test made checkable).
  • New leaf crate as the code home for the artifact layer (document types, validation, introspection); CLI verbs wire it into aura.

Acceptance sketch: an LLM or human can author a process document and a campaign document as text, validate both headlessly with precise refusals, introspect the vocabularies and any partial document's open slots via the CLI, and obtain stable content ids for both — without any Rust compile and without any run being executed.

  • depends on: nothing (first cycle of the milestone)
  • context: #188 is the design anchor and decision log; the executor and the sugar/retirement path for the existing orchestration verbs (sweep/mc/walkforward/generalize) are later cycles, gated on the resolution comment's "once it carries" rule.
Define the two research-artifact document types from the #188 role-model design pass — the **process document** (role 5: a named, versionable validation/eval methodology) and the **campaign document** (role 6b: persisted experiment intent — data windows × strategy references × axes × process reference × data-level presentation) — as closed-vocabulary, typed, serialized data, with parsing, validation, the introspection contract, and content-addressing. **No executor in this cycle.** Design basis (all on #188): the issue body (role model, resolved forks 1–4), the addendum comments (introspection contract from day one; P1 control-flow tier: axes / gates / ladders), the fork-triage comment (decided items 1–8), and the resolution comment (user decisions A–C). Key constraints fixed there: - Canonical JSON with a `format_version` envelope; content id through the same hashing primitive blueprints use; documents stored content-addressed beside blueprints in the registry store pattern. - Campaign documents reference processes and strategies **by id only** (reference-only process slot; content/identity ids as the role-6a↔6b interface). - The v1 process vocabulary is a thin named layer over shipped primitives (R-metrics reduction, argmax/plateau/deflated selection, cross-instrument generalization, R-bootstrap Monte-Carlo) — no invented taxonomy. - P1 control constructs only: axes (bounded loops over declared finite sets), gates (predicate filters over declared metrics between stages), ladders (finite value ladder + stop predicate). No variables, no general recursion, no unbounded iteration. - Presentation in the campaign document is data-level only (which taps to persist, which metrics/comparison tables to emit). - Block ids are namespaced (node-type-id pattern); the vocabulary contract is extension-ready, but this cycle ships the compiled-in std set only. - Both document types ship the op-script-precedent introspection surface: enumerate the vocabulary, describe one block's typed slots, validate a partial document, list open slots (the Blockly litmus test made checkable). - New leaf crate as the code home for the artifact layer (document types, validation, introspection); CLI verbs wire it into `aura`. Acceptance sketch: an LLM or human can author a process document and a campaign document as text, validate both headlessly with precise refusals, introspect the vocabularies and any partial document's open slots via the CLI, and obtain stable content ids for both — without any Rust compile and without any run being executed. - depends on: nothing (first cycle of the milestone) - context: #188 is the design anchor and decision log; the executor and the sugar/retirement path for the existing orchestration verbs (`sweep`/`mc`/`walkforward`/`generalize`) are later cycles, gated on the resolution comment's "once it carries" rule.
Brummel added this to the Research artifacts — process & campaign documents milestone 2026-07-03 12:38:03 +02:00
Brummel added the feature label 2026-07-03 12:38:03 +02:00
Author
Owner

Design reconciliation (spec production, cycle 0106)

Spec: 0106 research-artifact vocabularies. The design basis is #188 (body, both addenda, fork-triage comment, resolution comment); the derived decisions below close the remaining spec-bearing forks. Each is a derived orchestrator decision with its rationale — none is a user decision unless quoted.

  • Fork: crate nameaura-research. Derived: it names the domain (the research loop's document layer — both artifact types serve it equally) without privileging one document type and without colliding with the C13 deploy-artifact vocabulary that "artifact" alone would evoke.
  • Fork: serde placement → the document types carry serde derives directly in aura-research. Derived: the serde-free convention exists to keep wire formats out of the sim core (engine Op vs CLI OpDoc, #162 precedent); a document-definition leaf crate IS the wire format's home, so a parallel DTO layer would duplicate every type for no boundary gain.
  • Fork: content-id primitive homeaura-research hosts the canonical-bytes SHA-256 helper as a library function; aura-cli's existing content_id delegates to it. Derived: the fork-triage comment fixed "same primitive" for all content ids; today that primitive lives in the binary (aura-cli), unreachable by a library crate — hosting it in the new leaf and delegating keeps exactly one implementation without inverting any dependency.
  • Fork: identity id for documents → content id only in this cycle; no identity-id analogue. Derived: the blueprint identity id blanks non-load-bearing debug names, but in these documents names and references ARE the semantics (a process is referenced, metrics are named), so no name-blind projection with a defined meaning exists yet; inventing one now would be speculative.
  • Fork: CLI surface → two role-addressed verb families, aura process … and aura campaign …, each with validate <file> and introspect mirroring the shipped graph introspect flag idiom (--vocabulary / --block <id> / --unwired <file> / --content-id <file>). Derived: #188 defines role recognizability as "a surface addressed to the role" (role 5 → process verbs, role 6b → campaign verbs), and reusing the one shipped introspection idiom keeps a single learnable contract across all three artifact classes.
  • Fork: validation tiers → two tiers: intrinsic (store-free — schema, vocabulary membership, typed slots, P1 constraints: finite non-empty axes, gate metrics from the declared set, ladders with a stop predicate) and referential (inside a project — strategy/process ids resolve against the content-addressed stores; campaign axes ⊆ the referenced strategy's param space). Derived: mirrors the shipped eager/holistic predicate split of the construction service (#157) and keeps documents validatable headless anywhere while making dangling references catchable where stores exist.
  • Fork: gate predicate form → structured data only: conjunctions of {metric, comparator, value} triples over the declared metric vocabulary with a closed comparator set; never a string expression. Derived: a string predicate is a mini-DSL hole that fails the ratified Blockly litmus test (a palette cannot type an opaque string), while structured triples are exactly typed slots.
  • Fork: process/campaign construct split → gates, ladders, and methodological counts (resamples, block length, walk-forward fold policy, selection rules) live in the process document; data and param spaces (instruments, windows, strategy references, param-value axes, base seed) live in the campaign document. Derived: this is the ratified role boundary itself — role 5 owns "how to judge", role 6b owns "what to span" — and it keeps a process reusable across campaigns with different data, which is the diagnosis's cure.
  • Fork: registry store → minimal content-addressed put/get for both document types beside the blueprint store (processes/<hash>.json, campaigns/<hash>.json) ships this cycle. Derived: the resolution comment fixed "stored content-addressed alongside blueprints (the existing store pattern)", and the referential validation tier is inert without it; the blueprint store is the shipped template.
  • Fork: v1 std stage set → four stage blocks wrapping shipped primitives only: sweep (grid evaluation + selection rule argmax / plateau:mean / plateau:worst, optional deflation annotation), monte_carlo (R-bootstrap: resamples, block length), walk_forward (fold policy + in-sample selection), generalize (cross-instrument worst-case floor); the declared-metric vocabulary is the scalar field names of the shipped metrics/selection types. Derived: the fork-triage comment fixed "wrap what exists — no invented taxonomy"; this is the complete inventory of shipped selection/validation machinery, nothing more.

Status: all spec-bearing forks closed; spec production for cycle 0106 proceeds on this basis.

## Design reconciliation (spec production, cycle 0106) Spec: 0106 research-artifact vocabularies. The design basis is #188 (body, both addenda, fork-triage comment, resolution comment); the derived decisions below close the remaining spec-bearing forks. Each is a derived orchestrator decision with its rationale — none is a user decision unless quoted. - **Fork: crate name** → `aura-research`. Derived: it names the domain (the research loop's document layer — both artifact types serve it equally) without privileging one document type and without colliding with the C13 deploy-artifact vocabulary that "artifact" alone would evoke. - **Fork: serde placement** → the document types carry serde derives directly in `aura-research`. Derived: the serde-free convention exists to keep wire formats out of the sim core (engine `Op` vs CLI `OpDoc`, #162 precedent); a document-definition leaf crate IS the wire format's home, so a parallel DTO layer would duplicate every type for no boundary gain. - **Fork: content-id primitive home** → `aura-research` hosts the canonical-bytes SHA-256 helper as a library function; `aura-cli`'s existing `content_id` delegates to it. Derived: the fork-triage comment fixed "same primitive" for all content ids; today that primitive lives in the binary (`aura-cli`), unreachable by a library crate — hosting it in the new leaf and delegating keeps exactly one implementation without inverting any dependency. - **Fork: identity id for documents** → content id only in this cycle; no identity-id analogue. Derived: the blueprint identity id blanks non-load-bearing debug names, but in these documents names and references ARE the semantics (a process is referenced, metrics are named), so no name-blind projection with a defined meaning exists yet; inventing one now would be speculative. - **Fork: CLI surface** → two role-addressed verb families, `aura process …` and `aura campaign …`, each with `validate <file>` and `introspect` mirroring the shipped `graph introspect` flag idiom (`--vocabulary` / `--block <id>` / `--unwired <file>` / `--content-id <file>`). Derived: #188 defines role recognizability as "a surface addressed to the role" (role 5 → process verbs, role 6b → campaign verbs), and reusing the one shipped introspection idiom keeps a single learnable contract across all three artifact classes. - **Fork: validation tiers** → two tiers: **intrinsic** (store-free — schema, vocabulary membership, typed slots, P1 constraints: finite non-empty axes, gate metrics from the declared set, ladders with a stop predicate) and **referential** (inside a project — strategy/process ids resolve against the content-addressed stores; campaign axes ⊆ the referenced strategy's param space). Derived: mirrors the shipped eager/holistic predicate split of the construction service (#157) and keeps documents validatable headless anywhere while making dangling references catchable where stores exist. - **Fork: gate predicate form** → structured data only: conjunctions of `{metric, comparator, value}` triples over the declared metric vocabulary with a closed comparator set; never a string expression. Derived: a string predicate is a mini-DSL hole that fails the ratified Blockly litmus test (a palette cannot type an opaque string), while structured triples are exactly typed slots. - **Fork: process/campaign construct split** → gates, ladders, and methodological counts (resamples, block length, walk-forward fold policy, selection rules) live in the process document; data and param spaces (instruments, windows, strategy references, param-value axes, base seed) live in the campaign document. Derived: this is the ratified role boundary itself — role 5 owns "how to judge", role 6b owns "what to span" — and it keeps a process reusable across campaigns with different data, which is the diagnosis's cure. - **Fork: registry store** → minimal content-addressed put/get for both document types beside the blueprint store (`processes/<hash>.json`, `campaigns/<hash>.json`) ships this cycle. Derived: the resolution comment fixed "stored content-addressed alongside blueprints (the existing store pattern)", and the referential validation tier is inert without it; the blueprint store is the shipped template. - **Fork: v1 std stage set** → four stage blocks wrapping shipped primitives only: `sweep` (grid evaluation + selection rule argmax / plateau:mean / plateau:worst, optional deflation annotation), `monte_carlo` (R-bootstrap: resamples, block length), `walk_forward` (fold policy + in-sample selection), `generalize` (cross-instrument worst-case floor); the declared-metric vocabulary is the scalar field names of the shipped metrics/selection types. Derived: the fork-triage comment fixed "wrap what exists — no invented taxonomy"; this is the complete inventory of shipped selection/validation machinery, nothing more. Status: all spec-bearing forks closed; spec production for cycle 0106 proceeds on this basis.
Author
Owner

Spec auto-signed (cycle 0106)

Spec 0106 (research-artifact vocabularies: process & campaign documents — parse, two-tier validation, introspection contract, content-addressing; no executor) was signed autonomously: the signature is a grounding-check PASS from a fresh-context reviewer — all eleven load-bearing assumptions about current codebase behaviour ratified by named, currently-green tests (shared content-id primitive + canonical golden, blueprint-store round-trip, exactly-one-of introspect guard, usage-2/runtime-1 exit split, Display-free-fault prose seam, typed Scalar bind cells, RMetrics/RunMetrics field pins, FamilySelection annotation round-trips, SelectionMode↔--select parity, Aura.toml walk-up discovery, blueprint_from_json + param_space). No human signed; the plan proceeds and a reply here vetoes.

## Spec auto-signed (cycle 0106) Spec 0106 (research-artifact vocabularies: process & campaign documents — parse, two-tier validation, introspection contract, content-addressing; no executor) was signed autonomously: the signature is a grounding-check PASS from a fresh-context reviewer — all eleven load-bearing assumptions about current codebase behaviour ratified by named, currently-green tests (shared content-id primitive + canonical golden, blueprint-store round-trip, exactly-one-of introspect guard, usage-2/runtime-1 exit split, Display-free-fault prose seam, typed Scalar bind cells, RMetrics/RunMetrics field pins, FamilySelection annotation round-trips, SelectionMode↔--select parity, Aura.toml walk-up discovery, blueprint_from_json + param_space). No human signed; the plan proceeds and a reply here vetoes.
Author
Owner

Axis representation corrected (user veto, 2026-07-03)

The spec's first draft carried per-value tagged Scalar cells in campaign axes ("fast": [{"I64": 8}, …]), derived from op-script bind parity. The user vetoed while the plan was being written: "Macht total Sinn, dass für einen klar typisierten Parameter 'fast' jede einzelne Value im JSON eine typisierte Scalar-Zelle benötigt, nicht wahr?! Das sollte man mal reviewen" (2026-07-03) — the kind is a property of the parameter, not of each value.

Resolution (spec amended before any implementation): an axis declares its ScalarKind once — {"kind": "I64", "values": [8, 12, 16]} — with bare JSON values parsed as the declared kind. A mixed-kind axis is thereby unrepresentable rather than merely refused (stronger than the draft, which needed an extra validation rule to forbid mixes), and canonical serialization normalizes value spelling (an F64 axis writes 8 as 8.0), keeping content ids stable across equivalent spellings. The bind-parity rationale was mis-applied: an op-script bind slot holds exactly one value, so there the per-cell tag is the only kind carrier; an axis is a homogeneous list. Binds stay tagged; axes carry the kind once. The referential tier's kind check becomes one comparison per axis (declared kind vs the param's ScalarKind) instead of per cell.

## Axis representation corrected (user veto, 2026-07-03) The spec's first draft carried per-value tagged Scalar cells in campaign axes (`"fast": [{"I64": 8}, …]`), derived from op-script bind parity. The user vetoed while the plan was being written: "Macht total Sinn, dass für einen klar typisierten Parameter 'fast' jede einzelne Value im JSON eine typisierte Scalar-Zelle benötigt, nicht wahr?! Das sollte man mal reviewen" (2026-07-03) — the kind is a property of the parameter, not of each value. Resolution (spec amended before any implementation): an axis declares its ScalarKind once — `{"kind": "I64", "values": [8, 12, 16]}` — with bare JSON values parsed as the declared kind. A mixed-kind axis is thereby unrepresentable rather than merely refused (stronger than the draft, which needed an extra validation rule to forbid mixes), and canonical serialization normalizes value spelling (an F64 axis writes 8 as 8.0), keeping content ids stable across equivalent spellings. The bind-parity rationale was mis-applied: an op-script bind slot holds exactly one value, so there the per-cell tag is the only kind carrier; an axis is a homogeneous list. Binds stay tagged; axes carry the kind once. The referential tier's kind check becomes one comparison per axis (declared kind vs the param's ScalarKind) instead of per cell.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#189