fleetd #425 rework round 4: mutation-pinning test for the dropped PlacementDecision
SessionManager.acquireWithWorktree's unqualified branch must carry the PlacementDecision it already resolved via launcher.place() into launcher.spawn(spawnReq, decision) rather than re-deriving it through a blank-profile launcher.spawn(spawnReq). Every existing test in this file uses PlacementPolicies.fixed(), which answers select() the same way on every call, so dropping the decision (handle = launcher.spawn(spawnReq);) was invisible: 186 tests stayed green under that mutation. acquireWithWorktreeSpawnsOnTheSameProfileItProvisionedTheWorktreeForUnderARotatingPolicy uses PlacementPolicies.roundRobin() instead — deterministic AND stateful, so two select() calls on the same policy instance disagree (index 0 then index 1 across a two-profile pool). It asserts AGREEMENT between the profile the worktree's parity overlay was provisioned for and the profile the member actually spawned on, never a hardcoded expected profile name. Verified as a real mutation, not a no-op: applying the exact mutation (handle = launcher.spawn(spawnReq);) turns it red — expected [b.mcp.json] but was [a.mcp.json] — and reverting turns it green again. Full build: 1572 tests, 0 failures, 0 errors, BUILD SUCCESS.
This commit is contained in:
@@ -2219,6 +2219,64 @@ class SessionManagerTest {
|
||||
+ "on the worktree path alone (fleetd #425 rework, round 2)");
|
||||
}
|
||||
|
||||
/**
|
||||
* fleetd #425 rework, round 4: the exact regression a mutation test found that 186 green tests
|
||||
* missed — {@code acquireWithWorktree} dropping the {@link
|
||||
* dev.ltms.fleet.placement.PlacementDecision} it already resolved via {@code launcher.place},
|
||||
* and letting the unqualified spawn re-run placement a second time (a blank-profile {@code
|
||||
* launcher.spawn(spawnReq)}) instead of carrying that decision forward via {@code
|
||||
* launcher.spawn(spawnReq, decision)}. Every earlier test in this file uses {@code
|
||||
* PlacementPolicies.fixed()}, which returns the same answer on every {@code select()} call, so
|
||||
* dropping the decision is invisible under it — two {@code select()} calls simply agree by
|
||||
* accident. {@code PlacementPolicies.roundRobin()} is deterministic AND stateful: its {@code
|
||||
* select()} advances an internal index on every call, so two consecutive calls for the SAME
|
||||
* spawn (one from {@code place()} to provision the worktree, a second from a dropped-decision
|
||||
* blank-profile {@code spawn(spawnReq)}) land on DIFFERENT profiles from a two-profile pool —
|
||||
* index 0 ("a"), then index 1 ("b").
|
||||
*
|
||||
* <p>This test does not hardcode which profile wins — asserting one specific name would pass
|
||||
* for the wrong reason the moment the rotation order changes (round-4 brief invariant 3). It
|
||||
* asserts AGREEMENT instead: whichever profile the worktree's parity overlay was provisioned
|
||||
* for must be the SAME profile the member actually spawned on. Each profile's overlay list is
|
||||
* named after the profile itself ({@code "a.mcp.json"}/{@code "b.mcp.json"}), so comparing the
|
||||
* recorded overlay against {@code s.profile() + ".mcp.json"} checks agreement without ever
|
||||
* naming an expected winner.
|
||||
*/
|
||||
@Test
|
||||
void acquireWithWorktreeSpawnsOnTheSameProfileItProvisionedTheWorktreeForUnderARotatingPolicy() {
|
||||
Map<String, FleetConfig.Profile> profiles = new LinkedHashMap<>();
|
||||
profiles.put("a", new FleetConfig.Profile("a", "http://gx00.gw:8000", "coder-a", null,
|
||||
"FLEETD_WORKER_TOKEN", List.of("claude"), "tab", "fleetd-workers",
|
||||
"worker: {profile} #{n}", null, "/repo/a", List.of("a.mcp.json")));
|
||||
profiles.put("b", new FleetConfig.Profile("b", "http://gx00.gw:8000", "coder-b", null,
|
||||
"FLEETD_WORKER_TOKEN", List.of("claude"), "tab", "fleetd-workers",
|
||||
"worker: {profile} #{n}", null, "/repo/b", List.of("b.mcp.json")));
|
||||
FakeHerdr herdr = new FakeHerdr();
|
||||
ClaudeCodeLauncher adapter = new ClaudeCodeLauncher(new AgentControl(herdr), new WorkspaceControl(herdr),
|
||||
new SubscriptionGuard(Set.of("gx00.gw")), profiles, "a", _ -> null);
|
||||
// roundRobin is deterministic AND stateful: the first select() call picks index 0 ("a"),
|
||||
// and the SAME policy instance's second select() call (reached only if the
|
||||
// PlacementDecision is dropped) picks index 1 ("b") — the two-call disagreement this test
|
||||
// needs to make a dropped decision observable, rather than merely probable.
|
||||
PeerLauncher launcher = new CompositePeerLauncher(List.of(adapter), "a", profiles,
|
||||
PlacementPolicies.roundRobin(), _ -> 0);
|
||||
|
||||
FakeWorktrees worktrees = new FakeWorktrees();
|
||||
SessionManager sessions = new SessionManager(launcher, worktrees, () -> 0L);
|
||||
|
||||
MemberSession s = sessions.acquire(null, null, "/caller",
|
||||
null, new WorktreeRequest("fleetd-425-round4", null));
|
||||
|
||||
FakeWorktrees.OverlayCall overlay = worktrees.lastOverlay();
|
||||
assertNotNull(overlay, "overlayParity must have been called");
|
||||
assertEquals(List.of(s.profile() + ".mcp.json"), overlay.requested(),
|
||||
"the worktree must be provisioned for the SAME profile the member actually spawned "
|
||||
+ "on — under a rotating policy, dropping the PlacementDecision makes the "
|
||||
+ "second, spawn-time select() call disagree with the first, place()-time "
|
||||
+ "call, so the member ends up on a profile whose worktree (repoRoot/parity "
|
||||
+ "overlay) was built for a DIFFERENT profile (fleetd #425 rework, round 4)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce one {@code acquire(...)} attempt to a value comparable across the with-worktree and
|
||||
* without-worktree paths: the spawned profile name on success, or the thrown exception's class
|
||||
|
||||
Reference in New Issue
Block a user