fleetd #612 step 2 unit B2: behavioural replacements for the CB-185 pair #626

Merged
ltms merged 2 commits from worker/612-b2-cb185-176d3a-2 into worker/fleetd-612-unita-87807e-1 2026-09-22 07:19:29 +02:00
Member

fleetd #612 step 2, unit B2 — the CB-185 pair.

Base branch is worker/fleetd-612-unita-87807e-1 (Unit A + A-gaps), not main, per the lead's step 2 dispatch comment.

What this does

Deletes the two source-text guards Unit A broke by moving their scraped call sites out of Fleetd.java into FleetdAssembly.java, replacing each with a behavioural test driving the real assembled graph.

Deleted guard Pinned (by reading Fleetd.java text) Replaced by Now pins (by driving the real object)
FleetdConnectionIdentityConstructionTest "new PaneLocator(herdr, memberHerdr)" present FleetdAssemblyConnectionIdentityTest the real PaneLocator (runtime.mcp().identity().panes()) finds a pane that exists on only the LEAD daemon, and separately one that exists on only the MEMBER daemon
FleetdFleetAppConstructionTest "new FleetApp(herdr, memberHerdr, workers," present FleetdAssemblyFleetAppTest the real Javalin app (runtime.app()) reports GET /healthz as 503 when only the member daemon is down

Mutation proof (acceptance criterion 2)

Identity — FleetdAssembly.java:443-444 reverted to new PaneLocator(memberHerdr), ran only FleetdAssemblyConnectionIdentityTest:

[ERROR] connectionIdentitySearchesTheLeadDaemonNotJustTheMemberOne
expected: <term_a> but was: <null>
Tests run: 3, Failures: 1

Reverted, git diff --stat empty, file touched, re-ran: Tests run: 3, Failures: 0.

