core/docs/decisions/ADR-0098-demo-composition-contract.md
Shay 10457bec69 docs(adr): propose ADRs 0092-0099 — scale-up slate through public showcase
Eight load-bearing ADRs closing the loop from contemplation Phase 5 through
a public showcase demo. Each one is small and evidence-bearing; together
they sequence the next arc without duplicating existing substrate.

- 0092 Reviewer Registry v1 — populates docs/reviewers.yaml schema;
  unblocks all reasoning-capable claims under ADR-0091.
- 0093 Domain Pack Contract v1 Implementation — wires ADR-0091's five
  follow-up items (parser, dry-run validator, chain registry, eval lane
  refs, reviewer resolution) so manifest fields actually gate status.
- 0094 Proposal Source Provenance — sealed ProposalSource type widening
  proposal schemas ahead of 0095.
- 0095 Miner-Sourced Teaching Proposals — closes the contemplation
  loop: articulation_quality / contradiction_detection / frontier_compare
  miners emit PackMutationProposal candidates routed through the single
  reviewed teaching path; identity-pack defense at construction, not
  review; replay-equivalence pre-gate.
- 0096 Fabrication-Control Eval Lane — first negative-control measure;
  three case classes (phantom endpoint, cross-pack non-bridge, sibling
  collapse) with frozen thresholds (fabrication_rate ≤ 0.01).
- 0097 Mathematics-Logic Reasoning-Capable Ratification — first
  domain claim under ADR-0091; chain corpus + eval lanes already
  exist, this is the formal contract ratification.
- 0098 Demo Composition Contract — DemoCommand protocol so demos can
  be composed without reimplementation; deterministic JSON, no global
  state mutation, declared output paths only.
- 0099 Public Showcase Demo — composes four scenes (determinism /
  honest unknown / reviewed learning / multi-hop+trace) under 30s;
  pure composition enforced by grep gate; JSON byte-equality CI-pinned.

Landing order: 0092 → 0094 → 0095 → 0093 → 0096 → 0097 → 0098 → 0099.

Deliberately not included: curriculum compiler, formation course
runner, calculator operators, response-mode taxonomy expansion,
learning-scale 10k harness. Each is deferred with a documented reason.
2026-05-21 17:34:09 -07:00

152 lines
4.6 KiB
Markdown

# ADR-0098 — Demo Composition Contract
**Status:** Proposed
**Date:** 2026-05-21
**Author:** CORE agents + reviewers
---
## Context
CORE has shipped a growing set of operator-facing demos:
- `core demo audit-tour` (ADR-0042)
- `core demo anti-regression` (ADR-0055)
- `core demo learning-loop` (ADR-0056)
- `core demo register-tour` (ADR-0072)
- `core demo anchor-lens-tour` (ADR-0073d)
- `core demo orthogonality-tour` (ADR-0074)
- `core bench --suite teaching-loop` (ADR-0057)
Each one is correct in isolation. Each one stands as its own evidence
of a specific invariant. The problem the next ADR (ADR-0099 public
showcase) faces is that there is no shared contract that lets one
demo safely embed another.
Without a contract, the showcase has two bad options:
1. Reimplement portions of each demo inline (drift, duplication,
doctrine violation).
2. Subprocess-spawn each demo and parse stdout (fragile, breaks the
trace-hash discipline).
The right answer is a small protocol that the existing demos retrofit
to, and that the showcase consumes.
---
## Decision
Introduce `DemoCommand` as a typed protocol. Existing demos are
retrofitted to it in the same PR (mechanical, small). Future demos
implement it from the start.
### Protocol
```python
class DemoCommand(Protocol):
demo_id: str # stable identifier, kebab-case
claim_contract_version: int # currently 1
def run(self, *, output_dir: Path, seed: int | None = None) -> DemoResult: ...
@dataclass(frozen=True, slots=True)
class DemoResult:
demo_id: str
claims: tuple[Claim, ...]
evidence: Mapping[str, str] # claim_id -> evidence locator (path or sha)
all_claims_supported: bool
json_path: Path
trace_features: Mapping[str, str] # canonical, for showcase composition
@dataclass(frozen=True, slots=True)
class Claim:
claim_id: str
statement: str
supported: bool
evidence_locator: str
```
### Rules
1. **Deterministic JSON.** Two runs with the same inputs and seed
produce byte-identical `json_path` contents. HTML may differ
in formatting; JSON is the truth-path.
2. **No global state mutation.** A demo's `run()` may not mutate
process-global registries (runtime singletons, telemetry sinks
attached at module load, environment variables outside its own
scope). Demos that need a telemetry sink attach a local one and
detach it before returning.
3. **Declared output paths only.** A demo writes only under
`output_dir`. Path traversal rejected via `safe_pack_id`-class
sanitization.
4. **Composability is read-only.** A composing demo (the showcase)
may read another demo's `DemoResult` but never mutates it.
### Retrofit scope
Each shipped demo gains a thin adapter in
`core/commands/demo_<name>.py` that conforms to `DemoCommand`. The
adapter does not change demo behavior; it wraps the existing entry
point and produces a `DemoResult`.
### What this ADR does not do
- Does not change demo behavior.
- Does not change demo CLI surface. `core demo audit-tour` runs the
same way; the protocol is internal.
- Does not introduce a registry. Demos remain discoverable via the
existing CLI subparser.
---
## Invariant
`demo_composition_no_side_effects` — a grep gate on the showcase's
import graph refuses any symbol that mutates runtime singletons or
attaches telemetry sinks at module load. The protocol contract is
enforced by structure, not by hope.
`demo_json_byte_equality` — for each demo retrofitted under this ADR,
running it twice with identical inputs produces byte-identical JSON.
CI lane verifies.
---
## Lane
`evals/demo_composition/` (new):
- positive: each retrofitted demo runs twice → identical JSON
- negative: a deliberately stateful test fixture → composition
detector rejects it
- composition: showcase reads two demo results → produces composite
claim set without mutating either
---
## Trust Boundary
Demos write only to operator-specified `output_dir`. Path traversal
rejection inherits from ADR-0051. No dynamic imports. No network. No
shell.
---
## Consequences
- ADR-0099 public showcase becomes mechanically possible without
reimplementing demo logic.
- Future demos cost less: implement the protocol once, gain
composability for free.
- The shipped demos gain a small adapter layer but no behavioral
change.
---
## PR Checklist
- Capability added: composition protocol for demos.
- Invariants proved: `demo_composition_no_side_effects`, `demo_json_byte_equality`.
- Lane proving it: `evals/demo_composition/`.
- Hidden normalization / stochastic fallback / approximate recall / unreviewed mutation: none.
- Trust boundary: demos write only under declared output paths; no global state mutation.