The work moved to titan (macOS), where the gate failed for reasons older than M5a: sockets under macOS's long TMPDIR pass its 104-byte limit, gatewayd reads /proc/self for its uid, and /tmp is /private/tmp. Task 16 sets TMPDIR=/tmp for every process Cargo runs (.cargo/config.toml [env]), has gatewayd take its uid from the owner of a pipe it makes (no dependency, no unsafe), and hands over a toolkit shell.rs that compares resolved paths. On a scratch tree the gate passes on titan and on talos with 936 tests, and a wrong uid fails 7 gatewayd tests. Tasks 16 to 19 are renumbered 17 to 20. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
3.1 KiB
M5a task 20: a staged write never reuses an id
Branch: m5a (run git switch m5a; git status --short must be empty, otherwise stop)
Commit subject: memoryd: a staged write's id counts every write staged that day
Goal
A fix for a bug the M5a review found (2026-09-24). When review is on, review::submit gives each
staged write an id, p-<day>-NNNN, numbered by how many writes that day already have one. It
counted only the writes still waiting. So once p-2026-09-24-0001 had been accepted, the next
write that day was given p-2026-09-24-0001 again. waiting treats every id with an Accepted
line as done, so that write never showed in bxctl memory pending and could not be accepted or
rejected: it was lost, while the model was told it was waiting for review.
The fix counts every Waiting line in pending.jsonl, done or not, so an id is never used twice.
The comment above says the same, more plainly than before.
Files
- Copy: the new test
crates/memoryd/tests/review_ids.rs, fromdocs/plans/M5a/files/(the same path under it) - Modify:
crates/memoryd/src/review.rs,docs/implementer-log.md
The edits, exactly
Both are in submit in crates/memoryd/src/review.rs. Nothing else in the file changes;
waiting does not change, since list, accept and reject still use it.
1. The comment lines
// 2. `day` is the first 10 characters of `ctx.now.to_rfc3339()`. `taken` = how many Waiting
// lines have an id starting format!("p-{day}-"). The id is format!("p-{day}-{:04}", taken +
// 1).
become
// 2. `day` is the first 10 characters of `ctx.now.to_rfc3339()`. `taken` = how many Waiting
// lines of `lines(store)?`, done or not, have an id starting format!("p-{day}-"): an id is
// never used twice. The id is format!("p-{day}-{:04}", taken + 1).
2. The line
let taken = waiting(store)?
becomes
let taken = lines(store)?
The .iter(), .filter(..) and .count() lines after it stay as they are.
Steps
- 1. Copy the test:
cp docs/plans/M5a/files/crates/memoryd/tests/review_ids.rs crates/memoryd/tests/ - 2. See it fail.
cargo test -p memoryd --test review_ids. Expected: both tests fail,a_write_staged_after_an_accepted_one_gets_a_new_id_and_can_be_acceptedandids_count_every_write_staged_that_day_waiting_or_done. - 3. Make the two edits. Run
cargo fmt --all. - 4. See it pass.
cargo test -p memoryd --test review_ids: both pass. Thencargo test -p memoryd: every suite passes. - 5. Run the gate.
make gate. Expected last line:gate: ok, with 941 tests (939 before this task, plus the two new ones). - 6. Log and commit.
git add crates/memoryd docs/implementer-log.md && git commit
Done when
make gateprintsgate: okwith 941 tests.
Stop and report if
- Either quoted block is not in the file exactly as shown.
- Step 2 shows a different result than two failures.
- A test other than these two fails after the edits. Do not change a test.