# 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 --allow 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`.