fleetd #425: fleet_profiles' default and worktree provisioning must read live placement #430

Closed
agent wants to merge 1 commits from worker/425-default-profile-live-f55534-8 into main
Member

What changed

fleetd #425: fleet_profiles' "default" was frozen at daemon boot (CompositePeerLauncher.defaultProfile, captured once from cfg.effectiveDefaultProfile()), while an unqualified fleet_spawn resolves the dev pool LIVE, on every call, via defaultProfileFor(MemberRole.DEV)/poolFor. Reordering fleet.developers and reloading changed where a spawn landed without ever changing what fleet_profiles reported.

Fix 1 (reporting): CompositePeerLauncher.defaultProfile() now delegates to defaultProfileFor(MemberRole.DEV) -- the same live, reload-aware pool read placement already uses -- falling back to the frozen field only when no profiles are configured at all. Per the lead's ruling (not re-opened here): fleet_profiles' "default" reports the live DEV default, not a per-role map, because an unqualified fleet_spawn's role defaults to dev.

PeerLauncher gains a default method defaultProfileFor(MemberRole) so a generic PeerLauncher reference (e.g. in SessionManager) can ask for a role's live default without depending on CompositePeerLauncher directly. Its default implementation delegates to defaultProfile(), for launchers with no pool concept of their own (HerdrPeerLauncher alone, never reached this way in production).

Fix 2 (worktree provisioning), chosen option -- resolve once, spawn with the same name: SessionManager.acquireWithWorktree used to resolve a profile via launcher.defaultProfile() (DEV-only) to provision repoRoot/parityOverlay, then spawn using the ORIGINAL (possibly blank) profile parameter, which independently re-resolves via placement. For any non-DEV role, or across a config reload between the two reads, the two resolutions could disagree, provisioning a worktree (repo root, parity-overlay files) for a profile the member never actually runs on.

