Fix docs stale after Cut 1's teardown (PA.f15)

Cut 1 (d69e9d4) deleted the tick driver and the Active elaboration sweep, and
the ignored live smoke that exercised them. These passages still described
that machine as live:

- notes/local-live-smoke.md was a runbook for the deleted smoke and its
  command now runs zero tests. Trimmed to what is still true: connector and
  Claude SDK sidecar bring-up, which the seed lane still depends on. Fixed
  the references to its deleted sections in notes/fresh-workspace-handoff.md.
- docs/architecture/ghostlight-dungeon-mvp.md's Verification contract named
  the live smoke as the road's one proof point; it now says none exists until
  the play agent's own gate.
- notes/ghostlight-implementation-plan.md's Interruption section named
  ControllerHttpResult::Interrupted and run_cover_tick as live; both are
  deleted, and reporting an interruption to the play agent is Cut 8's.
- docs/architecture/ghostlight-stock-lenses.md gets one added sentence: the
  concurrent-elaboration claim holds as a library capability, and Dungeon
  runs none of it since Cut 1. The verdict is unchanged.
- notes/fresh-workspace-handoff.md's concurrent-elaboration and
  tick-driver lines now say what Dungeon actually runs today.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-22 02:27:59 +02:00
commit d8dce9db5e
5 changed files with 68 additions and 263 deletions

View file

@ -221,9 +221,11 @@ transports: the CodexConnector and, per `claude`-prefixed lane model, the
Node sidecar on the Claude Agent SDK. The Rust decoder is the one validator
on both; the sidecar hands arguments through unvalidated. The sidecar and
its receipt shape are a named stopgap, deleted whole when a Messages-API port
has budget. The SDK transport is proven on the road: seeded runs on
`claude-sonnet-5` committed ticks end to end (`notes/local-live-smoke.md`,
"SDK runs, 2026-09-10"). A kernel refusal continues the authoring
has budget. The SDK transport was proven on the road before the play agent's
Cut 1 (`d69e9d4`) deleted the tick driver those runs exercised: seeded runs on
`claude-sonnet-5` committed ticks end to end (evidence ledger; the runbook
that recorded them, `notes/local-live-smoke.md`, no longer carries that
narrative). A kernel refusal continues the authoring
conversation (`Refusal` rows, `controller_work.v16`); the Interpreter cites
prose by quote (`source_quote`), and a quote not in the prose is a gap. Plan
step 12 is landed: `PersonaMaterial` is the thirteenth component, a promise
@ -306,8 +308,10 @@ follow-ups are listed in
stock lens set, is implemented (`835ea4d..872ba35`; cut map
`docs/architecture/ghostlight-stock-lenses-cut.md`): lens weights are world
data the owner replaces with `SetLensWeights`, each elaborator session records
the lens it drew and that lens's instruction text, and elaboration sessions run
concurrently under the caller's ceiling.
the lens it drew and that lens's instruction text, and the library runs a
caller's elaboration sessions concurrently under that caller's own ceiling.
Dungeon runs no Active elaboration since the play agent's Cut 1 (`d69e9d4`)
deleted its sweep and ceiling; nothing in Dungeon calls this path today.
Also owed on the way, found 2026-09-15 by reading source:
@ -317,7 +321,9 @@ Also owed on the way, found 2026-09-15 by reading source:
- Active elaboration runs with `NullEvidenceSource` (`controllers.rs`), so no
Vault reaches it. This is L2's subject and is deferred with L2; the play
path stops elaborating while Active.
- Ticks run cells in sequence at 15–50 s each; a reply takes minutes.
- Dungeon runs no tick driver since the play agent's Cut 1 (`d69e9d4`)
deleted it; when cells ran, they ran in sequence at 15–50 s each. Cut 8
owns Persona dispatch going forward.
The eight titles ship as the library's stock lens set. Their 2026-09 removal
had no operator decision; the correction record in `state/evidence.jsonl`
@ -388,7 +394,8 @@ acceptance roots, and local run scaffolding.
- Consumer contract: `docs/architecture/ghostlight-world-consumer-api.md`
- Frozen teardown map: `notes/ghostlight-current-system-map.md`
- Current implementation plan: `notes/ghostlight-implementation-plan.md`
- Local live smoke runbook: `notes/local-live-smoke.md`
- Connector and Claude SDK sidecar bring-up (no live smoke exists):
`notes/local-live-smoke.md`
- Human-readable state: `state/map.yaml`
- Distilled evidence: `state/evidence.jsonl` (full history in
`state/evidence.archive.jsonl`)

