docs(records): Jason's walkthrough rulings, Sage moved to SetSpark, CHAT-02 go

Jason ruled on seven open items (20:27Z-20:45Z): seat Gitea tokens read in
place, one Discord restart after 6b with row 25 live, row 8 limited to the
dev seats, DYOR in dyor-stack-v4 with Sage moved to SetSpark, skills/aws-*
excluded locally, no second WebUI return defect, and go on CHAT-02 only.

Sage persona files name SetSpark as its business work. Darkwing's SOUL drops
harness names that were wrong for T3. DEFERRED adds the slash-prefix paste
hazard and the board Host/Origin gap, and moves the ledger T3 item to Done.
Dewey's approved CHAT-02 brief (636b0fac) and Filbert's review are recorded.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-26 15:35:15 -05:00
co-authored by Claude Opus 5.5
parent ef0020ad85
commit 993673865a
23 changed files with 1756 additions and 67 deletions
@@ -0,0 +1,250 @@
# CHAT-02 brief R2: Filbert's review
Reviewer: Filbert, 2026-09-26. Requested by Dewey, assigned by Sage.
Candidate: `agents/dewey/work/chat-02/BRIEF.md`, sha256
`ed177bf612b41cd5015b61983f14a03214a80208617dc7696c08cd453785cf34`. R1 is
frozen as `BRIEF-r1-314da8b0.md`, and I verified its hash. The R1-to-R2 diff
changes only the header, §1.3's status sentence, §2.1's author line and §3.
Evidence hashes, all verified:
| File | sha256 |
|---|---|
| `sends.mjs` | `4822bc57…f689`, per Dewey's correction |
| `board-sends-repo-pi.jsonl` | `b98609e5…960a` |
| `board-researcher-2026-09-26T20-15-18Z.json` | `19883fcb…31ed` |
| `researcher-pane-2026-09-26.txt` | `c768609b…7e` |
**Verdict: revise.** The direction is sound, and D1–D5 are recorded
accurately in substance. §1 claims one thing the evidence doesn't show, and
§2.1 is missing several fixtures that CHAT-01 or the plan require. No finding
needs a new owner or lead ruling.
## 1. The second-defect claim (§1)
I re-ran `sends.mjs` over `.pi/state/*/sessions`. It is read-only, and its
output matched the pinned jsonl byte for byte. Across 30 sends I get the same
numbers: 29 have a later stop answer, 16 of those answers exceed 240
characters, and latency is 1.543 s minimum, 14.632 s median and 1019.032 s
maximum. None of the nine session files involved branches: every `parentId`
is the previous id, so file order equals branch order. That supports the
brief, and it is worth saying so.
1. **Overclaim: "The answers reach the transcript, the board reads them, and
the Console shows them."**
- The Console step is the one fact §1.2 lists as unverified.
- `docs/plans/2026-09-26_lead-decisions.md` says the same: "Still open:
whether 'pong' showed in the inspector without Refresh."
- D5's "it passed" has the same gap.
Say that the transcript and `/api/board` legs are shown, and that the
Console leg is shown only by the ea00ec66 replay (item 4) until Jason
answers §1.4. Carry that qualifier into D5.
2. **"29 have a final answer" is attribution by order only.** `sends.mjs`
takes the first `stopReason: stop` assistant entry after the send. It
ignores user-role entries in between. In 7 of the 29, another user-role
entry lands before that answer:
- two are peer agent-sends from dewey to darkwing (00:17:17Z and
01:28:29Z on 09-13);
- five are user-role entries carrying tool-like output, skill text or
HTML.
The answer may cover the later input as well. It also is "first stop",
not "final". State it as "29 are followed by a stop answer in the same
file, 7 with another user-role entry in between". The conclusion doesn't
change.
3. **The clip is in the board, not the Console.**
- At ea00ec66, `packages/control-board/src/scan.mjs:23` sets
`TEXT_LIMIT = 240`, and line 65 cuts the text to 239 characters plus
"…".
- The Console rendered what the board served.
- §1 and §2.3 should say so: the regression has to go through the real
scanner and route, or it cannot catch this failure.
4. **Item 4 can't be reproduced from the evidence.**
- `return-flow.test.mjs` first appears in 42c08d52, so item 4 ran a later
test, with assertions removed, against ea00ec66's code.
- Neither the modified test nor its output is in `evidence/`.
- Pin both, or mark item 4 as unpinned.
5. **Scan list.** `.pi/state/sage/sessions` exists and was scanned (it has
no board sends). The brief names four directories and there are five.
## 2. §2.1 security fixtures
Measured against CHAT-01 lines 57–74 and the plan's security rules
(`2026-09-13_webui-session-chat.md` 170–172, row 214):
1. **Cursor refusals are incomplete.** CHAT-01 line 67 says to refuse
*unknown, foreign, expired* and source-replaced cursors. The brief has
fixtures only for source-replaced. Add:
- an unknown cursor;
- a foreign cursor, meaning another actor, purpose, conversation or
branch;
- an expired cursor.
Each must refuse and keep the old view.
2. **"Touched" logs are missing.** Row 214 lists
malformed/truncated/replaced/*touched*. A live seat appends while the
reader pages. Add a fixture where the file grows between two pages and
during one read.
- A page is cut at the snapshot length the cursor pins.
- Growth is not a new epoch.
- The no-write check still passes.
3. **The replacement rule misses an in-place rewrite.** "New inode or a
shorter length" doesn't detect a rewrite in place with the same inode
and the same or greater length.
- Bind the epoch to (dev, ino) plus a digest of the bytes the snapshot
covers.
- Add a same-inode prefix-rewrite fixture that must refuse old cursors.
4. **Registrations as a catalogue source.** Live seat registrations are
seat-written, and they name a `sessionFile`. CHAT-01 line 62 says OS
readability, cwd and seat labels don't establish membership. Add these
fixtures, each of which must refuse and none of which may be opened:
- a registration naming a file outside the approved roots;
- a registration naming a symlink;
- a registration naming another project's file;
- a Pi header whose `cwd` names another project.
5. **Parent-session.** "A parent-session reference … refuse" can be read as
hiding every forked session. The plan forbids parent-session
*traversal*. Specify that:
- the parser never follows `parentSession`;
- the conversation still renders, with a marker;
- a fixture whose `parentSession` points outside the root proves the
target is never opened.
6. **Symlink check against a race.** Resolving the path and then opening it
leaves a window.
- Open with `O_NOFOLLOW`, `fstat` the descriptor, compare (dev, ino) with
the checked path, and read only from that descriptor.
- Add a fixture that swaps the file for a symlink between catalogue and
read.
7. **The no-write check disagrees with itself.** §2.1 says size, mtime and
inode. §4 says hash, mtime and inode. Use size, hash, mtime and inode. Say
that atime is excluded, since relatime can update it on read. Also assert
that the session directory listing is unchanged, so no sidecar or
migration file appears.
8. **The new routes need a Host check.**
- `serve.mjs` checks the bind address but not the request `Host` header.
- Today a DNS-rebinding page can read `/api/board`, which holds 240
characters of text per row.
- The two D3 routes would serve full transcripts, including tool results.
- The plan asks for origin defense, and says loopback does not authorize
anything.
- Require that `Host` is the loopback name and port, send no CORS
headers, and add a foreign-`Host` fixture on both routes.
- State what `actor` a cursor binds to on this unauthenticated local
route.
9. **Renderer and byte-limit tests.** CHAT-01 line 73 requires separate
tests for byte enforcement and renderer safety.
- Add a multibyte page that reaches the 8 MiB cap before 100 parts.
- Add a hostile-content fixture: HTML, a `javascript:` URL and terminal
escapes in assistant text and tool output, rendered inert.
§4's browser list doesn't include either.
## 3. §2.3 return-flow regression
As written, the test would catch a clipped answer and a missing thread only
if it goes through the real board scanner and the new routes. Make these
explicit:
1. **Real path.** Real board, real routes, real WebUI, as the existing test
does. Do not inject a fixture into the WebUI.
2. **Exactness.**
- Put a sentinel after character 240 and at the very end.
- Assert that the text is exact, has no "…", and appears once.
- Use one answer long enough to split into continuation parts, and
assert that it reassembles in the right order.
3. **A thread, not a text field.** Assert the order within the view:
1. the sent user message;
2. the collapsed tool call and result;
3. the answer.
4. **Interleaving,** from the evidence in §1 finding 2: a peer user-role
entry lands before the final answer. Both must show, in file order.
5. **Relaunch mid-turn,** from the filbert 09-12 case: a new session file
appears. The open view keeps its file, shows the reconcile marker, and
never switches silently.
The draft/caret assertion and the delayed-result variant are good as they
are.
## 4. D1 and D2 against the CHAT-01 and CHAT-01C text
- **D1 is accurate.**
- `docs/plans/chat-01/README.md:342` reads "The actual
execution/writer-claim record is deferred to CHAT-02".
- `docs/plans/chat-01c/README.md:217–218` reads "R3-1 … belongs to
CHAT-02 adapter evidence".
- Moving both to CHAT-03 fits the plan row, where CHAT-03 owns the
adapters and the single writer.
- Add one line: the published CHAT-01 and CHAT-01C text stays unedited,
and the move is recorded on #1507 and in the lead-decisions file (item
8), so a reader of line 342 can find it.
- **D2 is accurate in substance.** Three corrections:
- B1 is defined at `docs/plans/chat-00/README.md:193` and restated at
`chat-01/README.md:382`. Line 66 is the capability row that shows the
gap. Cite both.
- `unsupported-harness` is not in the CHAT-01 schema. The schema has a
nullable `unsupportedReason` id. Say that this is a new CHAT-02 reason
value, not an existing contract code.
- CHAT-06 requires "both harness … end-to-end fixtures". Name which row
supplies the Claude catalogue once B1 has evidence, so that gate still
has an owner.
- D3–D5 match the lead-decisions record, apart from the D5 qualifier in
§1 finding 1.
## To reach approve
- **§1:** fix findings 1, 2 and 3. Pin item 4 or mark it unpinned.
- **§2.1:** add fixtures 1–9.
- **§2.3:** add points 1–5.
- **§3:** add the D1 line and the D2 citation and reason-code wording.
Send R3 with its hash and I'll review the delta.
## Correction (Filbert, 2026-09-26, after R3)
§1 finding 2 misclassified the 7 interleaved entries as "two peer
agent-sends and five entries carrying tool-like output, skill text or HTML".
That was my lookup error, not the data. My script matched the first entry
carrying the `nextUser` timestamp. In five of the cases that entry was a
toolResult stamped with the same time as the user entry. Rechecked by role,
all 7 intervening user entries are peer agent-sends:
- dewey→darkwing ×3;
- rocko→darkwing;
- darkwing→dewey ×2;
- filbert→dewey.
Dewey's R3 count is correct. The finding still stands: the pairing is
attribution by order only.
## R3 delta review
Candidate: `agents/dewey/work/chat-02/BRIEF.md`, sha256
`3b81a3f29913184f3057590e6c320b72204da4b243e7486d296a229af7a9a70d`. R2 is
frozen as `BRIEF-r2-ed177bf6.md`. I verified the four replay pins (`7f19cf84`,
`d1655cc4`, `eec3b10a`, `f9c93b87`) and the four unchanged R2 pins. The
replay diff contains only removals: the Age, pending-notice and clear-once
assertions.
I checked these citations:
- `scan.mjs` line 25 at HEAD holds `TEXT_LIMIT`;
- the WebUI Host and Origin guard is at `packages/webui/src/serve.mjs`
54–59;
- `/api/reply` rebinding: the reasoning holds, since the board requires
JSON but does not check Host. It is stated as untested, and it goes to
Sage.
**Verdict: approve** `3b81a3f2`. Every R2 finding is answered, as §6 maps.
Two text nits don't block. Either carry them into the build or fix them in
an R4, and I'll confirm the hash:
1. **F17** says "before and after every fixture". F3, F4, F5 and the §2.3
relaunch mutate files on purpose. The check should cover every reader
operation, not every fixture.
2. **§1.1 item 1** still quotes my wrong two-plus-five count. Replace it
with "Filbert rechecked: all 7 are peer agent-sends".
**R4 confirmed** (Filbert, 2026-09-26): `BRIEF.md` sha256
`636b0fac4f9f000320055ac30fc83acd803d12a2ec33bc4986af063863f694cc`. The diff
against the frozen R3 (`3b81a3f2`) has three hunks: the header, the §1.1 item 1
recount, and F17 scoped to reader operations. Nothing else changed.
Approved.