Hand over the M3a plan: 22 tasks, their files, and the check record
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>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
# M3a checks, fork A: the audit chain (tasks 01, 03, 09, 19)
|
||||
|
||||
What each task's tests were checked against before hand-over, and what writing that check
|
||||
exposed. The reference lives on branch `m3a-ref-a` (worktree `~/src/boxmaker-ref-a`).
|
||||
|
||||
The fixture logs in `files/crates/proto/tests/fixtures/audit/` were made by
|
||||
`crates/proto/tests/gen_audit_fixtures.rs` in the reference tree
|
||||
(`cargo test -p proto --test gen_audit_fixtures -- --ignored`). It builds a good two-day log with
|
||||
real `proto::sha256` hashes and then damages it one way per directory. The generator is not
|
||||
handed over: the implementer gets the directories and `tests/chain.rs`, which says what each
|
||||
must verify as.
|
||||
|
||||
Mutation check: eight deliberate defects were put into the reference one at a time (recovered
|
||||
line must fail to parse; writer goes back to an older file; `--accept-break` uses the short
|
||||
check; break `seq` read from the record; `last_good` unchecked; break `prev` unchecked; sticky
|
||||
failure removed; an unparseable last line with a newline is a failure). Each made at least one
|
||||
given test fail.
|
||||
|
||||
| Task | Check | What the check exposed |
|
||||
|---|---|---|
|
||||
| 01 proto audit types | Reference (the types), plus the existing walk-every-object test `strict.rs` | **Contract defect, security-relevant.** `DecisionRecord::Allowed` and `Ask` were unit variants. serde does not apply `deny_unknown_fields` to a unit variant of an internally tagged enum, so `{"outcome":"allowed","zz":true}` decoded. `strict.rs` (tip T2) caught it on the first run. Fixed by making them empty struct variants, `Allowed {}` and `Ask {}`; the JSON is unchanged, but every construction and match site writes the braces. `strict.rs` had to change: a decision or approval line now holds three objects, not two. |
|
||||
| 03 proto chain verifier | Reference, 30 generated fixture logs, mutation check | **Spec gap 1.** The spec gives `abandoned` and `unfinished` as "seq of …" but `Result.decision` and `Approval.decision` both name the *decision's* `seq`, so an approved call can only be tracked under the decision's `seq`. The reference reports the decision's `seq` in both lists (it is also the approval id the owner saw). **Spec gap 2.** The resumed-verifier exception was specified only outside a failed region. If the latest file also has damage before the break record, the resumed verifier is already in a failed region when it meets the break naming an older file, its four checks cannot match, and `brokerd` would refuse to start after a correctly accepted break while `--accept-break` says "nothing to accept". The exception must apply inside a region too. **Spec gap 3.** A chain-valid `Recovery` record that describes nothing (hash and length of no neighbouring line) was not addressed; the reference makes it a failure. **Spec gap 4.** `ChainReport` as specified could not tell the writer what a `Recovery` or `AcceptedBreak` must carry, so each consumer would recompute `seq` and `prev`; `ChainFailure` gained `last_good`, `break_prev`, `break_seq`, `tail_torn`, and `torn_tail` became a `TornTail` with `recovery_prev` and `recovery_seq`. **Test defect found by running:** the generator's day-2 approval named a fixed decision `seq`, wrong once a recovery shifted the numbering. |
|
||||
| 09 brokerd audit writer | Reference, mutation check | **Spec defect 1.** "Each tampering fixture must fail in `brokerd`'s startup" cannot hold as written: an ordinary start reads only the latest file, so damage in an older file is, by design, not seen. The startup tests copy the damaged file alone so that it is the latest. **Spec defect 2.** "Resumed from the last line of the file before; that line must parse, or it is the failure" deadlocks: accept a break whose failure *is* that last line, and every later ordinary start fails on it while `--accept-break` says "nothing to accept". The reference falls back to verifying the whole log when there is no record to resume from. **Spec gap.** Whether `--accept-break` with a torn tail and no failure recovers the tail before refusing: the reference writes nothing and returns "nothing to accept". **Task defect.** `AuditError::Broken(ChainFailure)` fails clippy's `result_large_err`; it is boxed. **Also:** a fallback "if the short check fails, run the full check" was written and then removed, because the region exception (gap 2 above) makes it unreachable and an untested rule is one the implementer will get wrong silently. |
|
||||
| 19 bxctl audit verify | Reference | Spec gap: the exact lines were not given, and a torn tail had no line at all, although a live `brokerd` mid-write produces one. The task fixes the wording. `main.rs` was not touched here (fork D owns it); the task describes the command's behaviour for the implementer to add in task 18's style. |
|
||||
Reference in New Issue
Block a user