Task files, the files they copy in (byte-identical to the reference on m3a-ref), each area's check record, and a README with the per-task table of what each check exposed. The handoff note is done with. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
9.2 KiB
M3a checks, area E: the broker (tasks 10 to 15) and end to end (task 22)
What each task's given tests were checked against before hand-over, and what doing so exposed.
Branch m3a-ref-e (worktree ~/src/boxmaker-ref-e), built on the merge of areas A to D
(f9195ec). Every task here had a full reference implementation, as the plan decided.
What ran
| Task | Check | Tests | First run against the reference |
|---|---|---|---|
| 10 runner | reference | runner 8, doctests 2 (9 in brokerd with task 07's 7) |
all passed |
| 11 approvals | reference | approvals 7 |
all passed |
| 12 ledger | reference | ledger 11, ledger_answer 9 |
all passed |
| 13 broker | reference | broker 9, broker_pending 5, broker_sequence 2 |
all passed after two test-side compile fixes |
| 14 admin | reference | admin 12 |
all passed |
| 15 serve | reference, through the binary | serve 9 |
all passed |
| 22 end to end | reference (the real brokerd binary) |
end_to_end 1 |
passed |
17 BrokerPort::call (area C's skeleton) |
a reference body, as a measurement; not handed over | broker_port 15, broker_port_bad 2 |
all 17 passed first time |
Nothing only compiled. With the BrokerPort body written, make gate passes in full on this
branch, the end-to-end line included.
Runs. Every area E suite, and broker_port, broker_port_bad and end_to_end, ten times in a
row idle and ten times under sixteen busy loops on eight cores: 20 of 20 green, no flakes. The
timing bounds in area C's broker_port (250 to 1,100 ms for a 300 ms timeout; 550 to 1,700 ms for
a pending call nobody answers) held under that load.
Task order. For each of tasks 10 to 15, the reference tree was cut back to what the
implementer will have at that task (later modules empty, main.rs the stub) and that task's tests
and all earlier ones were compiled. Each compiled. This found one plan defect (below).
Mutation check. Fourteen deliberate defects, one at a time; each broke at least one given
test: no stop after a failed append; state not raised by the result's label; no last look before
running; a gone requester not taking its own entry; the re-decision ignoring the current state;
shell mounts read-only; expiry at > instead of >=; a found socket directory left at 0755;
RunSpec fields public (the compile_fail doctest); grant problems printed on every call; state
checked before grants; a refusal recorded without the owner's reason; result content passed on
when its record fails; the pending frame sent with final: true.
Spec defects and gaps (not applied to the spec; proposed wording)
- Section 5, write order: denials before
decideare recorded too. Section 3 says "the first two need noDecision-like guard: anyone may deny", which reads as ifgrants_invalidandstate_unreadableskip the record. The reference records every tool request, those included. Proposed: "Every tool request gets aDecisionrecord, including one denied withgrants_invalidorstate_unreadablebeforedecideruns. A message of a forbidden kind is not a tool request and gets none." - Section 5, records: the state of a session whose state cannot be read.
Decision,Approvaland a failedResultcarrytaint/untrusted(ortaint_after), and the spec does not say what they hold when the file is damaged. Chosen:secretandtrue. Proposed: "When the session's state cannot be read, records carrytaint: secretanduntrusted: true:brokerddoes not know how sensitive the session is." - Section 5, step 3: a result whose state cannot be read or written leaves no
Result. The answer isfailed, "the result could not be recorded", and nothing more is written, sobxctl audit verifylists the call as running or unfinished. Proposed, appended to step 3: "Nothing is written for it, so the log shows the call as unfinished; the state entry of the runbook explains that." - Section 6, approve: the re-decision's mode.
approve_result.outcomeand theApprovalrecord sayaskorallowed, butredecidereturns aDecision, which does not carry the mode. The ledger looks the matched grant up in the set it passed. It works; a cleaner fix for M3b is forredecideto return the mode with the decision. Proposed: "The outcome isaskif the grant matched now is anaskgrant,allowedif it isauto." - Section 6, refuse: a refusal whose record cannot be written. The table says
ok {}. The call is denied either way, butbxctlwould report success for something that was not recorded. Chosen:error internal, detail "the refusal could not be recorded; the call is denied; see docs/runbook.md#audit-unavailable" (bxctl refuseprints it and exits 1). Proposed: "If theApprovalrecord of a refusal cannot be written, the answer iserror internalwith a pointer toaudit-unavailable; the call is denied withaudit_unavailable." - Section 6, lost connection: the pending frame itself cannot be sent. Chosen: the thread
tries to take its own entry at once, exactly as when its one-second look finds
loopdgone. Proposed: add "The same holds if the pending frame cannot be sent." - Section 6: the request frame has no read timeout. A client that connects and sends nothing
holds a thread for ever. Only
loopdcan reachbroker.sockand only the owneradmin.sock, so it is not fixed in M3a. Worth a line in section 14, or a timeout in M3b. - Section 12, end to end: the recorded model calls
read_filedirectly, not throughcall_tool(thetool_callrecording).loopdforwards both the same way, so the test proves the same thing. Proposed: "The scripted model callsread_filewith no grant". - Section 2, "Threads and locks": where the expiry lives. Expiry answers entries the same way
approvedoes, so it isadmin::expire_due, called byserve's thread;approvalsstays a plain table (it comes before the ledger in task order).
Plan defects found by the checks
- The test rig broke task order. The first
support/rig.rsheld both the ledger rig and the broker client, so task 12's tests would not have compiled before task 13'sbrokermodule existed. Found by the task-order simulation above; the client moved tosupport/client.rs, which only task 13's and 14's tests include. files/Makefilecould not serve both task 21 and task 22. With the end-to-end line in it, task 21's gate would fail on a test target that does not exist yet. Task 21 now copiesfiles/Makefile-task21(area D's version, byte for byte);files/Makefileis task 22's. The parent should confirm this, since task 21 is area D's.- The editing tool decoded a backslash-u escape again, this time in a test comment
(
admin.rs). The escaped string itself is built from pieces and checked at run time (escaped.contains("u002f")); the comment was rewritten without an escape. Verdict::Runholds aBox<Decision>: clippy'slarge_enum_variantrejects it unboxed. The handoff's design hadRun(Decision).
Area C's BrokerPort, measured
About 130 lines, written from task 17's exit list. All 17 compile-only tests passed on the first
run and on all 20 later runs, idle and loaded. The body found nothing the skeleton and the
desk-checked exit list had missed. The end-to-end test now exercises the same port against the
real brokerd.
The straylight check
tools/check-m3a-device.sh (copied by task 22, never run by the implementer). It reads
GET /slots?model=ornith-1.5-35b-a3b first and stops unless slot 0 reports
"is_processing": false; loopd uses slot 0 for the turn. It starts a private inferproxy,
brokerd serve and loopd serve on a temporary home with one ask grant for read_file, runs
bxctl chat --say, waits for the approval in bxctl approvals, checks that the block names the
grant and the call, approves it, and checks the audit log verifies with decision, approval and
result records. It has not run: this area had no access to straylight. Its jq test was
checked on sample /slots answers only (a first version used jq -e, which exits 1 on false,
the idle answer, and would have refused every run).
docs/egress.md lists no development call to straylight, although verify-device and this
script both make one. Proposed row: "Development | make verify-device,
tools/check-m3a-device.sh | straylight's llama-server | Checks against the real model, through
a private inferproxy; the script also reads /slots with curl."
Runbook
No new anchor. The audit-unavailable entry gained the new messages that point at it (the
"earlier write failed" line on every later call, "the result could not be recorded", the refusal
error, and the panicked-ledger variant). Carry that edit to master. check-runbook.sh passes on
this branch.
For the process record
| Found by | Defects |
|---|---|
| Writing the reference | 7 spec gaps (1 to 7 above) |
| Writing the tests and fixtures | 1 spec inaccuracy (8), 1 tool defect (the escape) |
| Simulating the implementer's tree per task | 2 plan defects (the rig, the Makefile) |
| Running the tests against the reference | 0 test defects beyond compile errors |
The BrokerPort body |
0 |
| Mutation check | 14 of 14 mutants caught |