loopd: consult waits one hundred and eighty seconds
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
@@ -26,6 +26,9 @@ pub const MAX_PENDING_WAIT: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
/// longer: `brokerd` waits 170 s for `memoryd`, whose Honcho chats have 150 s (M5c spec,
|
||||
/// section 9).
|
||||
pub const ASK_MEMORY_WAIT: Duration = Duration::from_secs(180);
|
||||
/// 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);
|
||||
/// The runbook entry every outage line ends with.
|
||||
pub const POINTER: &str = "see docs/runbook.md#broker-unavailable";
|
||||
|
||||
@@ -63,6 +66,7 @@ pub struct BrokerPort {
|
||||
socket: PathBuf,
|
||||
timeout: Duration,
|
||||
ask_timeout: Duration,
|
||||
consult_timeout: Duration,
|
||||
pending_cap: Duration,
|
||||
log: Box<dyn Fn(&str) + Send + Sync>,
|
||||
}
|
||||
@@ -73,6 +77,7 @@ impl BrokerPort {
|
||||
socket,
|
||||
timeout,
|
||||
ask_timeout: ASK_MEMORY_WAIT,
|
||||
consult_timeout: CONSULT_WAIT,
|
||||
pending_cap: MAX_PENDING_WAIT,
|
||||
log: Box::new(|l| eprintln!("{l}")),
|
||||
}
|
||||
@@ -88,10 +93,12 @@ impl BrokerPort {
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// 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
|
||||
}
|
||||
@@ -114,6 +121,7 @@ impl BrokerPort {
|
||||
socket,
|
||||
timeout,
|
||||
ask_timeout: ASK_MEMORY_WAIT,
|
||||
consult_timeout: CONSULT_WAIT,
|
||||
pending_cap: MAX_PENDING_WAIT,
|
||||
log,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//! How long `BrokerPort` waits for `consult`: 180 s, or `[broker] timeout_ms` if that is longer.
|
||||
//! Do not edit.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use loopd::broker_port::{BrokerPort, CONSULT_WAIT};
|
||||
|
||||
fn quiet(timeout: Duration) -> BrokerPort {
|
||||
BrokerPort::with_log("unused.sock".into(), timeout, Box::new(|_| {}))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn consult_waits_one_hundred_and_eighty_seconds() {
|
||||
assert_eq!(CONSULT_WAIT, Duration::from_secs(180));
|
||||
let port = BrokerPort::new("unused.sock".into(), Duration::from_secs(120));
|
||||
assert_eq!(port.timeout_for("consult"), CONSULT_WAIT);
|
||||
assert_eq!(port.timeout_for("recall"), Duration::from_secs(120));
|
||||
let port = BrokerPort::new("unused.sock".into(), Duration::from_secs(300));
|
||||
assert_eq!(port.timeout_for("consult"), Duration::from_secs(300));
|
||||
let port = quiet(Duration::from_secs(120));
|
||||
assert_eq!(port.timeout_for("consult"), CONSULT_WAIT, "with_log as new");
|
||||
}
|
||||
@@ -6,6 +6,7 @@ reviewer adds findings under "Reviews" once per milestone.
|
||||
|
||||
| Task | Date | Status | Gate runs | First gate | Deviations | Notes | Model |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| M6b/02-loopd-consult-wait | 2026-10-03 | done | 1 | pass | none | Copied the given test `crates/loopd/tests/broker_port_consult_wait.rs` from `docs/plans/M6b/files/`. Step 2 failed as expected: E0432 unresolved `CONSULT_WAIT`. Added `CONSULT_WAIT` const (180 s) after `ASK_MEMORY_WAIT` in `broker_port.rs`. Added a `consult_timeout` field to the struct and to both `new` and `with_log` constructors (`with_ask_wait` and `with_pending_cap` use `..self` and need no edit). Extended `timeout_for` so `consult` returns `self.timeout.max(self.consult_timeout)` (floor, not replacement); a configured 300 s wait stays 300 s. `ASK_MEMORY_WAIT` and its arm unchanged; `broker_port_ask_wait.rs` and `config.rs` untouched. `cargo check -p loopd` clean, no warning; `wc -l` prints 270, under 500. All suites pass: `broker_port_consult_wait` 1, `broker_port_ask_wait` 4 (`the_wait_for_each_tool` still passes). `make gate` printed `gate: ok` with 1593 tests (1592 before, plus 1). No new dependency, so `Cargo.lock` unchanged. | ornith-1.5-35b-a3b |
|
||||
| M6b/01-loopd-consult-registry | 2026-10-03 | done | 1 | pass | none | Copied the given test `crates/loopd/tests/consult_registry.rs` from `docs/plans/M6b/files/`. Created `crates/loopd/src/consult.rs` with `CONSULT` const and `schema()` returning the `consult` `ToolSchema`. Added `pub mod consult;` to lib.rs after `pub mod config;`. In tools.rs `m5c()` pushed the non-core `consult` entry after the `subagent` entry (`Registry::new(entries)` unchanged). `cargo check -p loopd` clean, no warning; `wc -l` prints 21 for consult.rs, 481 for tools.rs, both under 500. All suites pass: `consult_registry` 2, `subagent_registry` 2, `ask_memory_tool`, `tools` 11, `baseline` 6. `make gate` printed `gate: ok` with 1592 tests (1590 before, plus 2). No new dependency, so `Cargo.lock` unchanged. | ornith-1.5-35b-a3b |
|
||||
| M6a/05-brokerd-state-inherit | 2026-10-03 | done | 1 | pass | none | Copied the given test `crates/brokerd/tests/state_subagent.rs` from `docs/plans/M6a/files/`. Step 2 (`cargo test -p brokerd --test state_subagent`) failed as expected: `a_new_subagent_copies_the_parents_untrusted_flag` (child was default private/trusted) and `a_nested_subagent_copies_through_a_missing_middle_child` (leaf was Private not Secret) failed, `a_plain_session_still_creates_nothing_on_read` passed. Applied I1 in state.rs `read`: replaced the `NotFound` early return with `return inherit_or_default(self, session)`. Applied I2 after `impl StateStore` (after `persist`'s and the `impl`'s closing braces, before `/// One line on disk`): added `inherit_or_default` which calls `parent_of_sub`, returns default when `None`, else `store.read(&parent)?` then `store.raise(session, SessionState::default(), Label{class: inherited.taint, untrusted: inherited.untrusted})`, and `parent_of_sub` which strips `sub-`, `rsplit_once('-')`, requires non-empty ASCII-digit suffix and builds `SessionId::new(parent)`. Did not touch `raise` or `persist`. `cargo check -p brokerd` clean, no warning; `wc -l` prints 176 for state.rs, under 500. All suites pass: `state_subagent` 3, `state` 9. `make gate` printed `gate: ok` with 1590 tests (1587 before, plus 3). No new dependency, so `Cargo.lock` unchanged. | ornith-1.5-35b-a3b |
|
||||
| M6a/04-loopd-scheduler-skip | 2026-10-03 | done | 1 | pass | none | Copied the given test `crates/loopd/tests/scheduler_subagent.rs` from `docs/plans/M6a/files/`. Step 2 (`cargo test -p loopd --test scheduler_subagent`) failed as expected: both tests failed, `work` not empty (a `Heartbeat` and a `Job { name: "mail", session: "job-mail-20261003t0700" }`) and `requests_to(CHAT)` not empty while the child was held. Applied H1 in channel.rs: added `holds_prefix` after `hold`'s closing `}` inside `impl Context`, locking `busy` like `hold` and returning whether any id starts with the prefix. Applied K2 in scheduler.rs `heartbeat`: after the `if !due { return; }` block and before `SessionId::new("heartbeat")`, `if ctx.holds_prefix("sub-") { return; }`. Applied K1 in scheduler.rs `tick`: immediately after `self.heartbeat(...)` and before `jobs_dir`, `if ctx.holds_prefix("sub-") { return work; }` so leftover-close on the first tick is already done. `cargo check -p loopd` clean, no warning; `wc -l` prints 307 channel.rs, 310 scheduler.rs, both under 500. All suites pass: `scheduler_subagent` 2, `scheduler_heartbeat` 6, `scheduler_cron` 6, `scheduler_heartbeat_failed` 1. `make gate` printed `gate: ok` with 1587 tests (1585 before, plus 2). No new dependency, so `Cargo.lock` unchanged. | ornith-1.5-35b-a3b |
|
||||
|
||||
Reference in New Issue
Block a user