Files
kyleandClaude Opus 5.5 64190c3701 M5a plan: task 16, the gate passes on macOS; the review's tasks become 17 to 20
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>
2026-09-25 16:41:44 -07:00

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, from docs/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_accepted and ids_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. Then cargo 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 gate prints gate: ok with 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.