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>
82 lines
3.1 KiB
Markdown
82 lines
3.1 KiB
Markdown
# 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
|
|
|
|
```rust
|
|
// 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
|
|
|
|
```rust
|
|
// 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
|
|
|
|
```rust
|
|
let taken = waiting(store)?
|
|
```
|
|
|
|
becomes
|
|
|
|
```rust
|
|
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.
|