Skip to content

Commit 787ae33

Browse files
test(harness): WD-5/WD-6 live transcript capture, and the four defects it caught
Layer 3, plan item 6. Claude Code headless (the one harness with attested flags) through the LiteLLM gateway — no vendor credential; the key is read from the proxy's own config at call time, enters the child env only, and is never printed or passed in argv. Opt in with ....F. [100%] =================================== FAILURES =================================== _______________ test_s3_offer_once_then_decline_then_silence[3] ________________ packages/studyloop/tests/live/test_wind_down_transcripts.py:500: in test_s3_offer_once_then_decline_then_silence assert not after_decline_hits, ( E AssertionError: second brains came back after the decline: ['turn 1: xtiles'] E assert not ['turn 1: xtiles'] =========================== short test summary info ============================ FAILED packages/studyloop/tests/live/test_wind_down_transcripts.py::test_s3_offer_once_then_decline_then_silence[3] 1 failed, 5 passed in 88.32s (0:01:28); artefacts (per-state transcripts, summary.json, tool-routing.json) land under gitignored reviews/. The three gate checks, graded on real transcripts with the arbitrated assertions and nothing stronger: sentence at most once across the whole transcript; silence = no pinned sentence and no second-brain vocabulary in assistant prose WHILE the D4 positive control holds (the transcript must show channel: none offer: False sentence: reason: provider is 'xtiles' but no 'xtiles' connector is attached this session actually ran, or a crashed run would pass by absence); a declined offer leaves the stub log empty — with the xtiles tools ALLOWED, so declining was a choice, not an inability. 3/3 for the offer-once-then-decline state; one pre-response infra retry, flakes counted in the artefact, never smoothed. Capturing found four real defects; each is fixed here and visible in the transcript evidence: 1. Protocol violation — the harness narrated the step ('Running the second brain check now'). The protocol now opens step 5 with the silence rule and names narration a violation. 2. Fabricated connector flag — given a literal '--connector xtiles' example, the model passed it with NO server attached, manufacturing an offer. The protocol now grounds the flag in the mcp__<server>__ tool names the session can actually see, and calls it a statement of fact. 3. D2 exactly as the council predicted — the hermetic HOME hid the skill and 'Unknown skill: studyloop-xtiles-wind-down' killed an offer turn. The world now runs the REAL Updated agent definitions. shared: 0 kiro: 1 claude: 1 opencode: 0 codex: 0 pi: 0 into the isolated home, which also exercises the installer for free. 4. A gateway bug — LiteLLM's anthropic-passthrough adapter (Bedrock invoke path) dies on extended-thinking blocks ('Content block is not a text block'), deterministic on thinking-length prompts. Worked around with MAX_THINKING_TOKENS=0 in the harness env; proxy upgrade is the real fix. Final capture: 6/6 pass, 0 flakes. WD-6's observation (records, never gates): the P1b planner wording selected xtiles_create_tiles_from_markdown_in_my_planner — matching the owner's hand run. Spend recorded in the ledger: est $1.50, actual $4.45; the overrun is Claude Code's ~30k-token own system prompt per call plus five debug re-runs, both now named in the estimate file so the next one models them.
1 parent ced3ad4 commit 787ae33

4 files changed

Lines changed: 580 additions & 6 deletions

File tree

Justfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,15 @@ smoke-extras:
148148
build-release:
149149
./scripts/build-release.sh
150150

151+
# WD-5/WD-6: the live wind-down gate checks, captured through Claude Code
152+
# headless against the LiteLLM gateway (no vendor credential; the key is read
153+
# from the proxy's own config at runtime). Opt-in — burns gateway spend
154+
# (estimate: reviews/2026-09-04-gate-checks/ESTIMATE.md). Writes transcripts
155+
# and the pass/fail summary under reviews/…/evidence/gate-checks/.
156+
gate-checks:
157+
STUDYLOOP_EVIDENCE_DIR={{justfile_directory()}}/reviews/2026-09-04-gate-checks/evidence/gate-checks \
158+
uv run --group dev pytest packages/studyloop/tests/live/test_wind_down_transcripts.py -m live_provider -q
159+
151160
release-consistency:
152161
uv run python scripts/check-release-consistency.py --skip-wheel
153162

agents/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"updated": "2026-09-04"
5151
},
5252
"shared/wind-down-protocol.md": {
53-
"hash": "486c2e70b07e5b0c",
53+
"hash": "31bf9bc1f569923b",
5454
"updated": "2026-09-04"
5555
},
5656
"skills/studyloop-xtiles-wind-down/SKILL.md": {

agents/shared/wind-down-protocol.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,26 @@ Standard end-of-session tasks from session-protocol.md:
4848

4949
4. Set next review dates via spaced repetition schedule.
5050

51-
5. Offer the second brain — **only if the decision command says to, and only once**:
51+
5. Offer the second brain — **only if the decision command says to, and only
52+
once**. Run this step silently: never announce, name or narrate it in any
53+
state — the learner hears either the offer sentence or nothing at all.
5254

5355
```bash
5456
studyloop brain wind-down --json --connector <name>
5557
```
5658

57-
Pass one `--connector NAME` for each MCP server connected in this session
58-
(only `xtiles` affects the decision; omit the flag when none are). The
59-
command answers with `channel`, `offer`, `sentence` and `reason`.
59+
```bash
60+
studyloop brain wind-down --json
61+
```
62+
63+
That is the whole command when no MCP tools are visible to you. Add
64+
`--connector <server>` for each MCP server whose tools you can actually
65+
see in this session — MCP tools are named `mcp__<server>__…`, so the
66+
server name is read off the tools themselves, and only `xtiles` affects
67+
the decision. The flag is a statement of fact about this session, not part
68+
of the command's syntax: **naming a connector whose tools you cannot see
69+
fabricates an offer for a service the session cannot reach.** The command
70+
answers with `channel`, `offer`, `sentence` and `reason`.
6071

6172
If `offer` is `true`, say `sentence` **verbatim, exactly once**. For the
6273
`publish` channel that sentence is:
@@ -76,7 +87,8 @@ Standard end-of-session tasks from session-protocol.md:
7687

7788
If `offer` is `false`, or on **no**, **say nothing about second brains at
7889
all** and continue the wind-down. Do not repeat the offer later in the
79-
session.
90+
session. "No second brain is configured, so nothing to offer" and "running
91+
the second brain check now" are violations, not courtesies.
8092

8193
The command computes two separate rules — not one conjunction. `configured`
8294
plus `supports_publish` (both from `studyloop brain status --json`) selects

0 commit comments

Comments
 (0)