View file

@ -408,10 +408,12 @@ defined by the digest, so a neighbour's act, a clock tick that rolls a
routine's `due`, an elaborator patch, a consumer document, and a world-scale
event are one case, indistinguishable at the handler. Schema bumps:
`controller_work.v11` and `ghostlight.persona_turn_receipt.v3`; prior rows
are refused, not migrated. Eve reports the interruption through
`ControllerHttpResult::Interrupted`, which renders as `denied` in the
command result today; the receipt text carries the subject, both scope
digests, the persona prose and receipt digest, and the untranslatable gap.
are refused, not migrated. The kernel's interruption still carries the
subject, both scope digests, the persona prose and receipt digest, and the
untranslatable gap; the play agent's Cut 1 (`d69e9d4`) deleted the owner's
dispatch surface and `ControllerHttpResult::Interrupted` with it, so nothing
in Dungeon reports an interruption today. Reporting a re-lowered turn to the
play agent's own turn record is Cut 8's.
Cut line held: no new kernel arm, bundle, or joint command; no second Persona
turn; no event log reaches a controller; the delta shown to the Interpreter
@ -424,10 +426,12 @@ What is undone: no road run has exercised the re-lowering against a live
provider; none exists yet. Closed since landing: fork D's branch was dead by
construction (grants are insert-only, so a fresh opportunity always carries
speech) and is deleted; transfer, route-closing, and grant-revocation causes
are proven anonymous by Soul; a `run_cover_tick` end-to-end carries an
interruption through a real tick and shows the overtaken turn committing
nothing; a witness landing mid-turn yields the anonymous knowledge line and
no overheard row. Still open: the elaborator-patch cause is proven only by
are proven anonymous by Soul; an end-to-end test carried an interruption
through a real tick via `run_cover_tick` and showed the overtaken turn
committing nothing, before the play agent's Cut 1 (`d69e9d4`) deleted
`run_cover_tick` and the tick driver it drove; a witness landing mid-turn
yields the anonymous knowledge line and no overheard row. Still open: the
elaborator-patch cause is proven only by
the shared code path, not by a fixture that drives the elaborator past its
answer gate; and whether Eve's command-result vocabulary needs a fourth
state for an overtaken turn is the Eve owner's question.

View file

