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:
@@ -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.
|
||||
Reference in New Issue
Block a user