Skip to content

feat(paging,#1299): PressureBrokerModule bootstrap — singleton + DockerTierPool register + tick loop (PR-1)#1307

Merged
joelteply merged 1 commit into
canaryfrom
feat/pressure-broker-bootstrap-1299
May 16, 2026
Merged

feat(paging,#1299): PressureBrokerModule bootstrap — singleton + DockerTierPool register + tick loop (PR-1)#1307
joelteply merged 1 commit into
canaryfrom
feat/pressure-broker-bootstrap-1299

Conversation

@joelteply
Copy link
Copy Markdown
Contributor

Summary

PR-1 of #1299 (Phase 2 of #1239). Brings the cross-pool PressureBroker online:

  • New modules::pressure_broker_module::PressureBrokerModule wraps Arc<PressureBroker> and pre-registers DockerTierPool on construction.
  • Hands the broker's relieve() tick to the runtime's standard start_tick_loops() machinery (cadence = BrokerConfig.tick_interval, default 5s, matching DMR_TICK_INTERVAL).
  • tick() wraps relieve() in spawn_blocking because DockerTierPool::evict_at_least shells out to docker system prune which can take seconds.
  • Observer-only: empty command_prefixes so the runtime router never dispatches here. Typed system/pressure-broker-state IPC lands in PR-2; chat-substrate alert sink lands in PR-3.
  • broker() getter so the ipc/mod.rs bootstrap can expose the broker to other subsystems (VRAM/KV-cache pool registration, alert sink wiring) without re-instantiating.
  • Registered in ipc/mod.rs::start_server next to SystemResourceModule using the standard runtime.register(Arc::new(...)) pattern.

Acceptance items closed by this PR (per #1299)

  • (1) Singleton instantiated at server boot
  • (2) DockerTierPool registered on boot
  • (3) Tick loop calling relieve() on cadence
  • (6) Test with fake ResourcePool

Deferred to follow-up slices on this same card

  • (4) Chat-substrate alert sink → PR-3
  • (5) system/pressure-broker-state IPC + bin/continuum status row → PR-2

Test plan

  • 6 new unit tests pass (cargo test --lib --features metal,accelerate modules::pressure_broker_module):
    • DockerTierPool present in broker right after ::new()
    • ModuleConfig tick_interval mirrors BrokerConfig
    • command_prefixes empty in PR-1 (regression guard for future maintainers)
    • tick → relieve fires eviction when fake pool is at ~95% pressure
    • tick is a no-op when all pools below threshold
    • handle_command error explains the PR-1-observer-only staging
  • cargo build --lib --features metal,accelerate: clean (no new warnings; pre-existing 52 unchanged)
  • CI green on this PR
  • Live: start the server, watch the pressure-broker tick loop appear in Started N tick loops log line

Why a wrapper module vs OnceLock<Arc<PressureBroker>> directly

Every other singleton in this server (gpu_manager, system_monitor, etc.) either lives behind a ServiceModule or is owned by one. Following that pattern keeps the boot sequence in ipc/mod.rs uniform and gives the broker the same shutdown / metrics treatment as everything else.

Coordination

Aligned with codex's parallel #1306 — that PR lifts cognition's hardcoded max_concurrency: 1 cap with this broker as the real backpressure source it was deferring to.

🤖 Generated with Claude Code

…erTierPool register + tick loop (PR-1)

Phase 2 of #1239 follow-on. Phase 1 (PR #1297) shipped the data-surface
`system/docker-tier-stats` IPC that bypassed the broker. This module
brings the broker online so disk-tier pressure can drive real eviction
instead of just sitting in the data layer.

What lands here (PR-1 of #1299)

- New `modules::pressure_broker_module::PressureBrokerModule`. Wraps an
  `Arc<PressureBroker>` and pre-registers `DockerTierPool` as a
  `ResourcePool` on the broker at construction. Acceptance items 1, 2.
- ServiceModule impl declares `tick_interval = BrokerConfig.tick_interval`
  (default 5s, matching `DMR_TICK_INTERVAL`). The runtime's existing
  `start_tick_loops()` machinery owns the cadence; we just implement
  `tick()` to call `PressureBroker::relieve()`. Acceptance item 3.
- `tick()` wraps `relieve()` in `tokio::task::spawn_blocking` because
  `DockerTierPool::evict_at_least` shells out to `docker system prune`
  which can take seconds — the broker tick must never stall other
  tokio tasks sharing the runtime.
- Observer-only: `command_prefixes` is empty so the runtime command
  router never dispatches to this module. The typed
  `system/pressure-broker-state` IPC lands in PR-2; chat-substrate
  alert sink lands in PR-3.
- `broker()` getter on the module so the ipc/mod.rs bootstrap can
  expose the broker to other subsystems (VRAM/KV-cache pools that
  want to register; PR-3's alert sink wiring) without re-instantiating.
- Registered in `ipc/mod.rs::start_server` next to `SystemResourceModule`
  using the same `runtime.register(Arc::new(...))` pattern every other
  ServiceModule uses.

Tests (acceptance item 6 — fake ResourcePool)

- `FakePool` whose pressure is driven by a test-controlled `AtomicU64`
  and whose `evict_at_least` stamps the bytes requested so the test
  can assert the broker actually invoked eviction.
- `module_registers_docker_pool_at_construction` — DockerTierPool is on
  the broker right after `::new()`, before any external call.
- `module_advertises_tick_interval_from_config` — ModuleConfig's
  tick_interval mirrors BrokerConfig so runtime cadence matches policy.
- `module_exposes_no_command_prefixes_in_pr1` — guards against a future
  PR adding prefixes without handlers (catches a common scoping mistake).
- `tick_drives_relieve_and_fires_eviction_over_threshold` — fake pool
  at ~95% pressure, one tick, assert evict_at_least was called with
  positive bytes. Proves end-to-end: tick → relieve → eviction path
  is wired, not just relieve() being called.
- `tick_is_a_noop_when_all_pools_below_threshold` — mirror at ~30%,
  assert evict_at_least was NOT called.
- `handle_command_returns_pr1_observer_only_error` — error message
  explains the staging so a future maintainer knows where commands
  land instead of silently failing.

Why a wrapper module vs `OnceLock<Arc<PressureBroker>>` direct: every
other singleton in this server (gpu_manager, system_monitor, etc.)
either lives behind a ServiceModule or is owned by one. Following that
pattern keeps the boot sequence in ipc/mod.rs uniform and gives the
broker the same shutdown / metrics treatment as everything else.

Validation
- 6/6 new tests pass: cargo test --lib --features metal,accelerate modules::pressure_broker_module
- 2296 other lib tests still filtered correctly (no incidental breakage)
- cargo build --lib --features metal,accelerate: clean
- No new warnings introduced; pre-existing 52 warnings unchanged

Follow-on PRs on this same card
- PR-2: typed `system/pressure-broker-state` IPC + ts-rs export +
  `bin/continuum status` row (acceptance item 5)
- PR-3: chat-substrate alert sink via existing airc bridge — broker
  emits `PressureAlert`, sink posts `📢 PressureAlert tier=docker ...`
  to #cambriantech (acceptance item 4)

Refs continuum#1239 (parent), continuum#1297 (Phase 1 PR), continuum#1299 (this card).
Aligned with codex's parallel #1306 work that lifts cognition's
hardcoded `max_concurrency: 1` cap — the broker is now the real
backpressure source that cap was deferring to.
@joelteply joelteply merged commit a7f6c59 into canary May 16, 2026
3 checks passed
@joelteply joelteply deleted the feat/pressure-broker-bootstrap-1299 branch May 16, 2026 14:24
joelteply pushed a commit that referenced this pull request May 16, 2026
…rface (PR-2)

Continues #1299 (Phase 2 of #1239). Adds the IPC + wire types on top
of PR-1's (PR #1307) singleton + tick loop:

- PressureBrokerModule now declares `command_prefixes = &["system/pressure-broker-state"]`
  and implements handle_command to return BrokerSnapshot as JSON. Single
  probe per call (atomic pressure reads + max over pool list) — no
  eviction fires, cheap to poll.
- ts-rs-exports BrokerSnapshot + PoolView + PoolStats + PressureTier
  with camelCase serde so the TS mixin reads the same shape the Rust
  module emits — no manual remap layer. PressureTier serialized
  lowercase to match the existing label() impl + every other tier
  string the system emits in logs.
- Generated files land at shared/generated/paging/{BrokerSnapshot,PoolView,PoolStats,PressureTier}.ts;
  barrel re-exports updated via `npx tsx generator/generate-rust-bindings.ts`.

PR-1 tests updated to reflect the new behavior:
- `module_routes_only_pressure_broker_state_command` replaces the
  empty-prefixes guard from PR-1 with a one-prefix invariant.
- `handle_command_returns_typed_snapshot_for_routed_command` pins the
  wire contract: every camelCase BrokerSnapshot key must be present,
  globalTier must be lowercase normal|warning|high|critical (catches
  serde rename regressions).
- `handle_command_rejects_unknown_command` validates the error path
  names the actually-handled command.

7/7 tests pass: cargo test --lib --features metal,accelerate modules::pressure_broker_module
70/70 paging tests pass (ts-rs export_bindings tests included).

What this PR is NOT
- No TS mixin yet on RustCoreIPCClient (PR-2b candidate, follow-up small
  PR, follows the docker-tier-stats pattern from #1297).
- No `bin/continuum status` row (PR-3 candidate alongside the alert sink).

Stacked on PR #1307 (PR-1). Base = canary; will rebase if #1307 lands first.
joelteply added a commit that referenced this pull request May 16, 2026
…rface (PR-2) (#1308)

Continues #1299 (Phase 2 of #1239). Adds the IPC + wire types on top
of PR-1's (PR #1307) singleton + tick loop:

- PressureBrokerModule now declares `command_prefixes = &["system/pressure-broker-state"]`
  and implements handle_command to return BrokerSnapshot as JSON. Single
  probe per call (atomic pressure reads + max over pool list) — no
  eviction fires, cheap to poll.
- ts-rs-exports BrokerSnapshot + PoolView + PoolStats + PressureTier
  with camelCase serde so the TS mixin reads the same shape the Rust
  module emits — no manual remap layer. PressureTier serialized
  lowercase to match the existing label() impl + every other tier
  string the system emits in logs.
- Generated files land at shared/generated/paging/{BrokerSnapshot,PoolView,PoolStats,PressureTier}.ts;
  barrel re-exports updated via `npx tsx generator/generate-rust-bindings.ts`.

PR-1 tests updated to reflect the new behavior:
- `module_routes_only_pressure_broker_state_command` replaces the
  empty-prefixes guard from PR-1 with a one-prefix invariant.
- `handle_command_returns_typed_snapshot_for_routed_command` pins the
  wire contract: every camelCase BrokerSnapshot key must be present,
  globalTier must be lowercase normal|warning|high|critical (catches
  serde rename regressions).
- `handle_command_rejects_unknown_command` validates the error path
  names the actually-handled command.

7/7 tests pass: cargo test --lib --features metal,accelerate modules::pressure_broker_module
70/70 paging tests pass (ts-rs export_bindings tests included).

What this PR is NOT
- No TS mixin yet on RustCoreIPCClient (PR-2b candidate, follow-up small
  PR, follows the docker-tier-stats pattern from #1297).
- No `bin/continuum status` row (PR-3 candidate alongside the alert sink).

Stacked on PR #1307 (PR-1). Base = canary; will rebase if #1307 lands first.

Co-authored-by: Test <test@test.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant