core/docs/decisions/ADR-0112-runnable-expert-demo-showcase.md
Shay bd7005c786 feat: ADR-0112 runnable expert-demo showcase (core demo expert --domain <id>)
Closes the asymmetry between the `expert-demo` ledger status (audit
artifact only) and the actual `core demo` surface (runnable
walkthroughs producing HTML + JSON). Until this commit the word
"demo" in `expert-demo` was aspirational; now it corresponds to
something a reader can open.

What it does

- Reads the signed expert_demo_claims entry from docs/reviewers.yaml
- Loads latest on-disk result files for each attached lane × split
- Re-derives the evidence-bundle digest and asserts byte-for-byte
  match against the signed claim_digest — this is the load-bearing
  audit step, now exercised at two independent enforcement points
  (ledger gate + showcase)
- Runs each lane's metrics through the ADR-0109 lane-shape registry
  and surfaces the verdict
- Picks the first three cases from each split verbatim (deterministic
  by file order) and renders them as HTML for inspection
- Emits expert_demo.json (canonical bytes, deterministic) + expert_demo.html

Surface

  core demo expert --domain mathematics_logic
  core demo expert --domain physics
  # → evals/expert_demos/<domain>/latest/expert_demo.{json,html}

Read-only by construction: cannot mutate docs/reviewers.yaml or any
lane result file. Tested. Unpromoted domains raise ValueError —
no silent fallback, no "preview" mode that fakes a showcase.

Generated artifacts are gitignored — the inputs they derive from are
already committed, so duplicating the renders would just churn the
tree.

Tests: 16 new cases pinning all five ADR-0112 invariants. Smoke suite
still 67/67 green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 14:59:27 -07:00

216 lines
7.6 KiB
Markdown

