fleetd #612 B3: behavioural replacements for lead-seat, quarantine, lead-rollover guards #628

Merged
ltms merged 3 commits from worker/612-b3-mcpwirings-da2b58-3 into worker/fleetd-612-unita-87807e-1 2026-09-22 07:36:05 +02:00
Member

Scope

fleetd #612 step 2, unit B3 (issue #612 comment 17513) — replaces three FleetdAssembly.java source-text guards with tests that drive the real assembled objects through FleetdAssembly.assembleAndStart(...) -> FleetdRuntime.mcp().

Base branch is worker/fleetd-612-unita-87807e-1, not main — matches this unit's brief; do not merge this into main.

Disclosure up front: FleetMcp.java accessors are public, not package-private

The brief's precedent (registeredTools()) is package-private, and said to add the new accessors "the same reason" — package-private if possible, and to disclose loudly if not. I could not keep them package-private: my new assembly tests live in package dev.ltms.fleet (they must, since they build the ResourcePorts that FleetdAssembly.assembleAndStart needs, and ResourcePorts's methods return Fleetd-nested types only visible from that package), while FleetMcp is in dev.ltms.fleet.mcp. A package-private accessor there is invisible from dev.ltms.fleet. So quarantineSource(), leadSeatSource() and leadRollover() on FleetMcp are public. Flagging this for whichever other B-unit (B1/B2) touches FleetMcp.java or FleetdRuntime.java next — no field was added to FleetdRuntime itself, per the brief's explicit ban.