FleetApp — FleetdAssembly.java:518 reverted to new FleetApp(herdr, herdr, workers, ..., ran only FleetdAssemblyFleetAppTest:

[ERROR] healthzGoesRedWhenTheMemberDaemonIsDownEvenThoughTheLeadIsUp
expected: <503> but was: <200> — body had no "member" key
Tests run: 2, Failures: 1

Reverted, git diff --stat empty, file touched, re-ran: Tests run: 2, Failures: 0.

Why GET /sessions isn't pinned here too

The deleted FleetdFleetAppConstructionTest's javadoc also named the /sessions merge as a consequence. I could not drive that through the real assembly: /sessions requires Authz.Action.READ, which needs Caller.resolved() — a real positive pid from the assembly's hardcoded new LsofPeerPidLookup(). In an in-process JUnit test the HTTP client and the daemon under test are the same JVM pid, and LsofPeerPidLookup explicitly excludes its own pid, so the resolved pid is always -1 and fleetd #317's fail-closed rule refuses the request (401 unauthenticated) before the route — and its merge — is ever reached. Verified directly (not assumed). Documented in the new test's class javadoc. FleetAppTwoDaemonTest (unchanged, still passing) remains the full behavioural proof that FleetApp itself merges /sessions correctly once given two clients; this PR's /healthz test is what carries the CB-185-via-the-real-assembly claim.

Production accessors added (flagged per brief — not FleetdRuntime)

I could not reach ConnectionIdentity/PaneLocator through runtime.app()/runtime.mcp() alone: identity was a constructor-local variable inside FleetMcp, never stored as a field, and a real MCP/HTTP round trip can't exercise PaneLocator either, for the same in-process-same-pid reason above. I did not touch FleetdRuntime (the brief flagged three workers colliding there). Instead, two small additions:

  • ConnectionIdentity#panes() — returns the PaneLocator it resolves against.
  • FleetMcp#identity() — returns the ConnectionIdentity it was constructed with (now stored as a field; previously only captured by a constructor-local closure).

Both are additive (new field + new getter), placed away from other constructors' argument lists, to minimize collision risk with the B1/B3 units also touching FleetdAssembly-adjacent files.

Build

Baseline on 608e449 (this branch's tip before my change), mvn -o test: Tests run: 1880, Failures: 9, Errors: 0, Skipped: 0 — confirmed to be the same 9 named in the brief.

After this change, full mvn -o test: Tests run: 1883, Failures: 7, Errors: 0, Skipped: 0 — the 7 are exactly FleetdCompletionResolverWiringTest (4), FleetdBackendQuarantineWiringTest, FleetdLeadRolloverWiringTest, FleetdLeadSeatWiringTest (B1's and B3's scope, untouched here).

git status --porcelain is empty of mutation leftovers.

fleetd #612 step 2, unit B2 — the CB-185 pair. Base branch is `worker/fleetd-612-unita-87807e-1` (Unit A + A-gaps), not `main`, per the lead's step 2 dispatch comment. ## What this does Deletes the two source-text guards Unit A broke by moving their scraped call sites out of `Fleetd.java` into `FleetdAssembly.java`, replacing each with a behavioural test driving the real assembled graph. | Deleted guard | Pinned (by reading `Fleetd.java` text) | Replaced by | Now pins (by driving the real object) | |---|---|---|---| | `FleetdConnectionIdentityConstructionTest` | `"new PaneLocator(herdr, memberHerdr)"` present | `FleetdAssemblyConnectionIdentityTest` | the real `PaneLocator` (`runtime.mcp().identity().panes()`) finds a pane that exists on only the LEAD daemon, and separately one that exists on only the MEMBER daemon | | `FleetdFleetAppConstructionTest` | `"new FleetApp(herdr, memberHerdr, workers,"` present | `FleetdAssemblyFleetAppTest` | the real `Javalin` app (`runtime.app()`) reports `GET /healthz` as 503 when only the member daemon is down | ## Mutation proof (acceptance criterion 2) **Identity** — `FleetdAssembly.java:443-444` reverted to `new PaneLocator(memberHerdr)`, ran only `FleetdAssemblyConnectionIdentityTest`: ``` [ERROR] connectionIdentitySearchesTheLeadDaemonNotJustTheMemberOne expected: <term_a> but was: <null> Tests run: 3, Failures: 1 ``` Reverted, `git diff --stat` empty, file touched, re-ran: `Tests run: 3, Failures: 0`. **FleetApp** — `FleetdAssembly.java:518` reverted to `new FleetApp(herdr, herdr, workers, ...`, ran only `FleetdAssemblyFleetAppTest`: ``` [ERROR] healthzGoesRedWhenTheMemberDaemonIsDownEvenThoughTheLeadIsUp expected: <503> but was: <200> — body had no "member" key Tests run: 2, Failures: 1 ``` Reverted, `git diff --stat` empty, file touched, re-ran: `Tests run: 2, Failures: 0`. ## Why `GET /sessions` isn't pinned here too The deleted `FleetdFleetAppConstructionTest`'s javadoc also named the `/sessions` merge as a consequence. I could not drive that through the real assembly: `/sessions` requires `Authz.Action.READ`, which needs `Caller.resolved()` — a real positive pid from the assembly's hardcoded `new LsofPeerPidLookup()`. In an in-process JUnit test the HTTP client and the daemon under test are the same JVM pid, and `LsofPeerPidLookup` explicitly excludes its own pid, so the resolved pid is always -1 and fleetd #317's fail-closed rule refuses the request (401 unauthenticated) before the route — and its merge — is ever reached. Verified directly (not assumed). Documented in the new test's class javadoc. `FleetAppTwoDaemonTest` (unchanged, still passing) remains the full behavioural proof that `FleetApp` itself merges `/sessions` correctly once given two clients; this PR's `/healthz` test is what carries the CB-185-via-the-real-assembly claim. ## Production accessors added (flagged per brief — not `FleetdRuntime`) I could not reach `ConnectionIdentity`/`PaneLocator` through `runtime.app()`/`runtime.mcp()` alone: `identity` was a constructor-local variable inside `FleetMcp`, never stored as a field, and a real MCP/HTTP round trip can't exercise `PaneLocator` either, for the same in-process-same-pid reason above. I did **not** touch `FleetdRuntime` (the brief flagged three workers colliding there). Instead, two small additions: - `ConnectionIdentity#panes()` — returns the `PaneLocator` it resolves against. - `FleetMcp#identity()` — returns the `ConnectionIdentity` it was constructed with (now stored as a field; previously only captured by a constructor-local closure). Both are additive (new field + new getter), placed away from other constructors' argument lists, to minimize collision risk with the B1/B3 units also touching `FleetdAssembly`-adjacent files. ## Build Baseline on `608e449` (this branch's tip before my change), `mvn -o test`: `Tests run: 1880, Failures: 9, Errors: 0, Skipped: 0` — confirmed to be the same 9 named in the brief. After this change, full `mvn -o test`: `Tests run: 1883, Failures: 7, Errors: 0, Skipped: 0` — the 7 are exactly `FleetdCompletionResolverWiringTest` (4), `FleetdBackendQuarantineWiringTest`, `FleetdLeadRolloverWiringTest`, `FleetdLeadSeatWiringTest` (B1's and B3's scope, untouched here). `git status --porcelain` is empty of mutation leftovers.
agent added 1 commit 2026-09-22 07:04:18 +02:00
Deletes the two source-text guards fleetd #612 Unit A broke by moving their
scraped call sites from Fleetd.java into FleetdAssembly.java, replacing each
with a behavioural test that drives the real assembled graph instead.

- FleetdConnectionIdentityConstructionTest pinned that Fleetd.java contained
  "new PaneLocator(herdr, memberHerdr)". Replaced by
  FleetdAssemblyConnectionIdentityTest, which drives the real PaneLocator a
  real FleetdAssembly.assembleAndStart(...) built (reached via
  runtime.mcp().identity().panes(), never a copy) with two distinct FakeHerdr
  daemons, and proves it finds a pane that exists on only one of them —
  first the lead-only case (the CB-185 bug: a lead's own connection going
  unresolvable), then the member-only case, plus a no-match control.

- FleetdFleetAppConstructionTest pinned that Fleetd.java contained
  "new FleetApp(herdr, memberHerdr, workers,". Replaced by
  FleetdAssemblyFleetAppTest, which binds the real Javalin app
  FleetdAssembly built (runtime.app()) to a real ephemeral port and proves
  GET /healthz goes 503 when only the member daemon is down — the consequence
  named in the deleted test's javadoc (a down member daemon invisible behind
  a healthy lead). The GET /sessions merge half of that javadoc could not be
  driven the same way: it requires Authz.Action.READ, which needs a real
  positive pid from the real assembly's hardcoded LsofPeerPidLookup, and an
  in-process test's HTTP client and server share one JVM pid so that pid is
  always -1 (fleetd #317's fail-closed rule then refuses the request before
  the route, and its merge, is ever reached) — documented in the new test's
  javadoc; FleetAppTwoDaemonTest remains the full behavioural proof that
  FleetApp itself merges /sessions correctly given two clients.

Both replacements were proven red today: reverting FleetdAssembly.java:443-444
to "new PaneLocator(memberHerdr)" turns the identity test red (expected
"term_a", got null); reverting :518 to "new FleetApp(herdr, herdr, ..." turns
the app test red (expected 503, got 200 with no "member" key). Both mutations
reverted, tree confirmed clean, and the mutated file touched afterward so
Maven does not skip recompiling a stale .class.

Adds two small production accessors needed to reach the real objects rather
than a copy, since FleetdRuntime may not gain a field (three workers touch
that file): ConnectionIdentity#panes() exposes the PaneLocator it resolves
against, and FleetMcp#identity() exposes the ConnectionIdentity it was built
with (now also stored as a field).

Baseline on 608e449: 1880 tests, 9 failures (the known source-text set).
After this change: 1883 tests, 7 failures — the remaining #248/#176/#466/#480
guards, which are B1's and B3's scope, not this one's.
agent added 1 commit 2026-09-22 07:11:34 +02:00
Per ticket comment 17525: my second independent mutation on
FleetdAssembly.java:518 survived — new FleetApp(memberHerdr, memberHerdr, ...)
(dropping the LEAD client instead of the member one) left both existing
FleetdAssemblyFleetAppTest cases green. That is the symmetric form of the
CB-185 defect (/healthz green while the LEAD daemon is down), and the guard
this PR deletes would have caught it: its positive assertion required the
exact pair "new FleetApp(herdr, memberHerdr, workers,", which does not
survive either daemon being dropped.

Adds healthzGoesRedWhenTheLeadDaemonIsDownEvenThoughTheMemberIsUp, symmetric
to the existing member-down case.

Proven red today: reverting FleetdAssembly.java:518 to
"new FleetApp(memberHerdr, memberHerdr, workers, ..." and running only
FleetdAssemblyFleetAppTest gives Tests run: 3, Failures: 1 — the new case
fails ("expected: <503> but was: <200>", body has no "member" key); the other
two cases stay green. Reverted, git diff --stat empty, file touched, re-ran:
Tests run: 3, Failures: 0.

Full mvn -o test: Tests run: 1884, Failures: 7 (same 7 B1/B3-scope failures
as before this fixup; 1884 = 1883 + 1 new case).
ltms merged commit 14b169c410 into worker/fleetd-612-unita-87807e-1 2026-09-22 07:19:29 +02:00
Sign in to join this conversation.