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>
7.2 KiB
M3a checks, fork D: bxctl (tasks 18, 20) and the runbook gate script (task 21)
What each task's given tests were checked against before hand-over, and what doing so exposed.
Branch m3a-ref-d, three commits: 292780f (the task 18 state), 5f27808 (the task 20 state,
skeleton), and the one after it (reference bodies, written afterwards as a measurement).
What was checked how
| Task | Check | Ran green | Compiled only |
|---|---|---|---|
21 check-runbook.sh |
Real script, run for real. Self-test passes; five mutations of the script (no -x, exit at the first missing anchor, no -prune, a narrower anchor pattern, no "no pointers" check) each make the self-test fail. |
all | none |
18 escape.rs |
Written for real: 12 lines of logic, cheaper than a stub. | escape 8 of 8 |
none |
18 cli.rs, main.rs |
Written for real. Not by choice: the 12 existing chat tests drive the binary, and the binary cannot parse its arguments through a todo!(). |
cli 11 of 12; chat 12 of 12 |
cli 1 (it needs admin) |
18 admin.rs |
Skeleton (todo!() bodies; reason_name real, because the printer calls it). |
admin 1 of 21 |
admin 20 |
20 Printer, stream_turn, main.rs |
Written for real, for the same reason as cli.rs. |
chat_print 9 of 9; chat_approvals 3 of 20 |
none |
20 handle_pending |
Skeleton. | none | chat_approvals 17 |
So "skeleton" came to two things: the bodies of admin.rs and one function in chat.rs. 38 of
the 82 tests only compiled at hand-over quality. Everything was clippy-clean and formatted, and
the task 18 state (new command dispatch, M2b chat code) was built and tested on its own commit,
because main.rs is rewritten in both tasks.
Measurement: what a reference found that the skeleton had not
After the skeleton state was committed, the missing bodies were written (about 150 lines) and the
38 compile-only tests were run: all passed on the first run, then six more runs under CPU
load with no failure. The reference exposed no defect that the skeleton and a desk-check had
missed. For this kind of task (formatting and a request/answer client, exact strings) the
skeleton was enough. The reference bodies are kept in the last commit because the straylight
check needs a working bxctl approve; they are not handed to the implementer.
Defects the checks exposed
Task 21
- Spec 11 does not say what a pointer is when its anchor is not written out. A pointer built
with
format!("see docs/runbook.md#{anchor}"), or the placeholderdocs/runbook.md#<anchor>in a comment, has no anchor the script can read, and a script that skipped these would let a computed pointer through unchecked. The script fails on them. This binds every crate: undercrates/, in source and in tests, a pointer must be a literal, and no comment may holddocs/runbook.md#followed by a placeholder. Runsh scripts/check-runbook.shon the merged reference tree before hand-over. Proposed wording for spec 11: "An anchor must be written out in the source; a pointer whose anchor the script cannot read is an error." - Spec 11 says "in
crates/" without saying which files. Chosen:*.rs, test files included,target/excluded.grepon the binary frame fixture would otherwise need-a, which is not POSIX. - No pointer at all is a failure (tip I2): otherwise a change to the message format would turn the check off silently. Not in the spec; proposed: "It fails if it finds no pointer."
- Not fixed, out of scope:
scripts/check-lines.shstill exits at the first long file, inside a pipeline subshell (M1 finding 8).
Task 18
- Spec 9's example block contradicts spec 6. The example shows
{"command": "rm …", "cwd": "…"}with spaces; section 6 says the arguments areserde_json's serialisation of the typed value, which has none.bxctlprints whatbrokerdsent, escaped, and the tests use the compact form. The example should be compact. - Spec 9 leaves the block's details open; the tests now fix them: two spaces between parts;
spans are whole seconds under a minute, whole minutes under an hour, else whole hours, rounded
down;
expiredoncenow >= expires; a clock behind the broker's shows0 s ago; a session id over 10 characters is its first 9 and…; an empty list printsno pending approvals;approve_resultwith outcomeaskprintsruns(the re-decision lets anaskrun); any other error frame printsbxctl: <code>: <detail>on stderr and exits 1. GrantProblem.problemcan be several lines (toml's errors are), which would break<file>:<line>: <problem>.bxctlputsfileandproblemthroughescape_json_text, so each problem is one line whatever arrives. Better fixed at the source too: task 06 should give one-line problems.- The error type had to change while the test was being written (the T16 kind of defect):
a message that names the socket needs
AdminError::Connect(PathBuf, io::Error), notConnect(io::Error). Found by the skeleton. "+41".parse::<u64>()succeeds. An id is now "ASCII digits only, then parse".- Task order. Task 18 creates
main.rs'saudit verifyarm, butverify::runis task 19's. Task 18 therefore createscrates/bxctl/src/verify.rswith the final signature and a placeholder body, and adds all fourpub modlines. Task 19 must say "Modifyverify.rs", not "Create", and must not touchlib.rsormain.rs. - A contract file changed:
crates/bxctl/src/lib.rsgainedpub mod cli;, andchat::code_namebecamepub.
Task 20
- Spec 9, "
--sayand--jsonprint the event only", is ambiguous: without--jsonthere is no printed form of the event. Chosen, and tested:--jsonprints the event's JSON line and never contactsbrokerd;--sayshowsbrokerd's block and asks nothing, and the owner answers withbxctl approvefrom another terminal. Proposed wording: "--sayshows the block and does not ask.--jsonprints the event as JSON and nothing else." - Spec 9 escapes "reasoning and content" only. The model also chooses tool names, which were printed raw in three places, and the final answer on stdout was raw. All are escaped now. Proposed wording: "everything the model wrote: reasoning, content, tool names, and the answer on stdout."
- Exits the spec does not cover, now defined: the end of the input at the question
refuses;
brokerdunreachable, an approval that expired between the list and the answer, and any other failed answer are each reported on one line and the turn goes on; a failed write to the terminal is an error and nothing is answered. - One reader for stdin. Designing the binary-level test showed that the approval's answer
must come from the same
BufReaderas the chat lines: with a pipe, everything typed is in the first reader's buffer, and a second reader sees the end of the input.main.rsholds one reader for the whole run;interactive_mode_reads_the_answer_from_the_same_input_as_the_chatfails otherwise. tests/admin.rsis 497 lines andtests/chat_approvals.rs487, against the limit of 500. A test added later to either needs a new file.