M3b plan: follow-up tasks 14 to 17 for the review's lower findings

14 moves the pipe handling out of container.rs (a pure move, replayed on its
own); 15 starts threads with Builder and bounds output collection with a 2 s
grace period; 16 escapes container errors in the log and fixes two texts; 17
fixes toolkit's thread start, casts and the egress-proxy form. Each checked
against a reference, which is not kept. Tips T24 to T26 from this run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-23 15:33:23 -07:00
co-authored by Claude Opus 5.5
parent c3aaecdae2
commit a57a1305e7
11 changed files with 695 additions and 7 deletions
+69
View File
@@ -0,0 +1,69 @@
# M3b task 17: three small fixes in `toolkit`
**Branch:** `m3b` (run `git switch m3b`; `git status --short` must be empty, otherwise stop)
**Commit subject:** `toolkit: no thread panic in http_fetch, no casts, exact egress-proxy form`
## Goal
Three findings from the M3b review (3 and 7), all small:
1. `fetch.rs` starts its standard-error reader with `std::thread::spawn`, which panics when the
system cannot make a thread. Use `std::thread::Builder`.
2. `input.rs` and `files.rs` compute a byte limit with an `as u64` cast, which AGENTS forbids.
3. `toolkit egress-proxy --socket <path> --allow <list> extra` is taken as the proxy form and
listens. The form is **exactly** five words; anything longer is not it.
## Files
- Copy: `crates/toolkit/tests/egress_form.rs`
- Modify: `crates/toolkit/src/fetch.rs`, `crates/toolkit/src/input.rs`,
`crates/toolkit/src/files.rs`, `crates/toolkit/src/main.rs`, `docs/implementer-log.md`
## The changes, exactly
**1. `fetch.rs`.** Replace
`let stderr_handle = std::thread::spawn(move || read_capped(stderr_reader));` with:
```rust
// `Builder`, not `spawn`, which panics when the system refuses a thread.
let stderr_handle = match std::thread::Builder::new().spawn(move || read_capped(stderr_reader)) {
Ok(handle) => handle,
Err(e) => {
let _ = child.kill();
let _ = child.wait();
return Outcome::tool_error(format!("http_fetch: cannot start a thread: {e}"));
}
};
```
**2. `input.rs` and `files.rs`.** Replace `.take(MAX_INPUT as u64 + 1)` with
`.take(u64::try_from(MAX_INPUT).map_or(u64::MAX, |n| n.saturating_add(1)))`, and the same for
`MAX_READ` in `files.rs`.
**3. `main.rs`.** In `parse_egress_proxy`, the first check becomes:
```rust
// Exactly five words: a longer list is not this form, and goes to the tool form (exit 2).
if args.len() != 5 || args.first()?.as_bytes() != b"egress-proxy" {
return None;
}
```
## Steps
- [ ] **1. Copy.** `git switch m3b`, then
`cp docs/plans/M3b/files/crates/toolkit/tests/egress_form.rs crates/toolkit/tests/`
- [ ] **2. See it fail.** `cargo test -p toolkit --test egress_form`. Expected: 1 fails after about
3 s ("it is listening").
- [ ] **3. Make the three changes.** Run `cargo fmt --all`.
- [ ] **4. See it pass.** `cargo test -p toolkit`. Expected: every suite passes; `egress_form` 1
passed quickly.
- [ ] **5. Check.** `grep -n "thread::spawn\| as u64" crates/toolkit/src/` prints nothing.
- [ ] **6. Run the gate.** `make gate`. Expected last line: `gate: ok`, with about 649 tests.
- [ ] **7. Log and commit.** `git add crates/toolkit docs/implementer-log.md Cargo.lock && git commit`
This is the last follow-up task of M3b. Stop after the commit.
## Done when
- `cargo test -p toolkit` passes; the grep prints nothing; `make gate` prints `gate: ok`.