@ -1,12 +1,17 @@
# Local Live Smoke
# Connector And Claude SDK Sidecar Bring-Up
The one place the road is tested: the seed lane, the production tick driver,
elaboration sweep, and clock against a real CodexConnector on a created
world, for a configured number of seed sessions and ticks. Everything else
proves the machine under fixture inference ports. The harness is the ignored
test
`runtime::tests::live_smoke_seeds_then_ticks_a_world_against_the_connector`;
its log is the deliverable.
No live smoke exists in this tree. The ignored test this file once documented,
`runtime::tests::live_smoke_seeds_then_ticks_a_world_against_the_connector`,
ran the production tick driver and the Active elaboration sweep against a real
CodexConnector; the play agent's Cut 1 (`d69e9d4`) deleted both, and the test
with them. A command that names it now matches nothing and exits 0. No
replacement exists until the play agent's own gate (`ghostlight-play-agent.md`)
lands one.
What remains true and stays here: bringing up a real CodexConnector and a
built Claude SDK sidecar. The seed lane (`world.seed`) still runs real
inference through `ControllerRunner`, and both transports below are how a
session gets real model responses instead of a fixture inference port.
## Substrate
@ -17,13 +22,12 @@ Machine-local, outside the repo: `F:\Projects\Ghostlight-smoke\`.
- `connector\ghostlight.key`: 64 hex characters, no trailing newline; the
shared connection secret. Both sides read the same file.
- `connector\connector.cc`: the daemon's single-caller config.
- `logs\`: connector stdout/stderr and pid, smoke logs.
- `logs\`: connector stdout/stderr and pid.
The connector binary is `F:\Projects\CodexConnector\target\debug\codex-connector.exe`
built from the repo head with the `daemon` feature. Ghostlight's `Cargo.lock`
pins the connector library at an older revision whose daemon does not build
against its own lockfile; the head daemon speaks the same wire law, proven by
the handshake in the run below.
against its own lockfile; the head daemon speaks the same wire law.
## Bring-up
@ -42,117 +46,18 @@ $R='F:\Projects\Ghostlight-smoke'; $p = Start-Process -FilePath 'F:\Projects\Cod
Stop it with `Stop-Process -Id (Get-Content F:\Projects\Ghostlight-smoke\logs\connector.pid)`.
## Run
```bash
export GHOSTLIGHT_CONTROLLER_CONNECTOR=127.0.0.1:4103 \
GHOSTLIGHT_CONTROLLER_CREDENTIAL='F:\Projects\Ghostlight-smoke\connector\ghostlight.key' \
GHOSTLIGHT_ACCEPTANCE_RUNTIME_ID=ghostlight-smoke \
GHOSTLIGHT_CONTROLLER_PROJECTOR_MODEL=gpt-5.6-luna \
GHOSTLIGHT_CONTROLLER_PERSONA_MODEL=gpt-5.6-terra \
GHOSTLIGHT_CONTROLLER_INTERPRETER_MODEL=gpt-5.6-terra \
GHOSTLIGHT_CONTROLLER_OPERATIONAL_MODEL=gpt-5.6-terra \
GHOSTLIGHT_CONTROLLER_ELABORATOR_MODEL=gpt-5.6-terra \
GHOSTLIGHT_SMOKE_TICKS=3 \
GHOSTLIGHT_SMOKE_LOG='F:\Projects\Ghostlight-smoke\logs\smoke-ticks.log' \
GHOSTLIGHT_SEED_VAULT_ROOT='F:\Projects\Kalsa\Kalsa' \
GHOSTLIGHT_SMOKE_VAULT_SCOPE='Public' \
GHOSTLIGHT_SMOKE_SEED_SESSIONS=4 \
GHOSTLIGHT_SMOKE_SEED_TARGET=6 \
GHOSTLIGHT_SMOKE_SEED_ROOT_LABEL='Low Sere' \
GHOSTLIGHT_SMOKE_SEED_BRIEF='A dry basin town that owes its water to the gate above it.'
cargo test -p ghostlight-dungeon --bin ghostlight-dungeon live_smoke_seeds_then_ticks -- --ignored --nocapture
```
`GHOSTLIGHT_SEED_VAULT_ROOT` is required; the runner refuses to seed with it
unset. `GHOSTLIGHT_SMOKE_VAULT_SCOPE` and `GHOSTLIGHT_SMOKE_SEED_BRIEF` are
optional; the brief is the world's brief, set at creation and projected to
every lane as guidance, and the world is titled by the seed root label unless
`GHOSTLIGHT_SMOKE_WORLD_TITLE` names it. The scope is a directory under the root; Kalsa's spoiler split is
that scope, so a world that must not see `Spoilers` is seeded from `Public`.
The root label must name a place the Vault knows; Low Sere has a Public note. The caller runtime id must equal the one the
connector config admits.
## First run, 2026-09-05, before the seed lane
Genesis: Active, three subjects (Operator, Persona, Operational Agent) in
`commons`, three opportunities, no boundaries, no deficit rows (no scale
intent at genesis).
| Tick | Wall time | Cells | Revision | Persona speech |
|---|---|---|---|---|
| 1 | 71 s | 2 singletons | 2 → 5 | "I am here." |
| 2 | 41 s | 2 singletons | 5 → 8 | "I am here. Time 60." |
| 3 | 44 s | 2 singletons | 8 → 11 | "Is anyone there?" |
Each tick committed one narrative command, one operational command, and one
clock advance; the elaboration sweep returned clean every tick because the
world derives nothing to answer. The store's final digest is in the log.
What this proves: the connector handshake, the Persona membrane end to end
(projector, persona, interpreter), the operational lane, the cover, the tick
driver, the clock, and the elaboration sweep all work on the road. What it
does not prove: anything about a world with structure. The prose is thin
because the world is three subjects in one room with one affordance; that is
the seed-producer gap, not a cognition fault.
The older ignored test `real_codex_connector_cognition_modes_commit_speech`
in `world/controllers.rs` predates pass 6 and declares its subjects unplaced,
so it fails at `NoAudience` before reaching the provider; retire or place it.
## Seeded run, 2026-09-05
Kalsa `Public` scope, root Low Sere, target six persons, brief "A dry basin
town that owes its water to the gate above it."
| Stage | Wall time | Result |
|---|---|---|
| Seed session 1 | 39 s | one round, committed: six persons in Low Sere, all qualified, deficit 6 → 0; session 2 skipped, no shortfall left |
| Activate | | nine subjects, nine opportunities, six boundaries for the elaborator |
| Tick 1 | 95 s | 8 singleton cells, revision 3 → 7, Bren Ash: "I'm here." |
| Tick 2 | 95 s | 8 singleton cells, revision 7 → 11, Mara Dene: "Bren?" |
| Tick 3 | 123 s | 8 singleton cells, revision 11 → 15, Tovin Rusk: "Bren?", the Persona asking for a beginning |
Twelve runs were needed to get here. Every failure was on the road, not in
the kernel, and each became a rule the tree now carries:
- The copied Codex credential diverged from the live session and its refresh
token was invalidated; the connector's Codex home is now the operator's
real `~/.codex`, one credential family.
- Strict function schemas refuse `oneOf` and a `const` without a `type`; the
emitter uses `anyOf` and types every tag, and a test walks every tool of
both authoring lanes against the strict rules offline.
- `gpt-5.6-sol` is not available to a ChatGPT account; the Persona runs on
`gpt-5.6-terra` here.
- A seed generation exceeded the five-minute socket read; the connector's
expiry skew stays at five minutes while the response read timeout is
fifteen.
- The model referenced existing things by label; the brief prints every
canonical id beside its label.
- One tool call per response spent the six-round budget; the seed lane has
its own budget of 24, requests parallel tool calls, and submits the draft
as authored when the budget ends instead of discarding it.
- A repair round re-used the first attempt's provider request id and the
connector refused it as a replay conflict; request ids are content-addressed.
- Obligations carried a period; the tool description states the commitment
shape rule the resolver enforces.
- The first landed seed put all six people in the commons; the brief states
that a subject must stand at the row's root or inside it to count.
The harness fails when no seed patch lands, so a run that reaches the
provider and authors nothing is a failed run. Silence is not failure: a
person given a place, a debt, and a clock and nothing else says nothing, and
since run 6 the prompts render that honestly instead of borrowing a voice.
A session that wants the connector reads
`GHOSTLIGHT_CONTROLLER_CONNECTOR=127.0.0.1:4103` and
`GHOSTLIGHT_CONTROLLER_CREDENTIAL='F:\Projects\Ghostlight-smoke\connector\ghostlight.key'`,
the same variables the deleted harness read.
## Claude SDK route
Run; see "SDK runs, 2026-09-10" below. `world/sdk_inference.rs`'s `SdkInferencePort` gives the same
ignored smoke a second transport: a lane whose configured model is
`claude`-prefixed (matching `GHOSTLIGHT_SDK_MODEL_PREFIX`, default `claude`)
routes to a Node sidecar instead of the CodexConnector, so the road can run
on the Claude subscription with no Codex budget. `LiveController` and
`ControllerRunner::open` (through `open_inference`) already carry this
optional binding; only the operator side and a real run are outstanding.
`world/sdk_inference.rs`'s `SdkInferencePort` gives any lane whose configured
model is `claude`-prefixed (matching `GHOSTLIGHT_SDK_MODEL_PREFIX`, default
`claude`) a second transport: a Node sidecar on the Claude Agent SDK instead of
the CodexConnector, so a session can run on the Claude subscription with no
Codex budget.
**Operator prerequisites, none of which Ghostlight performs:**
@ -182,120 +87,9 @@ GHOSTLIGHT_SDK_MODEL_PREFIX=claude # optional; this is already the default
```
`GHOSTLIGHT_SDK_SIDECAR`'s absence means no SDK binding at all — a
`claude`-prefixed lane model then fails at open with `UnroutableModel`
rather than silently reaching the connector. Any of the five
`claude`-prefixed lane model then fails at open with `UnroutableModel` rather
than silently reaching the connector. Any of the five
`GHOSTLIGHT_CONTROLLER_*_MODEL` variables can be set to a `claude`-prefixed
model (for example `claude-opus-5`) to route that lane through the sidecar;
the connector variables (`GHOSTLIGHT_CONTROLLER_CONNECTOR`,
`GHOSTLIGHT_CONTROLLER_CREDENTIAL`) are only required for the lanes that
still route to the connector, and an all-`claude` configuration needs
neither.
The harness is the same ignored test,
`runtime::tests::live_smoke_seeds_then_ticks_a_world_against_the_connector`;
its `#[ignore]` reason names both prerequisites this route adds: "requires a
vault plus either a running CodexConnector or a built Claude SDK sidecar
with an ambient Claude Code login; see `GHOSTLIGHT_SMOKE_*` and
`GHOSTLIGHT_SDK_*` environment."
### SDK runs, 2026-09-10
Every lane on `claude-sonnet-5`, Kalsa `Public`, Low Sere, target six, two
seed sessions, three ticks. The operator installed the CLI and logged in
interactively; the sidecar inherited the login. No connector variables were
set.
| Run | Seed | Ticks | Result |
|---|---|---|---|
| 1 | both sessions refused: subjects with no grant, twelve commitments due at or before the clock | 3 committed, 2 cells each, Persona spoke | harness failed on the empty seed; the transport itself worked end to end |
| 2 | one session, one round, 89 s: six qualified persons, deficit 6 to 0 | 456 s, 395 s, 326 s; 8 singleton cells each; revision 3 to 24 | passed; tick 3 quarantined one cell |
| 3 | one session, one round, 109 s: six persons and an institution, deficit 6 to 0 | two ticks, 230 s and 138 s; 9 singleton cells each; revision 3 to 15 | passed; no quarantine; speech cited by quote arrives whole |
| 4 | one round, 87 s | two ticks, 219 s and 235 s; 8 cells | passed; Projector now carries the subject's own life; five people say "Fourteen days", the due on their obligation |
| 5 | one round | two ticks, 316 s and 251 s; 9 cells; whole membrane traced (`GHOSTLIGHT_SMOKE_TRACE`) | passed; first exchange: Sera Venn "Maro first, then the rest.", Maro Seln "First for what, Sera?"; every voice was the model's |
| 6 | one round, 90 s | two ticks, 299 s and 235 s; 9 cells; flat prompts | passed; eighteen cells, nobody spoke; the honest baseline of an unauthored person |
| 7 | refused: six distinct people with memories, reads, and worded promises, every `declare_subject` carrying `"controller": {}` | 2 ticks on genesis alone | harness failed on the empty seed; the repair continuation faulted on the SDK lane (one user turn) |
| 8 | one round, 97 s: six people, each with a voice, values, memories, reads, and a promise in words | two ticks, 191 s and 261 s; 8 cells; 43 speak captures to 9 gaps | passed; seven distinct lines about the grate, the roll, and the crew |
| 9 | one round, 94 s; world titled Low Sere with its brief on every lane | two ticks, 218 s and 209 s; 8 cells; 20 speak captures to 24 gaps | passed; no fixture name anywhere in the trace; promises and speech in the world's own terms (the grate, the ration boards, the kiln on stored ash) |
| 10 | one round, 95 s | two ticks, 220 s and 166 s; 8 cells; revision 3 to 15; 29 speak, 18 display, 10 gaps | passed; the first displays ("I set the spindle down where both of them can see the face of it", "I look to Yeshe, not unkind."); every gap is private reasoning; the first live interrupted cell (below) |
| 11 | one round, 100 s | two ticks, 241 s and 221 s; 8 cells; revision 3 to 16; 27 speak, 24 display, 14 gaps | passed; three interrupted cells, each printed as its own line with the subject and both digests; the operator feed shows displays beside speech ("So, [seen: I shift the spindle from one hand to the other, then back]") |
| 12 | round 1 rejected after 200 s (the seed model wrote `kind` where the controller schema says `type`, omitted the `over` tag, and narrated it as tool bugs); round 2 committed in 99 s: six people and an institution | two ticks, 288 s and 150 s; 9 cells; revision 3 to 16; 39 speak, 6 display, 10 gaps | passed; every cited span landed, no overlap gaps; two interrupted cells in tick 1; a two-sentence act arrives as one display ("I stand near the wall where the shade still holds... I watch the dust settle where their boots have been.") |
Rules run 1 imposed are in the implementation plan under step 11 (descriptions
carried through the sidecar, `due` described and the clock printed, the grant
rule on the subject tool, raw tool calls logged, refusal continues the
conversation). Run 2's two findings: three of eight speech captures were cut
mid-word ("just t", "a?\" I") because the Interpreter cited byte spans the
model counted wrong, and the tick-3 quarantine was a mis-spanned utterance
failing the canonical-text rule at invocation, which is a translation gap
wearing an infrastructure fault's coat. Run 3, after speech and gaps moved to
`source_quote`, shows every utterance whole and no quarantine. Ticks are slow
because singleton cells run in sequence at roughly 15 to 50 s per cell on this
lane.
Runs 4 to 6 read the membrane itself. Set `GHOSTLIGHT_SMOKE_TRACE` to a file
and every request is appended with its purpose, model, instructions, input
turns, tool catalog, and output, so a cell can be read end to end: Projector
in and out, Persona in and out, Interpreter in and out. Run 5's trace showed
the machine working as designed (the Interpreter captured only quoted speech
and recorded honest gaps for posture, private priority, and provisional
belief) and two faults of context, not of prose: a `Commitment` carries no
statement of what is promised, so `due: 1000` was read as a thousand owed;
and the ontology's `PersonaMaterial` (values, voice, memories, reads) is
named in the doc and built nowhere, so every person spoke in the model's one
voice. Run 6, after the prompts were flattened to render only what the
context carries, is silent, which is correct. Run 6's trace also shows the
Projector saying "no one before me" for two people in the same house: the
context carries the subject's own place and not who else stands in it.
Run 10 is plan step 14 on the road: a visible act is captured by `display`
and lands as a seen row on the room. Sera set the spindle down where Maro and
Behn could see it, and Maro's re-lowered turn read it as seen and her "Not
finished yet." as said. The ten gaps are what the cut leaves private on
purpose ("There's nothing to tell them until the spindle's finished telling
me."). Run 11 showed the one fault the runs 10 and 11 shared: "So," was
captured whole and the rest of the sentence dropped, and a turn with four
visible acts kept one, because the fold allowed one span per kind and made
the rest ambiguity gaps. The Interpreter was citing correctly; the fold was
discarding. The fold now takes every span cited for a kind, in prose order,
as one utterance and one display, and only an overlapping span is an
ambiguity (`controller_work.v15`; run 12 below).
Runs 7 and 8 are plan step 12 on the road. Run 7 authored the best seed so
far and lost it to a field with no description and a tool result that said
only "recorded as a gap"; the controller variant now describes its shapes,
a decode failure's reason goes back to the model, and the SDK lowering
carries a later user turn (the refusal) in its transcript. Run 8 is the
first run whose people are people: Maro "Sera. Where's the crew.", Sera "Not
yet, Bren. I haven't given Maro the condition of the intake, and until I do,
I won't say send them down.", Iva keeping the roll of names before anyone
goes below. Speech captures went from one per tick to twenty-one, and gaps
from most of the prose to nine. One promise in run 8 read "I promise Maro
Seln I will mend the tick fixture by the appointed hour, though Maro Seln
holds no authority to command my compliance and no forum will hear a suit":
the world was still titled "Cover Tick Fixture" and the brief's boundary
language leaked into a vow. Run 9, after `world_create.v3` gave the world
its title and brief, has no fixture name in its trace and its promises read
"I want every one of the forty-one hearths accounted for on the ration
boards, with no favorites".
## Interrupted cell
Exercised live in runs 10 and 11. A subject whose room changed mid-turn gets
one re-lowering, not a lost turn: in run 10 Maro Seln's turn was bound, Sera
Venn then spoke and set the spindle down in the same room, and the runner
re-lowered Maro's prose once with the section "What was said or done before
this person since" carrying her line as said and her act as seen. Run 11
printed the line this section asked for, once per re-lowered cell, after the
tick line:
```text
interrupted cell subject=Sera Venn bound=sha256:8ac0… renewed=sha256:2c71…
```
The pair of digests is read from the committed turn's own receipt
(`NarrativeDecision::re_lowering`, the `interrupted_from` binding and the one
that replaced it), the cover driver carries it on the tick summary
(`CoverSummary.interrupted`) and logs it per cell, and the harness prints it
from the summary. Three cells re-lowered in run 11, three lines printed,
three `Interrupted:` sections in the trace, and each act appears once in the
operator feed.
the connector variables are only required for lanes that still route to the
connector, and an all-`claude` configuration needs neither.