Repository navigation
Commit ad7f569
authored
🤖 refactor: extract the agent peer-messaging broker from TaskService (#4010)
## Summary
Extracts the peer/family agent-messaging protocol's admission invariants
out of `TaskService` into a new `AgentPeerMessageBroker`: sliding-window
rate limits (per sender-target pair and per target), duplicate
suppression, queued-peer-message capacity, consecutive-peer-wake caps,
per-pair/per-target session budgets with idempotent refunds, per-target
delivery locks, title capping, and peer envelope/trigger composition.
`TaskService` keeps tree topology, stop-epoch/overlay orchestration, and
dispatch, and delegates every admission decision directly (no
pass-through wrappers).
## Background
Refactor #4 from the 2026-08-29 architecture review (evidence at main @
f04e0f8): taskService.ts inlined the whole protocol across two regions
(~5654-6736, ~9612-10097), and every protocol-invariant test had to spin
up the 35-method `WorkspaceHost` mock harness. Protocol invariants now
live in one module testable with a fake one-method host and a mock
clock.
Behavior-preserving by construction: check ordering, refusal codes,
reason strings, `retryAfterMs` math, and budget charge arithmetic are
byte-identical to the pre-refactor code.
## Net LOC delta
| | added | removed | net |
| ---------------------------------------------------------------- |
----- | ------- | -------- |
| Production (`agentPeerMessageBroker.ts` + `taskService.ts`) | 271 |
286 | **-15** |
| Tests (`agentPeerMessageBroker.test.ts` + `taskService.test.ts`) | 238
| 561 | **-323** |
| Total | 509 | 847 | **-338** |
Harness-heavy tests that only re-asserted pure invariants through the
full TaskService stack were deleted and replaced by table-driven broker
tests; one thin delegation test per route (peer rate-limit refusal,
`task_message_parent` and sibling budget exhaustion) plus every test
covering behavior the broker cannot see (refund-on-dispatch-failure,
charge-at-admission ordering, stop races, envelope-row persistence,
delivery serialization) were kept. The only irreducible addition is the
broker's structural boilerplate (imports, class/constructor, the local
one-method host interface), which is what makes the invariants
independently testable.
The broker declares its own minimal host interface
(`countQueuedAgentPeerMessages`) instead of importing from
`taskWorkspaceSeam.ts`, keeping this diff merge-independent from the
parallel WorkspaceHost role-interface split.
## Validation
- Remote dogfood UAT (Coder Agents): **PASS** on `ae9bf3e93` — live Xum
UI multi-agent tree across descendant/sibling/ancestor relations, an
independent 22-assertion edge-case probe (rate/dedupe/wake/budget
boundaries at exact ceilings, refund idempotence), and a source-level
cross-check of every refusal string and retry computation against
f04e0f8. The one commit since (`daa28db4f`) is cosmetic (test-cast
type reuse), revalidated locally.
- `bun test src/node/services/agentPeerMessageBroker.test.ts`: 12/12.
- `bun test src/node/services/taskService.test.ts`: 514 pass; the 2-3
sporadic failures (`terminal recovery ...` x2, `higher-ancestor waiters
...`) reproduce identically on pristine `origin/main` in this
environment (config.json atomic-write chown/rename ENOENT under /tmp)
and are unrelated to this diff.
- `make static-check`: green.
## Risks
Low. The moved logic is byte-identical and the delegation points are 1:1
at existing callsites; the riskiest surface (admission/charge ordering
under concurrent sends) is covered by kept integration tests and the
broker's check-order test (queued-count host query is only reached after
in-memory checks pass).
---
_Generated with `xum` • Model: `anthropic:claude-fable-5` • Thinking:
`xhigh` • Cost: `$37.96`_
<!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh
costs=37.96 -->
## Stack
Layer 3/10 of the architecture refactor stack (net -5,101 LOC overall).
This PR's diff is only this layer, against `mike/arch-git-patch-engine`.1 parent aedd055 commit ad7f569
4 files changed
Lines changed: 509 additions & 847 deletions
File tree
- src/node/services
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
0 commit comments