# M6b task 02: `CONSULT_WAIT` through `timeout_for` **Branch:** `m6b`. Check it: `git branch --show-current` prints `m6b` and `git status --short` is empty; otherwise stop. Never switch branch. **Commit subject:** `loopd: consult waits one hundred and eighty seconds` **Log row:** the Task cell is `M6b/02-loopd-consult-wait`. **First action.** Run this before any Read of crate source. Do not `ls` `crates/loopd/tests/`. Do not Read `tests/support/`, `config.rs`, `docs/implementer-log.md` (except the first 12 lines at the log step). Do not edit `crates/loopd/tests/broker_port_ask_wait.rs` or `crates/loopd/src/config.rs`. The quoted blocks are the only edits. ```sh cp docs/plans/M6b/files/crates/loopd/tests/broker_port_consult_wait.rs crates/loopd/tests/ ``` ## Goal `BrokerPort::timeout_for("consult")` is 180 s, or `[broker] timeout_ms` if that is longer (spec 4.3). The default `[broker] timeout_ms` stays 120_000. `ask_memory` is unchanged. No test sleeps (T27). This task does not talk to `brokerd`. ## Every place that changes | Place | What happens there | |---|---| | `crates/loopd/src/broker_port.rs` | `CONSULT_WAIT`; `consult_timeout` on `new` and `with_log`; `timeout_for` arm | | `crates/loopd/tests/broker_port_consult_wait.rs` | new, given | | everything else | **no change**: not `config.rs`, not `broker_port_ask_wait.rs` | ## Files - Copy, from `docs/plans/M6b/files/` (the same path under it): the new test `crates/loopd/tests/broker_port_consult_wait.rs`. - Modify: `crates/loopd/src/broker_port.rs`, `docs/implementer-log.md`. - Do not touch: any other file. Do not edit `crates/loopd/tests/broker_port_ask_wait.rs` (`the_wait_for_each_tool` does not list `consult`; leaving it unedited is required). Do not change the default `timeout_ms: 120_000` in `crates/loopd/src/config.rs`. ## Facts you need - **Floor, not a replacement.** `timeout_for("consult")` is `self.timeout.max(self.consult_timeout)`. A configured 300 s wait stays 300 s. - **Both constructors.** `new` and `with_log` each name `consult_timeout: CONSULT_WAIT`. `with_ask_wait` and `with_pending_cap` use `..self` and need no edit. - **`ASK_MEMORY_WAIT` stays.** Do not change its value or its arm. - The items the edits use. This table is complete. | Item | Signature | |---|---| | `BrokerPort::new` | `new(socket: PathBuf, timeout: Duration) -> BrokerPort` | | `BrokerPort::with_log` | `with_log(socket: PathBuf, timeout: Duration, log: Box) -> BrokerPort` | | `BrokerPort::timeout_for` | `timeout_for(&self, tool: &str) -> Duration` | | `crate::consult::CONSULT` | `&str`, `"consult"` (task 01) | | `crate::memory::ASK_MEMORY` | `&str`, `"ask_memory"` | ## The edits, exactly Each quoted "before" block occurs exactly once after task 01. ### `crates/loopd/src/broker_port.rs` **W1.** After `pub const ASK_MEMORY_WAIT: Duration = Duration::from_secs(180);` add: ```rust /// The longest `BrokerPort` waits for a `consult` answer, unless `[broker] timeout_ms` is /// longer: `brokerd`'s `[consult] timeout_ms` defaults to 180 s (M6 spec, section 4.3). pub const CONSULT_WAIT: Duration = Duration::from_secs(180); ``` **W2.** The struct fields ```rust socket: PathBuf, timeout: Duration, ask_timeout: Duration, pending_cap: Duration, log: Box, ``` become ```rust socket: PathBuf, timeout: Duration, ask_timeout: Duration, consult_timeout: Duration, pending_cap: Duration, log: Box, ``` **W3.** Inside `new`, the fields ```rust socket, timeout, ask_timeout: ASK_MEMORY_WAIT, pending_cap: MAX_PENDING_WAIT, log: Box::new(|l| eprintln!("{l}")), ``` become ```rust socket, timeout, ask_timeout: ASK_MEMORY_WAIT, consult_timeout: CONSULT_WAIT, pending_cap: MAX_PENDING_WAIT, log: Box::new(|l| eprintln!("{l}")), ``` **W4.** The comment and body of `timeout_for` ```rust /// The wait for one call of `tool`, used wherever the port waits for that call: the timeout, /// or for `ask_memory` the longer of the timeout and its own wait. pub fn timeout_for(&self, tool: &str) -> Duration { if tool == crate::memory::ASK_MEMORY { self.timeout.max(self.ask_timeout) } else { self.timeout } } ``` become ```rust /// The wait for one call of `tool`, used wherever the port waits for that call: the timeout, /// or for `ask_memory` and `consult` the longer of the timeout and that tool's own wait. pub fn timeout_for(&self, tool: &str) -> Duration { if tool == crate::memory::ASK_MEMORY { self.timeout.max(self.ask_timeout) } else if tool == crate::consult::CONSULT { self.timeout.max(self.consult_timeout) } else { self.timeout } } ``` **W5.** Inside `with_log`, the fields ```rust socket, timeout, ask_timeout: ASK_MEMORY_WAIT, pending_cap: MAX_PENDING_WAIT, log, ``` become ```rust socket, timeout, ask_timeout: ASK_MEMORY_WAIT, consult_timeout: CONSULT_WAIT, pending_cap: MAX_PENDING_WAIT, log, ``` ## Steps - [ ] **1. Copy the given test.** ```sh cp docs/plans/M6b/files/crates/loopd/tests/broker_port_consult_wait.rs crates/loopd/tests/ ``` - [ ] **2. See it fail.** `cargo test -p loopd --test broker_port_consult_wait`, timeout 600000 ms: the test target does not compile (`E0432` unresolved `CONSULT_WAIT`). - [ ] **3. The edits.** W1–W5. `cargo check -p loopd` prints no error and no warning. `wc -l crates/loopd/src/broker_port.rs` ≤ 500. - [ ] **4. The tests.** `cargo test -p loopd --test broker_port_consult_wait --test broker_port_ask_wait`: every test passes, 1 in `broker_port_consult_wait`. `the_wait_for_each_tool` still passes. - [ ] **5. Run the gate.** `cargo fmt --all`, then `make gate`, timeout 600000 ms. Last line `gate: ok`. Test count **1593** (1592 before, plus 1). After `gate: ok`, do not add up `test result:` lines. - [ ] **6. Log and commit.** Task cell `M6b/02-loopd-consult-wait`. Read only the first 12 lines of `docs/implementer-log.md`; insert the row under the header. Stage with `git add crates/loopd docs/implementer-log.md Cargo.lock`, then commit as `AGENTS.md` says. ## Done when - `make gate` prints `gate: ok` with 1593 tests. - `git diff HEAD~1 --stat` lists only `crates/loopd/src/broker_port.rs`, `crates/loopd/tests/broker_port_consult_wait.rs` and the log. ## Stop and report if - The branch check fails; a "before" block is missing or duplicated; step 2 compiles; you edit `broker_port_ask_wait.rs` or `config.rs`; `cargo check` warns; `the_wait_for_each_tool` fails; a test outside the named files fails in the gate (`git stash -u`, rerun, `git stash pop`, report both). ## What the given tests pin `CONSULT_WAIT` is 180 s. `timeout_for("consult")` is 180 s when the port timeout is 120 s, and 300 s when the port timeout is 300 s. `timeout_for("recall")` stays the port timeout. `with_log` matches `new`.