I took Option 1: resolve preResolvedProfile once via launcher.defaultProfileFor(memberRole) (the caller's actual role, not always DEV), and reuse that exact name for repoRoot, parityOverlay, AND the spawn call itself. I chose this over "provision the overlay after placement has chosen" because provisioning-after-spawn would mean the worktree doesn't exist yet when the member's process starts, which is a bigger restructure of the spawn lifecycle than this ticket's scope: the fix here does not change when the worktree exists relative to spawn, only which profile name every step agrees on.

Trade-off, stated honestly: the worktree-provisioned unqualified spawn is now a single explicit-profile spawn, so it loses CompositePeerLauncher's cross-candidate retry on PeerUnreachableException (an explicit profile bypasses placement's retry-across-pool). I judged this acceptable: a worktree provisioned for the wrong backend (the #425 hazard) is worse than a spawn that fails cleanly and can be retried by the caller.

Caveat: weighted/round-robin placement

defaultProfileFor/defaultProfile is exact only under the fixed placement policy (the default), which reads roleDefault as its first preferred candidate. weighted/round-robin policies can pick a different candidate from the pool even on the very first spawn; this fix does not simulate that choice -- it matches what the old defaultProfile:-derived reporting always did (report the configured default, not a placement simulation). Not treated as a defect in this ticket; noting it for review.

Mutation-proof results (mandatory)

One mutation at a time, applied and reverted:

A -- put the frozen field back in the reporting accessor (defaultProfile() reverted to return the frozen defaultProfile field instead of defaultProfileFor(MemberRole.DEV)): CompositePeerLauncherTest.defaultProfileTracksALiveDevPoolReorderAfterReload failed:

expected: <sonnet> but was: <opus>

(the reported default did not follow the reorder). FleetProfilesLiveDefaultTest.fleetProfilesDefaultTracksALiveDevPoolReorderAfterReload failed the same way at the fleet_profiles' "default" assertion. Reverted.

B -- make the accessor always return the live pool's first entry with no empty-pool fallback (defaultProfileFor changed to poolFor(role).getFirst() unconditionally, dropping the pool.isEmpty() ? defaultProfile : ... guard): CompositePeerLauncherTest.defaultProfileFallsBackToTheFrozenFieldWhenNothingIsConfiguredAtAll failed with a NoSuchElementException from List.getFirst() on the empty pool, instead of returning "opus". Reverted.

C -- revert the worktree fix (preResolvedProfile computed via launcher.defaultProfile() instead of launcher.defaultProfileFor(memberRole), and the spawn call passed the original profile instead of preResolvedProfile): SessionManagerTest.acquireWithWorktreeForANonDevRoleUsesThatRolesPoolNotTheDevPool failed:

the worktree must be provisioned with profile b's overlay -- the ARCHITECT pool's answer, the one actually spawned -- never a's, the DEV pool's answer that launcher.defaultProfile() alone would have given ==> expected: <[b.mcp.json]> but was: <[a.mcp.json]>

Reverted. Note: an earlier reorder-only test for criterion 3 (acquireWithWorktreeProvisionsTheOverlayForTheProfileActuallySpawned) did NOT catch this mutation, because for a DEV-role request launcher.defaultProfile() (post-fix-1) already agrees with defaultProfileFor(DEV) live -- no divergence is observable without a genuine role mismatch. Kept both tests: the reorder test for general hot-reload-through-worktree regression coverage, and the role-mismatch test as the actual load-bearing mutation-C-catching test.

Build

mvn clean install run unpiped from the fleetd/ directory:

Tests run: 1514, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

Out of scope (not touched, per brief)

  • HerdrPeerLauncher's own per-adapter frozen defaultProfile field. My view: I believe it IS dead in production as the ticket states, on the evidence I read -- CompositePeerLauncher is the only production caller I found that reaches a HerdrPeerLauncher, and it always calls spawn/effectiveCwd/parityOverlay with an explicit profile it resolved itself (via poolFor/defaultProfileFor), never relying on the adapter's own defaultProfile(). The one gap I could not fully close by reading alone: I did not find every test double or future caller that might construct a bare HerdrPeerLauncher and call defaultProfile() on it directly (some test files do, e.g. wiring tests), so "unreachable in production" is a narrower and safer claim than "unreachable, full stop" -- I'd remove it only after a search confirms zero non-test callers, which I did not do since it's out of scope here.
  • MemberRegistry architect-slot freeze (#424) -- untouched.
  • ConfigRef's fleet: split-key reporting -- untouched.
  • FleetHealthMonitor.coverage wording and CompletionResolver -- untouched.

On the lead's DEV-default ruling

I agree with it and did not re-open it. The reasoning holds: SpawnRequest's role defaults to MemberRole.DEV, so "the dev pool's live first entry" is exactly what an unqualified fleet_spawn lands on, and keeping fleet_profiles' "default" field a single string (not a per-role map) matches its existing shape/type with no breaking change to consumers.

## What changed fleetd #425: `fleet_profiles`' `"default"` was frozen at daemon boot (`CompositePeerLauncher.defaultProfile`, captured once from `cfg.effectiveDefaultProfile()`), while an unqualified `fleet_spawn` resolves the dev pool LIVE, on every call, via `defaultProfileFor(MemberRole.DEV)`/`poolFor`. Reordering `fleet.developers` and reloading changed where a spawn landed without ever changing what `fleet_profiles` reported. **Fix 1 (reporting):** `CompositePeerLauncher.defaultProfile()` now delegates to `defaultProfileFor(MemberRole.DEV)` -- the same live, reload-aware pool read placement already uses -- falling back to the frozen field only when no profiles are configured at all. Per the lead's ruling (not re-opened here): `fleet_profiles`' `"default"` reports the live **DEV** default, not a per-role map, because an unqualified `fleet_spawn`'s role defaults to `dev`. `PeerLauncher` gains a `default` method `defaultProfileFor(MemberRole)` so a generic `PeerLauncher` reference (e.g. in `SessionManager`) can ask for a role's live default without depending on `CompositePeerLauncher` directly. Its default implementation delegates to `defaultProfile()`, for launchers with no pool concept of their own (`HerdrPeerLauncher` alone, never reached this way in production). **Fix 2 (worktree provisioning), chosen option -- resolve once, spawn with the same name:** `SessionManager.acquireWithWorktree` used to resolve a profile via `launcher.defaultProfile()` (DEV-only) to provision `repoRoot`/`parityOverlay`, then spawn using the ORIGINAL (possibly blank) `profile` parameter, which independently re-resolves via placement. For any non-DEV role, or across a config reload between the two reads, the two resolutions could disagree, provisioning a worktree (repo root, parity-overlay files) for a profile the member never actually runs on. I took **Option 1**: resolve `preResolvedProfile` once via `launcher.defaultProfileFor(memberRole)` (the caller's actual role, not always DEV), and reuse that exact name for `repoRoot`, `parityOverlay`, AND the spawn call itself. I chose this over "provision the overlay after placement has chosen" because provisioning-after-spawn would mean the worktree doesn't exist yet when the member's process starts, which is a bigger restructure of the spawn lifecycle than this ticket's scope: the fix here does not change when the worktree exists relative to spawn, only which profile name every step agrees on. **Trade-off, stated honestly:** the worktree-provisioned unqualified spawn is now a single explicit-profile spawn, so it loses `CompositePeerLauncher`'s cross-candidate retry on `PeerUnreachableException` (an explicit profile bypasses placement's retry-across-pool). I judged this acceptable: a worktree provisioned for the wrong backend (the #425 hazard) is worse than a spawn that fails cleanly and can be retried by the caller. ## Caveat: weighted/round-robin placement `defaultProfileFor`/`defaultProfile` is exact only under the `fixed` placement policy (the default), which reads `roleDefault` as its first preferred candidate. `weighted`/`round-robin` policies can pick a different candidate from the pool even on the very first spawn; this fix does not simulate that choice -- it matches what the old `defaultProfile:`-derived reporting always did (report the configured default, not a placement simulation). Not treated as a defect in this ticket; noting it for review. ## Mutation-proof results (mandatory) One mutation at a time, applied and reverted: **A -- put the frozen field back in the reporting accessor** (`defaultProfile()` reverted to return the frozen `defaultProfile` field instead of `defaultProfileFor(MemberRole.DEV)`): `CompositePeerLauncherTest.defaultProfileTracksALiveDevPoolReorderAfterReload` failed: ``` expected: <sonnet> but was: <opus> ``` (the reported default did not follow the reorder). `FleetProfilesLiveDefaultTest.fleetProfilesDefaultTracksALiveDevPoolReorderAfterReload` failed the same way at the `fleet_profiles' "default"` assertion. Reverted. **B -- make the accessor always return the live pool's first entry with no empty-pool fallback** (`defaultProfileFor` changed to `poolFor(role).getFirst()` unconditionally, dropping the `pool.isEmpty() ? defaultProfile : ...` guard): `CompositePeerLauncherTest.defaultProfileFallsBackToTheFrozenFieldWhenNothingIsConfiguredAtAll` failed with a `NoSuchElementException` from `List.getFirst()` on the empty pool, instead of returning `"opus"`. Reverted. **C -- revert the worktree fix** (`preResolvedProfile` computed via `launcher.defaultProfile()` instead of `launcher.defaultProfileFor(memberRole)`, and the spawn call passed the original `profile` instead of `preResolvedProfile`): `SessionManagerTest.acquireWithWorktreeForANonDevRoleUsesThatRolesPoolNotTheDevPool` failed: ``` the worktree must be provisioned with profile b's overlay -- the ARCHITECT pool's answer, the one actually spawned -- never a's, the DEV pool's answer that launcher.defaultProfile() alone would have given ==> expected: <[b.mcp.json]> but was: <[a.mcp.json]> ``` Reverted. Note: an earlier reorder-only test for criterion 3 (`acquireWithWorktreeProvisionsTheOverlayForTheProfileActuallySpawned`) did NOT catch this mutation, because for a DEV-role request `launcher.defaultProfile()` (post-fix-1) already agrees with `defaultProfileFor(DEV)` live -- no divergence is observable without a genuine role mismatch. Kept both tests: the reorder test for general hot-reload-through-worktree regression coverage, and the role-mismatch test as the actual load-bearing mutation-C-catching test. ## Build `mvn clean install` run unpiped from the `fleetd/` directory: ``` Tests run: 1514, Failures: 0, Errors: 0, Skipped: 0 BUILD SUCCESS ``` ## Out of scope (not touched, per brief) - `HerdrPeerLauncher`'s own per-adapter frozen `defaultProfile` field. My view: I believe it IS dead in production as the ticket states, on the evidence I read -- `CompositePeerLauncher` is the only production caller I found that reaches a `HerdrPeerLauncher`, and it always calls `spawn`/`effectiveCwd`/`parityOverlay` with an explicit profile it resolved itself (via `poolFor`/`defaultProfileFor`), never relying on the adapter's own `defaultProfile()`. The one gap I could not fully close by reading alone: I did not find every test double or future caller that might construct a bare `HerdrPeerLauncher` and call `defaultProfile()` on it directly (some test files do, e.g. wiring tests), so "unreachable in production" is a narrower and safer claim than "unreachable, full stop" -- I'd remove it only after a search confirms zero non-test callers, which I did not do since it's out of scope here. - `MemberRegistry` architect-slot freeze (#424) -- untouched. - `ConfigRef`'s `fleet:` split-key reporting -- untouched. - `FleetHealthMonitor.coverage` wording and `CompletionResolver` -- untouched. ## On the lead's DEV-default ruling I agree with it and did not re-open it. The reasoning holds: `SpawnRequest`'s role defaults to `MemberRole.DEV`, so "the dev pool's live first entry" is exactly what an unqualified `fleet_spawn` lands on, and keeping `fleet_profiles`' `"default"` field a single string (not a per-role map) matches its existing shape/type with no breaking change to consumers.
agent added 1 commit 2026-09-10 07:24:33 +02:00
fleetd #425: fleet_profiles' default and worktree provisioning must read live placement
CI / build (pull_request) Successful in 1m29s
CI / contract (pull_request) Successful in 1m32s
e1d7ddeabb
fleet_profiles' "default" was CompositePeerLauncher.defaultProfile, a value
frozen at construction from cfg.effectiveDefaultProfile(). An unqualified
fleet_spawn instead resolves the dev pool live via defaultProfileFor(DEV) on
every call, so reordering fleet.developers and reloading changed where a
spawn landed without ever changing what fleet_profiles reported.

- CompositePeerLauncher.defaultProfile() now delegates to
  defaultProfileFor(MemberRole.DEV) -- the same live, reload-aware pool read
  placement already uses -- falling back to the frozen field only when no
  profiles are configured at all.
- PeerLauncher gains a default defaultProfileFor(MemberRole) method so a
  generic PeerLauncher reference can ask for a role's live default; the
  default implementation delegates to defaultProfile() for launchers with no
  pool concept of their own.
- SessionManager.acquireWithWorktree resolved a profile via
  launcher.defaultProfile() (DEV-only) to provision repoRoot/parityOverlay,
  then spawned with the original (possibly blank) profile, which re-resolves
  independently through placement -- for any non-DEV role, or across a config
  reload between the two reads, the two resolutions could disagree and
  provision a worktree for a profile the member never runs on. Fixed by
  resolving once, through defaultProfileFor(the caller's actual role), and
  reusing that same resolved name for repoRoot, parityOverlay, and the spawn
  itself. Trade-off: this path now spawns with an explicit profile rather
  than a blank one, so it loses CompositePeerLauncher's cross-candidate retry
  on PeerUnreachableException -- accepted because a worktree provisioned for
  the wrong backend is worse than a spawn that fails cleanly and can be
  retried.

Tests: CompositePeerLauncherTest (live dev-pool reorder + empty-pool
fallback), FleetProfilesLiveDefaultTest (drives FleetMcp.profilesView
directly), SessionManagerTest (worktree overlay follows a reorder, and a
non-DEV role's worktree spawn uses that role's pool, not DEV's).
Owner

Not merging this yet. The reporting half is right and I want it. The SessionManager half introduces a regression that is bigger than the one the commit message owns up to.

Your build claim checks out — I ran it myself: Tests run: 1514, Failures: 0, Errors: 0, Skipped: 0, 0 compile errors, BUILD SUCCESS.

The regression

The commit message says the cost is losing "CompositePeerLauncher's cross-candidate retry on PeerUnreachableException". That is one of four things lost, and the smallest.

CompositePeerLauncher.spawn has two branches. The explicit-profile branch throws:

enforceNotQuarantined(requestedProfile);
enforceNotCoolingOff(requestedProfile);
enforceMaxLoad(requestedProfile);
enforceModelEnabled(requestedProfile);   // added by #429, merged today

The placement branch routes around the same conditions, by building quarantined/coolingOff/modelOff sets and letting the policy skip them.

acquireWithWorktree used to pass a blank profile, so it got the routing branch. It now passes defaultProfileFor(memberRole), so it gets the throwing branch. And defaultProfileFor is blind to every one of those conditions — it returns pool.getFirst().

Proof

A probe in your own worktree, on the default fixed() policy, with sol quarantined and b free:

half 1 — blank profile (what acquireWithWorktree passed before this PR)
  PASS: expected b, got b        // fixed placement routes around the quarantined default

half 2 — defaultProfileFor(DEV) (what it passes now)
  resolved = "sol"              // quarantine-blind, as expected
  ERROR: dev.ltms.fleet.placement.PlacementException:
    worker profile 'sol' is quarantined (credential 'shared-openai' exhausted;
    ~1800s remaining) — refusing spawn

Same spawn, same config. Before: it lands on b. After: it fails.

Note FixedPlacementPolicy's fast path already checks quarantined, coolingOff, unreachable and weight-0, so this is not a weighted-only concern — it hits the default policy.

Why this matters more as of today

#429 merged a few minutes ago and added enforceModelEnabled to that explicit branch. The whole point of the models.allow on/off switch is that the operator flips a model off and the fleet keeps working on the profiles that are still on. With this PR as written, an unqualified worktree spawn whose pool-first profile names an off model gets a hard PlacementException instead of routing to an enabled profile — the gate stops being a switch and becomes an outage.

Scope, stated honestly: this only bites spawns that name no profile. A fleet_spawn{profile:"sonnet", worktree:true} is unaffected, because preResolvedProfile is then just the caller's own profile.

What I think the fix is

The bug you found is real — provisioning repoRoot/parityOverlay for one profile and spawning on another is a genuine defect, and resolving once is the right shape. The mistake is resolving through defaultProfileFor, which answers a different question: "what is first in the pool", not "where would this spawn actually land".

So the launcher needs a way to run placement without spawning — the same candidate list, the same quarantined/coolingOff/modelOff/unreachable sets, the same policy — and return the chosen profile. acquireWithWorktree then uses that one answer for repoRoot, parityOverlay and the spawn. One resolution, and the exclusions survive.

Please keep the defaultProfile()/defaultProfileFor()/PeerLauncher half exactly as it is; that part I verified and want. Rework only acquireWithWorktree.

Acceptance, so it does not come back with the same hole:

  1. A test at the CompositePeerLauncher level: an unqualified worktree-shaped spawn whose pool-first profile is quarantined lands on the next candidate, under PlacementPolicies.fixed() — not weighted().
  2. The same test for a model-off pool-first profile, under fixed().
  3. A test that repoRoot/parityOverlay and the spawn all name that same routed profile — the defect you originally found, now proven on the routed path rather than the first-in-pool path.
  4. A mutation proof per site, printing the method name, the before/after occurrence count, and the count of every other similar site in the file.
Not merging this yet. The reporting half is right and I want it. The `SessionManager` half introduces a regression that is bigger than the one the commit message owns up to. Your build claim checks out — I ran it myself: `Tests run: 1514, Failures: 0, Errors: 0, Skipped: 0`, 0 compile errors, BUILD SUCCESS. ## The regression The commit message says the cost is losing "`CompositePeerLauncher`'s cross-candidate retry on `PeerUnreachableException`". That is one of four things lost, and the smallest. `CompositePeerLauncher.spawn` has two branches. The explicit-profile branch **throws**: ```java enforceNotQuarantined(requestedProfile); enforceNotCoolingOff(requestedProfile); enforceMaxLoad(requestedProfile); enforceModelEnabled(requestedProfile); // added by #429, merged today ``` The placement branch **routes around** the same conditions, by building `quarantined`/`coolingOff`/`modelOff` sets and letting the policy skip them. `acquireWithWorktree` used to pass a blank profile, so it got the routing branch. It now passes `defaultProfileFor(memberRole)`, so it gets the throwing branch. And `defaultProfileFor` is blind to every one of those conditions — it returns `pool.getFirst()`. ## Proof A probe in your own worktree, on the default `fixed()` policy, with `sol` quarantined and `b` free: ``` half 1 — blank profile (what acquireWithWorktree passed before this PR) PASS: expected b, got b // fixed placement routes around the quarantined default half 2 — defaultProfileFor(DEV) (what it passes now) resolved = "sol" // quarantine-blind, as expected ERROR: dev.ltms.fleet.placement.PlacementException: worker profile 'sol' is quarantined (credential 'shared-openai' exhausted; ~1800s remaining) — refusing spawn ``` Same spawn, same config. Before: it lands on `b`. After: it fails. Note `FixedPlacementPolicy`'s fast path already checks `quarantined`, `coolingOff`, `unreachable` and weight-0, so this is not a `weighted`-only concern — it hits the default policy. ## Why this matters more as of today #429 merged a few minutes ago and added `enforceModelEnabled` to that explicit branch. The whole point of the `models.allow` on/off switch is that the operator flips a model off and the fleet keeps working on the profiles that are still on. With this PR as written, an unqualified worktree spawn whose pool-first profile names an off model gets a hard `PlacementException` instead of routing to an enabled profile — the gate stops being a switch and becomes an outage. Scope, stated honestly: this only bites spawns that name **no** profile. A `fleet_spawn{profile:"sonnet", worktree:true}` is unaffected, because `preResolvedProfile` is then just the caller's own profile. ## What I think the fix is The bug you found is real — provisioning `repoRoot`/`parityOverlay` for one profile and spawning on another is a genuine defect, and resolving once is the right shape. The mistake is resolving through `defaultProfileFor`, which answers a different question: "what is first in the pool", not "where would this spawn actually land". So the launcher needs a way to run placement **without** spawning — the same candidate list, the same `quarantined`/`coolingOff`/`modelOff`/`unreachable` sets, the same policy — and return the chosen profile. `acquireWithWorktree` then uses that one answer for `repoRoot`, `parityOverlay` and the spawn. One resolution, and the exclusions survive. Please keep the `defaultProfile()`/`defaultProfileFor()`/`PeerLauncher` half exactly as it is; that part I verified and want. Rework only `acquireWithWorktree`. Acceptance, so it does not come back with the same hole: 1. A test at the `CompositePeerLauncher` level: an unqualified worktree-shaped spawn whose pool-first profile is **quarantined** lands on the next candidate, under `PlacementPolicies.fixed()` — not `weighted()`. 2. The same test for a **model-off** pool-first profile, under `fixed()`. 3. A test that `repoRoot`/`parityOverlay` and the spawn all name that **same** routed profile — the defect you originally found, now proven on the routed path rather than the first-in-pool path. 4. A mutation proof per site, printing the method name, the before/after occurrence count, and the count of every other similar site in the file.
Owner

Closing this in favour of PR #433, which reworks the same ticket.

Recap of why this one was rejected, so it is not re-tried: resolving acquireWithWorktree's profile through launcher.defaultProfileFor(memberRole) moved the caller from the routing branch of CompositePeerLauncher.spawn to the throwing branch. A blank profile goes to placement, which builds quarantined/coolingOff/modelOff and routes around them; a named profile hits enforceNotQuarantined/enforceNotCoolingOff/enforceMaxLoad/enforceModelEnabled, each of which throws. So pre-resolving the name turned a quarantined pool-first profile from "routed around" into a hard spawn failure. Proved with the PR's own wiring: blank profile → b; defaultProfileFor(DEV) → PlacementException: worker profile 'sol' is quarantined.

The reporting half of this PR — fleet_profiles' default reading live placement — was right and is carried over into #433.

The general lesson, for anyone reading this later: when a fix computes a value earlier so that two consumers agree on it, ask which branch that value now takes. Resolving an input earlier is not a no-op; here it changed which validation ran.

#433 is not merged either yet — it closed quarantine, cool-off and model-off but left maxLoad on the throwing side, which is the same shape one filter over. See my comment there and ticket #435.

Closing this in favour of PR #433, which reworks the same ticket. Recap of why this one was rejected, so it is not re-tried: resolving `acquireWithWorktree`'s profile through `launcher.defaultProfileFor(memberRole)` moved the caller from the routing branch of `CompositePeerLauncher.spawn` to the throwing branch. A blank profile goes to placement, which builds `quarantined`/`coolingOff`/`modelOff` and routes *around* them; a named profile hits `enforceNotQuarantined`/`enforceNotCoolingOff`/`enforceMaxLoad`/`enforceModelEnabled`, each of which throws. So pre-resolving the name turned a quarantined pool-first profile from "routed around" into a hard spawn failure. Proved with the PR's own wiring: blank profile → `b`; `defaultProfileFor(DEV)` → `PlacementException: worker profile 'sol' is quarantined`. The reporting half of this PR — `fleet_profiles`' `default` reading live placement — was right and is carried over into #433. The general lesson, for anyone reading this later: when a fix computes a value earlier so that two consumers agree on it, ask which *branch* that value now takes. Resolving an input earlier is not a no-op; here it changed which validation ran. #433 is not merged either yet — it closed quarantine, cool-off and model-off but left `maxLoad` on the throwing side, which is the same shape one filter over. See my comment there and ticket #435.
ltms closed this pull request 2026-09-10 08:27:52 +02:00
Some checks are pending
CI / build (pull_request) Successful in 1m29s
CI / contract (pull_request) Successful in 1m32s

Pull request closed

Sign in to join this conversation.