What each deleted guard pinned, and what pins it now

  • FleetdLeadSeatWiringTest (fleetd #176) — pinned that FleetMcp's LeadSeatSource construction still wires Fleetd.leadSeatLookup(...), by scraping the constructor call's source text.
    Replaced by FleetdLeadSeatAssemblyTest: seeds one FakeHerdr tab labelled to match a configured fleet.leaders.opus.tab (reusing FakeHerdr's own hardcoded default pane/agent — term_a/w2:p7/w2:t7 — no FakeHerdr change needed) and asserts the REAL assembled LeadSeatSource (runtime.mcp().leadSeatSource()) reports the live lead's seat against its own subscription profile: 1, not the 0 LeadSeatSource.none() (the inert stand-in) could ever report.

  • FleetdBackendQuarantineWiringTest (fleetd #466) — pinned that BackendQuarantine.withEscalation(...)'s text was present and the flat two-argument constructor's text was absent.
    Replaced by FleetdBackendQuarantineAssemblyTest: quarantines the same credential twice through the REAL assembled BackendQuarantine (runtime.mcp().quarantineSource().quarantine()) at controlled fake-clock offsets, and asserts the second cooldown doubles (200s vs 100s) — the one behavioural difference escalation and the flat constructor actually produce.

  • FleetdLeadRolloverWiringTest (fleetd #480), all three methods:

    • unrelatedAnchorStillPresent was a scaffold anchor with no independent claim — needs no replacement.
    • mainStillCallsTheLeadRolloverFactory pinned the leadRollover assignment's call-site text.
    • factoryGatesOnConfigPresence pinned that an absent leadRollover: config yields no LeadRollover.

    Replaced by FleetdLeadRolloverAssemblyTest's two tests:

    • assembledLeadRolloverRunsTheRealClearAndBootstrapSequence drives the REAL assembled LeadRollover (runtime.mcp().leadRollover()) through open()/confirm() end to end and asserts /clear then bootstrapText were actually sent through the real herdr router, reaching ROLLED.
    • absentLeadRolloverConfigMeansNoRolloverIsBuilt calls Fleetd.leadRollover(...) directly with no leadRollover: block and asserts null. This claim was found uncovered anywhere else — LeadRolloverTest's only related assertion is vacuous (assertNull(null)) and never calls the real factory.

Mutation proof — all three call sites, RED then GREEN

Each call site in FleetdAssembly.java was mutated to its named inert variant, run against ONLY its new test (RED), reverted, touch'd (the Maven mtime trap: git checkout/mv can restore an mtime older than the compiled .class, so Maven skips recompiling and silently re-runs the mutant's bytecode), and re-run (GREEN).

1. Quarantine — FleetdAssembly.java:179-180

BackendQuarantine.withEscalation(ports.nanoClock(), TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds())) -> new BackendQuarantine(ports.nanoClock(), TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds())) (the flat two-arg constructor)

RED:

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.696 s <<< FAILURE!
dev.ltms.fleet.FleetdBackendQuarantineAssemblyTest.assembledQuarantineEscalatesOnARepeatedExhaustion(Path) -- Time elapsed: 0.683 s <<< FAILURE!
org.opentest4j.AssertionFailedError: withEscalation's default backoff doubles the cooldown on the second consecutive exhaustion ... ==> expected: <200> but was: <100>

GREEN (after revert + touch):

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.774 s -- in dev.ltms.fleet.FleetdBackendQuarantineAssemblyTest

2. Lead seats — FleetdAssembly.java:479

new FleetMcp.LeadSeatSource(Fleetd.leadSeatLookup(() -> config.get().profiles(), leaders, leads)) -> FleetMcp.LeadSeatSource.none()

RED:

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.711 s <<< FAILURE!
dev.ltms.fleet.FleetdLeadSeatAssemblyTest.assembledLeadSeatSourceReportsALiveLeadsSeat(Path) -- Time elapsed: 0.701 s <<< FAILURE!
org.opentest4j.AssertionFailedError: the real LeadTabScanner recognises the labelled tab as a live 'opus' lead ... ==> expected: <1> but was: <0>

GREEN (after revert + touch):

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.829 s -- in dev.ltms.fleet.FleetdLeadSeatAssemblyTest

3. Lead rollover — FleetdAssembly.java:408

LeadRollover leadRollover = Fleetd.leadRollover(cfg, router.leadAgents(), config, leads); -> LeadRollover leadRollover = null;

RED:

Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.843 s <<< FAILURE!
dev.ltms.fleet.FleetdLeadRolloverAssemblyTest.assembledLeadRolloverRunsTheRealClearAndBootstrapSequence(Path) -- Time elapsed: 0.826 s <<< FAILURE!
org.opentest4j.AssertionFailedError: leadRollover: is present in this test's config, so FleetdAssembly.assembleAndStart must have built a real LeadRollover ... ==> expected: not <null>

(the sibling absentLeadRolloverConfigMeansNoRolloverIsBuilt correctly stayed green here — it calls Fleetd.leadRollover directly, not through this mutated call site)

GREEN (after revert + touch):

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.614 s -- in dev.ltms.fleet.FleetdLeadRolloverAssemblyTest

After every revert: git diff -- fleetd/src/main/java/dev/ltms/fleet/FleetdAssembly.java was empty.

Full build

mvn -o test in fleetd/ at the tip of this branch:

Tests run: 1879, Failures: 6, Errors: 0, Skipped: 0
BUILD FAILURE

Down from this branch's baseline (1880/9) by exactly the 3 guards this unit deletes. The 6 remaining failures are FleetdCompletionResolverWiringTest (4), FleetdConnectionIdentityConstructionTest (1) and FleetdFleetAppConstructionTest (1) — all out of this unit's scope (B1/B2, per issue #612 comment 17513's split). BUILD FAILURE is expected and correct until B1/B2 land.

Caveats for review

  • FleetMcp.java's three new accessors are public, not package-private — see disclosure above. Likely collides with whatever B1/B2 also touch in FleetMcp.java.
  • FleetdLeadRolloverAssemblyTest's happy-path test takes ~2.6s real wall-clock time: the production LeadRollover constructor always uses a real virtual thread and real 250ms settle-poll sleeps, and FakeHerdr's agent never reports WORKING, so the post-/clear wait releases via its 8-poll (~2s) pickup-grace path rather than a real completion boundary. This exercises the full real happy path (both agent.prompt sends, ending in ROLLED), just not instantaneously.
  • Not fixed, reported per the brief's "report the shape, don't fix it" instruction: FleetMcpHandoverTest (in dev.ltms.fleet.mcp) drives FleetMcp.handover(...) with a hand-built LeadRollover/FakeHerdr, not the real assembly — same general concern this ticket exists to address, but out of this unit's scope.
## Scope fleetd #612 step 2, unit B3 (issue #612 comment 17513) — replaces three `FleetdAssembly.java` source-text guards with tests that drive the real assembled objects through `FleetdAssembly.assembleAndStart(...) -> FleetdRuntime.mcp()`. **Base branch is `worker/fleetd-612-unita-87807e-1`, not `main`** — matches this unit's brief; do not merge this into `main`. ## Disclosure up front: FleetMcp.java accessors are `public`, not package-private The brief's precedent (`registeredTools()`) is package-private, and said to add the new accessors "the same reason" — package-private if possible, and to disclose loudly if not. I could not keep them package-private: my new assembly tests live in package `dev.ltms.fleet` (they must, since they build the `ResourcePorts` that `FleetdAssembly.assembleAndStart` needs, and `ResourcePorts`'s methods return `Fleetd`-nested types only visible from that package), while `FleetMcp` is in `dev.ltms.fleet.mcp`. A package-private accessor there is invisible from `dev.ltms.fleet`. So `quarantineSource()`, `leadSeatSource()` and `leadRollover()` on `FleetMcp` are `public`. Flagging this for whichever other B-unit (B1/B2) touches `FleetMcp.java` or `FleetdRuntime.java` next — no field was added to `FleetdRuntime` itself, per the brief's explicit ban. ## What each deleted guard pinned, and what pins it now - **`FleetdLeadSeatWiringTest`** (fleetd #176) — pinned that `FleetMcp`'s `LeadSeatSource` construction still wires `Fleetd.leadSeatLookup(...)`, by scraping the constructor call's source text. Replaced by **`FleetdLeadSeatAssemblyTest`**: seeds one `FakeHerdr` tab labelled to match a configured `fleet.leaders.opus.tab` (reusing FakeHerdr's own hardcoded default pane/agent — `term_a`/`w2:p7`/`w2:t7` — no FakeHerdr change needed) and asserts the REAL assembled `LeadSeatSource` (`runtime.mcp().leadSeatSource()`) reports the live lead's seat against its own subscription profile: 1, not the 0 `LeadSeatSource.none()` (the inert stand-in) could ever report. - **`FleetdBackendQuarantineWiringTest`** (fleetd #466) — pinned that `BackendQuarantine.withEscalation(...)`'s text was present and the flat two-argument constructor's text was absent. Replaced by **`FleetdBackendQuarantineAssemblyTest`**: quarantines the same credential twice through the REAL assembled `BackendQuarantine` (`runtime.mcp().quarantineSource().quarantine()`) at controlled fake-clock offsets, and asserts the second cooldown doubles (200s vs 100s) — the one behavioural difference escalation and the flat constructor actually produce. - **`FleetdLeadRolloverWiringTest`** (fleetd #480), all three methods: - `unrelatedAnchorStillPresent` was a scaffold anchor with no independent claim — needs no replacement. - `mainStillCallsTheLeadRolloverFactory` pinned the `leadRollover` assignment's call-site text. - `factoryGatesOnConfigPresence` pinned that an absent `leadRollover:` config yields no `LeadRollover`. Replaced by **`FleetdLeadRolloverAssemblyTest`**'s two tests: - `assembledLeadRolloverRunsTheRealClearAndBootstrapSequence` drives the REAL assembled `LeadRollover` (`runtime.mcp().leadRollover()`) through `open()`/`confirm()` end to end and asserts `/clear` then `bootstrapText` were actually sent through the real herdr router, reaching `ROLLED`. - `absentLeadRolloverConfigMeansNoRolloverIsBuilt` calls `Fleetd.leadRollover(...)` directly with no `leadRollover:` block and asserts null. **This claim was found uncovered anywhere else** — `LeadRolloverTest`'s only related assertion is vacuous (`assertNull(null)`) and never calls the real factory. ## Mutation proof — all three call sites, RED then GREEN Each call site in `FleetdAssembly.java` was mutated to its named inert variant, run against ONLY its new test (RED), reverted, `touch`'d (the Maven mtime trap: `git checkout`/`mv` can restore an mtime older than the compiled `.class`, so Maven skips recompiling and silently re-runs the mutant's bytecode), and re-run (GREEN). ### 1. Quarantine — `FleetdAssembly.java:179-180` `BackendQuarantine.withEscalation(ports.nanoClock(), TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds()))` -> `new BackendQuarantine(ports.nanoClock(), TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds()))` (the flat two-arg constructor) RED: ``` Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.696 s <<< FAILURE! dev.ltms.fleet.FleetdBackendQuarantineAssemblyTest.assembledQuarantineEscalatesOnARepeatedExhaustion(Path) -- Time elapsed: 0.683 s <<< FAILURE! org.opentest4j.AssertionFailedError: withEscalation's default backoff doubles the cooldown on the second consecutive exhaustion ... ==> expected: <200> but was: <100> ``` GREEN (after revert + touch): ``` Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.774 s -- in dev.ltms.fleet.FleetdBackendQuarantineAssemblyTest ``` ### 2. Lead seats — `FleetdAssembly.java:479` `new FleetMcp.LeadSeatSource(Fleetd.leadSeatLookup(() -> config.get().profiles(), leaders, leads))` -> `FleetMcp.LeadSeatSource.none()` RED: ``` Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.711 s <<< FAILURE! dev.ltms.fleet.FleetdLeadSeatAssemblyTest.assembledLeadSeatSourceReportsALiveLeadsSeat(Path) -- Time elapsed: 0.701 s <<< FAILURE! org.opentest4j.AssertionFailedError: the real LeadTabScanner recognises the labelled tab as a live 'opus' lead ... ==> expected: <1> but was: <0> ``` GREEN (after revert + touch): ``` Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.829 s -- in dev.ltms.fleet.FleetdLeadSeatAssemblyTest ``` ### 3. Lead rollover — `FleetdAssembly.java:408` `LeadRollover leadRollover = Fleetd.leadRollover(cfg, router.leadAgents(), config, leads);` -> `LeadRollover leadRollover = null;` RED: ``` Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.843 s <<< FAILURE! dev.ltms.fleet.FleetdLeadRolloverAssemblyTest.assembledLeadRolloverRunsTheRealClearAndBootstrapSequence(Path) -- Time elapsed: 0.826 s <<< FAILURE! org.opentest4j.AssertionFailedError: leadRollover: is present in this test's config, so FleetdAssembly.assembleAndStart must have built a real LeadRollover ... ==> expected: not <null> ``` (the sibling `absentLeadRolloverConfigMeansNoRolloverIsBuilt` correctly stayed green here — it calls `Fleetd.leadRollover` directly, not through this mutated call site) GREEN (after revert + touch): ``` Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.614 s -- in dev.ltms.fleet.FleetdLeadRolloverAssemblyTest ``` After every revert: `git diff -- fleetd/src/main/java/dev/ltms/fleet/FleetdAssembly.java` was empty. ## Full build `mvn -o test` in `fleetd/` at the tip of this branch: ``` Tests run: 1879, Failures: 6, Errors: 0, Skipped: 0 BUILD FAILURE ``` Down from this branch's baseline (1880/9) by exactly the 3 guards this unit deletes. The 6 remaining failures are `FleetdCompletionResolverWiringTest` (4), `FleetdConnectionIdentityConstructionTest` (1) and `FleetdFleetAppConstructionTest` (1) — all out of this unit's scope (B1/B2, per issue #612 comment 17513's split). `BUILD FAILURE` is expected and correct until B1/B2 land. ## Caveats for review - `FleetMcp.java`'s three new accessors are `public`, not package-private — see disclosure above. Likely collides with whatever B1/B2 also touch in `FleetMcp.java`. - `FleetdLeadRolloverAssemblyTest`'s happy-path test takes ~2.6s real wall-clock time: the production `LeadRollover` constructor always uses a real virtual thread and real 250ms settle-poll sleeps, and FakeHerdr's agent never reports `WORKING`, so the post-`/clear` wait releases via its 8-poll (~2s) pickup-grace path rather than a real completion boundary. This exercises the full real happy path (both `agent.prompt` sends, ending in `ROLLED`), just not instantaneously. - Not fixed, reported per the brief's "report the shape, don't fix it" instruction: `FleetMcpHandoverTest` (in `dev.ltms.fleet.mcp`) drives `FleetMcp.handover(...)` with a hand-built `LeadRollover`/`FakeHerdr`, not the real assembly — same general concern this ticket exists to address, but out of this unit's scope.
agent added 1 commit 2026-09-22 07:19:30 +02:00
and lead-rollover source-text guards

Replaces three FleetdAssembly.java source-text guards (each scraped
Fleetd.java for a call site that fleetd #612 Unit A moved into
FleetdAssembly.java) with tests that drive the real assembled objects
through FleetdAssembly.assembleAndStart(...) -> FleetdRuntime.mcp(),
per the step-2 B-unit split (issue #612 comment 17513).

- Deleted FleetdLeadSeatWiringTest (fleetd #176): pinned that
  FleetMcp's LeadSeatSource construction still wires
  Fleetd.leadSeatLookup(...) by scraping the constructor call's text.
  Replaced by FleetdLeadSeatAssemblyTest, which seeds one FakeHerdr
  tab labelled to match a configured fleet.leaders.opus.tab and
  asserts the REAL assembled LeadSeatSource (via
  runtime.mcp().leadSeatSource()) reports the live lead's seat against
  its own subscription profile -- 1, not the 0 LeadSeatSource.none()
  (the inert stand-in) could ever report.

- Deleted FleetdBackendQuarantineWiringTest (fleetd #466): pinned that
  the escalating BackendQuarantine.withEscalation(...) text was
  present and the flat two-argument constructor's text was absent.
  Replaced by FleetdBackendQuarantineAssemblyTest, which quarantines
  the same credential twice through the REAL assembled
  BackendQuarantine (via runtime.mcp().quarantineSource().quarantine())
  at controlled fake-clock offsets and asserts the second cooldown
  doubles (200s vs 100s) -- the one behavioural difference escalation
  and the flat constructor actually produce.

- Deleted FleetdLeadRolloverWiringTest (fleetd #480), all three
  methods: unrelatedAnchorStillPresent was a scaffold anchor with no
  independent claim, needing no replacement.
  mainStillCallsTheLeadRolloverFactory pinned the leadRollover
  assignment's call-site text. factoryGatesOnConfigPresence pinned
  that an absent leadRollover: config yields no LeadRollover.
  Replaced by FleetdLeadRolloverAssemblyTest's two tests:
  assembledLeadRolloverRunsTheRealClearAndBootstrapSequence drives the
  REAL assembled LeadRollover (via runtime.mcp().leadRollover())
  through open()/confirm() end to end and asserts /clear then
  bootstrapText were actually sent through the real herdr router,
  reaching ROLLED. absentLeadRolloverConfigMeansNoRolloverIsBuilt
  calls Fleetd.leadRollover(...) directly with no leadRollover: block
  and asserts null -- this claim was found uncovered elsewhere
  (LeadRolloverTest's only related assertion is vacuous, assertNull
  (null), and never calls the real factory).

Each of the three FleetdAssembly.java call sites (quarantine
line 179-180, leadRollover line 408, lead seats line 479) was mutated
to its named inert variant, run against ONLY its new test (RED),
reverted, touch'd (Maven mtime trap) and re-run (GREEN) -- six proven
runs, pasted in the PR body.

FleetMcp.java: adds three accessors (quarantineSource(),
leadSeatSource(), leadRollover()) alongside the existing
registeredTools() -- but public, not package-private, and this is a
deliberate deviation from that precedent, not an oversight: these new
assembly tests cannot live in package dev.ltms.fleet.mcp the way
registeredTools()'s callers do, because they also build the
ResourcePorts FleetdAssembly.assembleAndStart(...) needs, and
ResourcePorts' methods return Fleetd-nested types visible only from
package dev.ltms.fleet. Package-private would compile but be
unreachable from there.

Full mvn -o test in fleetd/: Tests run: 1879, Failures: 6 (down from
the branch baseline's 1880/9 by exactly the 3 guards this unit
deletes) -- the remaining 6 are FleetdCompletionResolverWiringTest (4)
and FleetdConnectionIdentityConstructionTest /
FleetdFleetAppConstructionTest (1 each), all out of this unit's scope
(B1/B2).
agent added 2 commits 2026-09-22 07:31:46 +02:00
Ticket comment 17553 on fleetd #612 found that the test's single shared
FakeHerdr made router.leadAgents() and router.memberAgents() collapse to
the identical client (FleetdAssembly.java:140-142's no-distinct-socket
fallback), so a mutation swapping leadAgents() for memberAgents() at the
FleetdAssembly.java:408 call site was invisible to this test even though
the two are genuinely different daemons in production.

Configure two distinct herdr sockets and two distinct FakeHerdr instances
(the same TwoHerdrResourcePorts shape B2's FleetdAssemblyConnectionIdentityTest
uses) and assert the roll's /clear + bootstrap sends land on the LEAD fake
and never on the MEMBER one.

Proven red against the router.memberAgents() mutation, reverted, touched,
and re-run green — both outputs recorded in the PR.
ltms merged commit 640f4d5f23 into worker/fleetd-612-unita-87807e-1 2026-09-22 07:36:05 +02:00
Sign in to join this conversation.