CB-185: route members to separate herdr #186
Reference in New Issue
Block a user
Delete Branch "worker/cb185-router-d6436d-3"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds memberHerdrSocket and HerdrRouter. Members use the optional second daemon while lead scanning and lead operations stay on the lead daemon. Tests: mvn -f fleetd/pom.xml clean install (988 tests, success).
Lead review — not merging yet. Three consumers are still on the wrong daemon.
The router itself is right, and the single-daemon path is genuinely unchanged: with
memberHerdrSocketunset,memberHerdr == herdr, the constructor takes itsmember == leadbranch,and there is still exactly one
AgentControland oneWorkspaceControl— the regression from thefirst revision is gone. I checked every consumer in
Fleetd.javaone by one and the launchers,LeadTabScanner,LeadLauncher,CompletionResolver,ReplyPushLoop,LeadHeartbeatLoop,LeadCoordLoop,Injector,StatusPollerandMessageServiceare all on the correct side.Three are not. All three are invisible today for the same reason — both clients are the same object —
and all three go wrong the moment the feature is switched on. That is the third time this branch has
had that exact shape, so I would rather fix them here than merge and find out later.
1.
PaneLocatoris pinned to the member daemon —Fleetd.java:502PaneLocator.terminalForPidwalkspane.liston ONE client. A lead's pane lives on the LEAD daemon,so with two daemons a lead's own MCP connection resolves to
terminal == null.FleetMcp.replyandFleetMcp.askboth refuse outright whencallerTerminal == null, so a lead can no longer answer apeer lead with
fleet_reply, andfleet_whoamiloses its leader name. Connection identity has to beable to resolve a caller on either daemon.
2.
StatusRefineris pinned to the member daemon —StatusPoller.java:47The router constructor builds
new StatusRefiner(router.memberAgents()), while the status call onthe next line is correctly routed per target. For a LEAD target whose raw herdr status comes back
UNKNOWN — a documented, real heuristic miss, which is why the refiner exists — the refiner reads pane
content from the wrong daemon and returns UNKNOWN forever. That wedges status-gated delivery to that
lead.
3.
FleetAppnever goes through the router —Fleetd.java:602FleetApp.healthz()callsherdr.call("ping")andFleetApp.sessions()callsherdr.call("workspace.list"), both on the raw lead-only client. With two daemons,/healthzisgreen while the MEMBER daemon is down — and then every spawn fails, which is precisely the failure
scripts/redeploy-fleetd.shalready warns about — andGET /sessionssilently drops everymember-hosted workspace.
On the tests
HerdrRouterTestbuilds its own router and asserts on it: it proves the router's logic, not thatFleetd.mainuses it.FleetdHerdrControlConstructionTestdoes check the real production file, butonly that no raw constructor call is left; it cannot see which client each consumer got. Neither test
would have caught any of the three above, and neither would a fourth test of the same kind. Whatever
lands next needs an assertion that ties a consumer to a side, not just to the router.
Build
mvn -f fleetd/pom.xml clean installon this branch:Tests run: 989, Failures: 0, Errors: 0—BUILD SUCCESS. So this is not about the build; it is about what the build cannot see.Delegated the three fixes to a member on branch
worker/cb185-router-routing-gaps-9e9d33-3. I willmerge this once they land.
Note that #187 has merged in the meantime (
a237fbf), so this branch will want a rebase or a mergefrom
main. #187'slist()fix and this router are the two halves of the same change — neither issafe to enable alone.