# ADR-0112 — Runnable Expert-Demo Showcase
**Status:** Accepted
**Date:** 2026-05-22
**Author:** CORE agents + reviewers
**Depends on:** ADR-0091, ADR-0092, ADR-0098, ADR-0099, ADR-0106, ADR-0109, ADR-0110, ADR-0111
---
## Context
ADR-0106 introduced the `expert-demo` ledger status as a contract-gated
promotion above `reasoning-capable`. ADR-0110 and ADR-0111 promoted
`mathematics_logic` and `physics` respectively under that contract.
The status name carries the word "demo." Until this ADR, the artifact
backing a promotion was a signed evidence-bundle digest in
`docs/reviewers.yaml` plus a set of on-disk lane result files —
*audit evidence*, not a runnable demonstration. An external reader
clone-and-run could verify the digest but had no per-domain HTML
artifact to open and see what the domain actually produces.
The asymmetry was real. `core demo audit-tour`,
`core demo register-tour`, `core demo learning-loop`,
`core demo showcase` all emit inspectable JSON + HTML walkthroughs.
The `expert-demo` *status* had no equivalent surface. The name implied
a demonstration that did not exist.
ADR-0112 closes the gap.
---
## Decision
Add a new demo target: `core demo expert --domain <id>`.
For a domain whose ledger row carries `expert_demo=true`, the composer
produces a per-domain runnable showcase:
1. Reads the signed `expert_demo_claims` entry from
`docs/reviewers.yaml`.
2. Loads the latest on-disk result file for each attached lane on
both `public` and `holdout` splits.
3. Re-derives the evidence-bundle digest from those files and asserts
byte-for-byte equality with the signed `claim_digest`. This is the
load-bearing audit step.
4. Runs each lane's metrics through the ADR-0109 lane-shape registry
and surfaces the shape-check verdict.
5. Picks the first N cases (N = 3) from each split's `cases` array
verbatim — same bytes the digest already covers, rendered for
inspection.
6. Emits `expert_demo.json` (canonical-serialized, byte-deterministic
via `core.demos.contract.canonical_json`) and `expert_demo.html`
(presentation-only) under
`evals/expert_demos/<domain>/latest/` by default.
The composer does **not** re-run the lanes. The lane result files are
the artifact the digest covers; replaying them would not strengthen
the claim and would introduce non-determinism (timestamp churn,
ordering). The "watch CORE answer X" experience is achieved by
surfacing the already-shipped case records — `surface`, `passed`,
`grounding_source`, `trace_hash` — directly from disk.
The composer is **read-only**. It writes only to its `output_dir`;
it does not mutate `docs/reviewers.yaml`, any lane result file, or
any pack manifest.
An unpromoted domain (no signed claim) raises `ValueError` with a
message naming the missing claim. The CLI surfaces a non-zero exit.
---
## Surface
```
core demo expert --domain mathematics_logic
core demo expert --domain physics
# default output dir: evals/expert_demos/<domain>/latest/
# override: core demo expert --domain physics --output-dir <path>
```
Output structure:
```
evals/expert_demos/<domain>/latest/
expert_demo.json # canonical bytes; same on-disk inputs → same SHA
expert_demo.html # presentation surface; opens in a browser
```
JSON shape (excerpt):
```text
{
"expert_demo_version": 1,
"claim_contract_version": 1,
"domain_id": "physics",
"claim": {
"signed_by": "shay-j",
"evidence_revision": "adr-0111:reviewed:2026-05-22",
"evidence_lanes": ["foundational_physics_ood", "inference_closure", "fabrication_control"],
"claim_digest": "a104cad1..."
},
"digest_verification": {
"signed": "a104cad1...",
"derived": "a104cad1...",
"matches": true
},
"lanes": [
{
"lane_id": "foundational_physics_ood",
"shape": "accuracy_shape",
"splits": {
"public": { "metrics": {...}, "shape_check": {...}, "case_count": 117, "sample_cases": [...] },
"holdout": { "metrics": {...}, "shape_check": {...}, "case_count": 39, "sample_cases": [...] }
}
},
...
],
"all_lanes_pass": true,
"all_digests_match": true,
"all_claims_supported": true
}
```
---
## Invariants
### `adr_0112_promoted_domain_renders`
`build_expert_demo(domain_id)` for every domain whose ledger row
carries `expert_demo=true` returns a payload with
`all_claims_supported=True`. Tested by
`tests/test_expert_demo_runnable.py::TestPromotedDomainsBuildSuccessfully`.
### `adr_0112_digest_recompute_byte_equal`
The recomputed digest equals the signed `claim_digest`. This is the
load-bearing audit invariant: if any byte of any attached lane result
file changes, the digest changes and the showcase declares
`all_claims_supported=False`. Tested in the same module.
### `adr_0112_unpromoted_domain_refused`
A domain without a signed claim raises `ValueError`. There is no
silent fallback, no "preview" mode that would emit an unsigned
showcase.
### `adr_0112_byte_determinism`
Two consecutive `run_expert_demo` calls with identical on-disk inputs
produce byte-identical `expert_demo.json`. Tested by SHA-256 of the
output bytes.
### `adr_0112_read_only`
`run_expert_demo` does not mutate `docs/reviewers.yaml` or any
`evals/<lane>/results/v1_*.json` file. Tested by capturing the bytes
of the source files before and after a run.
---
## Acceptance evidence
Accepted when:
- `core/demos/expert_demo.py` exists with `build_expert_demo`,
`run_expert_demo`, and `render_html` exported
- `core demo expert --domain <id>` works for `mathematics_logic` and
`physics`; both produce `all_claims_supported=True` and digest match
- `tests/test_expert_demo_runnable.py` pins the five invariants
- README + docs/decisions/README.md updated to point readers at the
new runnable surface
---
## Consequences
- The word "demo" in `expert-demo` now corresponds to something a
reader can open. The name is no longer aspirational.
- Each future expert-demo promotion automatically gains a runnable
surface — no per-domain composer work required. Adding a new
promoted domain (e.g. `systems_software`) needs only its signed
claim and on-disk lane results; the showcase composer handles the
rest by following the lane-shape registry.
- The digest-recompute step is now exercised in two places: the
ledger gate (`evaluate_expert_demo` at report time) and the
runnable showcase (every time a reader runs it). Same load-bearing
invariant, two independent enforcement points.
- An `expert_demo.html` is now a stable artifact a third party can
ask for. Future PRs that touch any of the three attached lane
result files for a promoted domain will, by definition, change
that domain's showcase output — `expert_demo.json` SHA stability is
a useful signal that the promotion claim still reproduces.
---
## Out of scope
- This ADR does not change the digest-derivation algorithm
(`derive_evidence_digest`), the lane-shape registry (ADR-0109),
or the contract gate (ADR-0106). The showcase is *consumer of*
those contracts, not an amendment.
- This ADR does not commit the per-domain `expert_demo.{json,html}`
artifacts to the repo. They are generated on demand. A future
ADR may pin selected showcases under `evals/expert_demos/<domain>/`
the way ADR-0099 pinned `evals/public_demo/results/latest/`; that
is a separate decision involving review of the artifact churn
cost.
- This ADR does not introduce live re-running of lane runners under
the showcase. The lane result files are authoritative; the showcase
is a renderer.
- Sample-case selection is the deterministic first-N. Replacing this
with a stratified or quoted-claim sample (e.g. include one case
per construction class) would be a future amendment.