CB-WP-0011: stage 1 first slice — chaos rolls L down to S
Some checks failed
ci / check (push) Has been cancelled

Provenance (tier S, structural L, chaos d4=4 -> S). First fire of the
chaos mechanism in six declarations. The structural trigger was L
(stage 1 creates a rendering port); the roll overrode it to S, which
has no ADR. Rather than lawyer the hard 'no code before ADR' gate in
either direction, the declaration is split: this packet takes the part
of stage 1 that creates no port and adds no dependency, and the port
half keeps its own declaration and its own roll.

AM-4a supports that ordering independently -- 3,750 lines of headroom
against a 250,000 target means any toolkit choice needs the survey the
roll just deleted.

Finding acted on: cb-play's render() drops ~a third of GroundView,
including the whole DARVO and GROUND-practice state.
This commit is contained in:
tegwick 2026-08-02 02:33:39 +02:00
parent cdc42afbb6
commit c3a850c6fc

View file

@ -0,0 +1,166 @@
---
id: CB-WP-0011
kind: product
title: "Stage 1, first slice: an inspector that shows everything"
status: todo
---
# Purpose
Tier **S** — and this is the **first time the chaos roll has changed
anything** in six declarations.
```
structural tier L (INTENT stage 1 creates a new capability port)
chaos d4 = 4 → override
override roll shuf -e S M L → S
declared tier S (structural L, chaos 4 → S)
```
Declaration 6 of 12 in the calibration window. The `CHAOS` gate in
`gates.toml` has `caught = []` and a `review_by` of 2026-09-30; this pass
is the first entry it can earn, whichever way the outcome falls.
## What tier S is allowed to mean here
A rolled-down tier relaxes *process weight*. It does not relax the hard
gate — **no implementation code for a capability exists before its ADR is
committed** — because that gate is stated unconditionally and the tier
table governs only "weight of steps 13", not whether step 3 happens.
The two rules meet head-on: stage 1's headline deliverable is a rendering
port (`cb-render-api` / `-null` / `-wgpu`, ArchitectureBlueprint §Port
pattern), a port needs an ADR, and tier S has no ADR.
**Resolution: split the declaration rather than lawyer either rule.**
This packet is the part of stage 1 that creates no port, adds no
dependency, and therefore trips no ADR gate. The GUI half gets its own
tier declaration and its own chaos roll later, informed by what this pass
learns. Two facts make that ordering the right one anyway:
- **AM-4a has 3,750 lines of headroom** (246,250 of 250,000 measured by
`make dep-weight`). Any 2D toolkit is a five- to six-figure line count.
The dependency decision needs a survey, and the roll just deleted the
survey — so the honest move is to not make the decision this pass.
- The second-use rule cuts the same way. A renderer that has never had to
show the whole of `GroundView` does not yet know what a view needs.
## The finding this packet acts on
`tools/cb-play/src/table.rs:113` already has
`render(view: &GroundView) -> String`. It is stage 1's renderer, written
in stage 0 to prompt a human, and **it drops roughly a third of what the
projection carries**:
| in `GroundView` | in `render` |
|---|---|
| `mode`, `focus`, `solution_discard` | absent |
| `ground_modes`, `ground_choices` | absent |
| `support_responses`, `darvo_targets` | absent |
| `protection`, `freedom_gate_lifted` | absent |
| `protected_this_round` on a Problem | absent |
| `personal`, `coalitions`, `mastery` on the outcome | absent |
Nothing is wrong: it was written to show a human their legal moves, and
it does. But "inspectable" is the word INTENT uses for stage 1, and an
inspector that silently omits the DARVO state machine and the GROUND
practice — the two mechanics this game exists to model — is not one.
The interesting part is that **no test could have caught this**, because
every assertion a renderer test naturally makes is satisfied by any
render. That is the harness-does-nothing class again, in its presentation
form.
## Task: the inspector shows everything, and a gate says so
```task
id: CB-WP-0011-T01
status: todo
priority: high
```
Extend `render` to cover every field of `GroundView`, and — the load-
bearing half — add the check that keeps it covering them.
**The check.** Serialize the view to `serde_json::Value`, walk it for
every object key reachable in a populated state, and require each key to
be classified in exactly one of two lists in the test:
- `RENDERED` — the inspector shows it, asserted against a state where the
field holds a distinctive value that appears in the output;
- `OMITTED` — with a stated reason per entry (e.g. `hand_size`, which is
redundant when `hand` is shown to its owner).
A new field on `GroundView` that is in neither list **fails the test**.
That is the same shape as `not_control_gates` in `gates.toml`, for the
same reason: silence must cost something.
**Vacuity controls (M-D1-MUT).** The test must go red for a stated reason
when (a) a field is deleted from the render, (b) a field is moved from
`RENDERED` to `OMITTED` while still being rendered, and (c) the walk is
made to return an empty key set — the EXPECT-VACUOUS control, since a
coverage test over zero keys passes trivially and that is precisely how
this check would rot.
Build the fixture from a **mid-DARVO, mid-GROUND** state, not a fresh
deal: most of the missing fields are empty at deal time, and a coverage
test run against a state where the fields are absent is the same lie in a
different costume.
## Task: `cb-play --inspect` walks a recorded game
```task
id: CB-WP-0011-T02
status: todo
priority: high
```
Stage 1 asks for a *debug inspector*. The inspector above renders one
state; this makes it walk a game.
Deliver `cb-play --inspect <bundle-or-scenario> [--as SEAT|spectator]`:
replay the recorded commands and print the full table after each step,
from the chosen viewpoint. A `.cbreplay` bundle and a scenario YAML are
both accepted — both already reconstruct a command sequence.
This is the first thing in the project that answers *"what did the table
look like when it went wrong?"* without adding a `dbg!` and re-running.
It costs no dependency: replay, projection and render all exist.
**Acceptance.** Inspecting a recorded game must reproduce the end-state
hash the bundle records — an inspector that shows a state the replay did
not reach is worse than none. Assert the hash, and mutate the replay to
prove the assertion fires.
**Projection is not optional here.** `--as 2` must show P3's hand and
must not show anyone else's. The stage-0 test that checked this was
vacuous twice before it held (CB-EV-0007); seat the assertion where the
hidden thing is actually hidden.
## Task: evidence, and what the chaos roll cost
```task
id: CB-WP-0011-T03
status: todo
priority: medium
```
Write `evidence/CB-EV-0009-inspectable-table.md` covering:
1. **Did tier S produce a worse outcome than tier L would have?** The
only honest way to answer is to name what the deleted survey would
have decided and check whether this pass needed it. State the answer
even if it is "no, and that is one data point against the tier table",
because that is the finding the calibration window is for.
2. The field-coverage gap as measured before and after T01.
3. Cost and session shape for the pass, per `make status`. The previous
pass opened at a **HARD** session-shape breach (338,852 mean context
against a 300,000 ceiling) and a **45%** trailing-3 meta share against
a soft 25%. This pass is `product`; report where both land.
4. Update `gates.toml`: `CHAOS` gets its first `caught` entry — the roll
fired, and what it changed.
**Do not update the ADR or INTENT.** Stage 1 is not shipped when this
lands; the port half is untouched and INTENT's stage-1 line stays open.
Marking a stage complete because part of it works is the failure mode
stage 0 avoided by leaving the CLI player open for three passes.