fleet: is a third split key, sitting in the coverage checker's own escape hatch — and SPLIT_KEYS membership does not prove any reporting code exists #333
Closed
opened 2026-09-04 10:23:45 +02:00 by ltms
·
1 comment
No Branch/Tag Specified
main
worker/fleetd-612-unita-87807e-1
worker/612-b3-mcpwirings-da2b58-3
worker/612-b2-cb185-176d3a-2
worker/612-b1-completion-457459-1
worker/612-agaps-73a926-2
worker/608-sleeps-3a64ff-3
worker/621-b4520b-1
worker/618-b83894-2
worker/fleetd-615-e05481-5
worker/lead-autocompact-5f1ab2-3
worker/fleetd-613-f85deb-3
worker/fleetd-608-flaky-nudge-test-d0c2d1-3
worker/lead-context-gauge-ad404f-1
worker/gauge-wiring-9158c1-4
worker/redeploy-slowstart-ead0e5-5
worker/charter-bytes-13668c-6
worker/rollover-outcome-291483-2
worker/589-f64303-2
worker/593-1a8025-5
worker/589-fcd2aa-1
worker/568-9fdaa2-3
worker/571-attempted-outcome-5739f7-2
worker/581-completionresolver-cas-sites-0542b7-6
worker/562-loop-health-wiring-test-99611c-5
worker/562-surface-loop-health-7df5cc-4
worker/575-waiter-cleanup-sites-62ad80-1
worker/572-answer-lock-release-46a9ae-5
worker/567-probe-channel-leak-a38fc5-6
worker/551-record-before-send-7cbf56-1
worker/561-listener-fanout-survives-a-throw-61d538-2
worker/555-redeploy-main-flow-seam-65c2f5-2
worker/556-injector-owns-registration-e027a5-1
worker/552-post-restart-mktemp-abort-bc2672-4
worker/553-onstatus-completion-leak-0da881-2
worker/550-shasum-linux-196132-1
worker/538-loop-dies-on-error-4a5eeb-6
worker/426-health-coverage-ef1fd4-4
worker/504-failed-reported-clean-3cfd66-3
worker/537-capturedlog-close-e4c437-2
worker/459-broken-link-targets-cadc17-5
worker/535-appender-leak-fe74c1-1
worker/512-part2-shutdown-detection-434701-9
worker/529-logger-level-sweep-2a5533-8
worker/528-drain-gate-call-site-5de83d-7
charter/forge-mcp-vs-token
worker/521-swap-guard-unpinned-28e931-5
worker/519-probe-test-harness-d25ab8-4
worker/525-logger-level-leak-1b4eb0-6
worker/518-fleetmcp-resolver-wiring-8ef96c-1
worker/512-drain-complete-line-7edd71-3
worker/517-abort-branch-and-jar-id-41b641-2
worker/500-9e52c9-3
worker/509-4912f4-2
worker/511-9a4b23-1
worker/493-479f45-2
worker/505-03f8b2-1
worker/492-followup-detect-unclear
worker/501-a31fa0-7
worker/498-451d1c-5
worker/494-1015ce-2
worker/492-209647-1
worker/489-001902-2
worker/480-relative-handover-path-906323-1
worker/480-b-handover-skill-45bf1f-5
worker/474-followup-source-pin-f54a55-17
worker/474-charter-check-on-reload-f54a55-17
worker/466-quarantine-repeatcount-report
worker/393-opencode-skill-seeding-71854b-13
worker/469-canonical-tool-names-2a472a-16
worker/466-quarantine-escalation-5ae9c1-15
worker/446-hot-exhausted-pattern-0af580-6
worker/464-charter-tool-name-guard-a85635-12
worker/463-listfleet-default-fails-open-f1c76c-11
worker/458-invariant-5-by-purpose-862f9a-10
worker/439-coordinator-row-gate-bc032a-8
worker/449-herdr-protocol-576015-4
worker/450-abstract-spawn-599e1c-5
worker/437-ack-refuses-177d91-1
worker/444-placement-window-feb56a-2
worker/440-helddurable-derived-d462d7-13
worker/425-rework-placement-resolve-c58ba1-9
worker/421-lead-peek-held-msgs-cdbad2-10
worker/435-fixed-policy-cap-fe11de-12
worker/422-gate-state-observability-9e79d6-11
worker/431-memberregistry-live-readers-cdbad2-10
worker/424-architect-slot-hot-038b41-7
worker/422-model-gate-spawn-c29f48-6
worker/425-default-profile-live-f55534-8
worker/415-coverage-wording-2cbf9c-5
worker/416-3ad1da-1
worker/418-588283-3
worker/deterministic-stamp-race-409-3cb7b6-10
worker/armed-reads-live-config-404-ed931f-9
worker/reply-peer-refusal-391-5a34bd-7
worker/models-allowlist-aa9e9b-3
worker/ttl-stamp-race-399-f1122f-8
worker/scrub-receipt-400-316b3e-5
worker/exhaustion-detection-395-105105-6
worker/scrub-abort-394-316b3e-5
fix/scrub-uid-abort
worker/task-scrub-517574-2
worker/t386-clock-bd5b78-4
worker/t384-scrub-813790-5
worker/t381-cc-748314-2
worker/t373-336973-2
worker/t365-3920c5-3
worker/t358-6e989b-1
worker/t355-8b321c-1
worker/fleetd-369-hermetic-git-tests-e8b19a-3
worker/fleetd-368-stale-lead-binding-f5682e-2
worker/fleetd-360-deploy-units-0d3793-1
worker/359-dead-lead-tabs-f1253b-4
worker/362-worktree-skills-c03e51-3
worker/361-coord-visibility-655144-1
362-plugin-visibility-and-drift
worker/errscan-bed2ca-2
worker/amqp-log-identity-bed2ca-2
worker/withdefaults-guard-561704
worker/sleepguard-82076d-1
worker/fd334-9ee1b6-5
worker/fd348-f1ab27-4
worker/fd335-a71c35-1
worker/fd342-174a17-2
worker/fd345-490d0f-3
worker/fleetd-337-5ec7d4-21
worker/fleetd-341-af5a6b-24
worker/fleetd-339-5ca0a2-23
worker/fleetd-338-83a4a1-22
worker/fleetd-333-281f46-18
worker/fleetd-329-11bdbb-16
worker/fleetd-330-2770fb-17
worker/fix-326-50506e-15
worker/fix-324-3e9bbf-14
worker/fix-323-b8287d-13
worker/fix-316b-bd0860-11
worker/fix-318-76ca36-9
worker/fix-317-486aec-8
worker/fix-315-ce47c5-6
worker/fix-307-275890-6
worker/fix-308-b4f664-7
worker/fix-309-ec3939-8
worker/fix-310-7a3974-9
worker/fix-302-52ad0e-9
worker/fix-298-ce1acb-8
worker/fix-297-66bd11-7
worker/fix-296-104622-6
worker/fix-293-bare-closetab-eb22b5-3
worker/fix-280-gone-ask-lapse-bca98e-2
worker/fix-290-reapidle-guard-coverage-9b0dd1-1
worker/fix-285-trust-seed-8f3565-10
worker/fix-284-backend-error-seat-85912c-11
worker/fix-282-chained-ask-e6d0bb-8
worker/fix-283-teardown-leaks-f40dfa-9
worker/fix-281-pin-handler-actions-4921ac-7
worker/audit-rendezvous-lifecycle-d072ae-2
worker/audit-health-placement-1a2476-6
worker/audit-teardown-exits-e207a5-3
worker/audit-launcher-asymmetry-27e370-4
worker/audit-rest-authz-6ca53c-5
worker/investigate-275-abandon-asking-fdef52-8
worker/fix-274-worktree-leak-b0095d-7
worker/fix-273-exhausted-pattern-9665b5-6
worker/fleetd-267-model-check-bd8068-1
worker/fleetd-131-archunit-18b834-7
worker/fleetd-266-sshagent-rename-a014ff-6
worker/fleetd-184-uid-claim-8e1f31-4
worker/fleetd-184-warn-b381ee-10
worker/fleetd-184-docs-be1d12-9
worker/fleetd-257-9bf010-7
worker/fleetd-103-23a113-6
worker/fleetd-247-342356-5
worker/fleetd-116-04dea8-4
worker/fleetd-252-a830e0-3
worker/fleetd-111-7e8673-9
worker/fleetd-155c-f8ef4b-8
worker/fleetd-176-b928ca-3
worker/fleetd-249-7a7878-2
worker/cb248-composition-root-b-9acdf7-15
worker/cb148-envrc-default-fa6c82-12
worker/cb201-unit5-wiring-6c12e6-8
worker/cb241-fallback-echo-1175e9-11
worker/cb149-trust-dialog-2392a5-9
worker/cb134-148-overlay-visible-c9b986-10
worker/cb234-session-id-keyed-04e1fc-1
worker/cb201-unit3-nudge-abdf5c-6
worker/cb201-unit2-policy-c1102c-5
worker/cb201-unit4-outcome-a13bfa-7
worker/cb201-unit1-classifier-91b9b1-4
worker/cb201-227-refine-831980-3
worker/cb175-model-readback-0f085f-1
worker/cb222-charter-tmpdir-17f013-1
worker/cb226-architect-slot-race-cd3aa8-3
worker/cb224-worktree-root-group-024523-2
worker/cb-123-role-demotion-c600f7-2
worker/cb-219-opencode-roots-1f677e-1
worker/cb214-claude-session-id-b9eab4-4
worker/cb213-zdotdir-wrong-process-dd6de4-3
worker/cb211-exhaustion-classification-9546e0-2
worker/cb137-ambiguous-task-4df3d8-4
worker/cb209-agentsessionid-4dfdb6-2
worker/cb185-hostenvnames-2692b5-3
worker/cb206-opencode-sqlite-128718-2
worker/cb185-worktree-group-fc0c99-1
worker/cb-137-ask-ticket-e7760c-2
worker/cb-172-broker-uri-d36ae4-4
worker/cb-175-model-readback-76ead6-3
worker/cb-161-pane-ancestry-293510-1
worker/cb-164-rebase-885863-8
worker/cb-164-empty-scrape-false-success-1a80af-3
fix/cb-197-ticket-ttl-from-completion
worker/cb-189-remote-url-coverage-4692f3-1
worker/cb-185-blockers-027756-4
worker/cb-192-gap-log-11b631-2
worker/cb-633-fix-5f4396-3
worker/cb185-router-d6436d-3
worker/cb185-router-routing-gaps-9e9d33-3
worker/cb185-paneids-992586-2
worker/cb-633-allow-list-union-ed374b-1
worker/cb-157-credential-in-remote-url-496e44-2
worker/cb-641-health-herdr-evidence-8f1f54-6
worker/cb-640-health-msg-evidence-99c9cd-1
worker/cb-642-fleets-status-skill-bbbc40-5
cb-634-ide-mcp
worker/lead-comms-wiring-c014b9-7
worker/lead-mailbox-c19577-6
worker/autocompact-window-82bc2f-5
worker/cb-634-probe-18056f-4
worker/cb635-broker-urienv
worker/cb-632-config-retry-8e0efa-7
lead/cb-622e-claude-md
lead/cb-622-followup
worker/cb-622a-165dff-1
lead/cb-622d-opencode-mount
worker/cb-622b-717c67-2
worker/cb-622c-ab7759-3
worker/cb-617b2-20ca4b-3
worker/cb-617a-5c2f4a-1
worker/cb596-4e49ef-3
worker/cb586-10500c-1
worker/cb-606-b9343a-25
worker/cb604-1445f8-24
worker/cb582-477374-21
worker/cb584-8c2281-22
worker/cb600-e6b9a9-20
worker/cb602-ce257f-19
worker/cb601-b42837-18
worker/cb598-6c7ba7-17
worker/cb599-740fe4-16
worker/cb597-282224-15
worker/cb590fix-185e9a-10
worker/cb528-recovery-race
worker/cb594-96bead-8
worker/cb590-916766-2
worker/cb527-997d99-3
worker/cb592-env-leak-3cbf9c-1
worker/cb588-async-ticket-nudge-3218f7-5
worker/cb578b-9dcb13-6
worker/cb581-d24826-5
worker/m2-u5-ef8c42-15
worker/cb578a-516499-2
worker/cb576-01a04b-17
worker/cb579-lead-tab-acba06-20
worker/cb580-terminal-health-ed6058-21
worker/cb577-f36fdc-18
worker/cb573b-3db06f-16
worker/cb568c-f36fdc-18
worker/cb568-drop-cause-c3ac1c
worker/cb575-cancelled-notification-c3ac1c
worker/m4-sol-a2cbec-3
worker/cb574-async-ask-c3ac1c
worker/cb573-health-model-8ca857-14
worker/cb572-unknown-target-7f2e35-13
worker/u4-700706-9
worker/u3-b9fcb6-6
worker/u2-ef5b68-4
worker/u1-469dce-1-clean
worker/u1-469dce-1
worker/cb-564-health-events-70cf7e-2
worker/cb-565-recycle-drops-role-98e58f-3
worker/cb-563-missing-reply-df2866-1
worker/cb-562-readiness-gate-silent-6c23c9-3
worker/cb-560-architect-presence-da8155-1
worker/cb-561-architect-silent-off-a71cab-2
worker/cb-548-bind-architect-slot-fe1b8c-1
worker/parity-overlay-settings-5fb711-1
secrets-central-store
cb-559-hot-key-correction
cb-557-fleet-role-pools
worker/cb-553-maxload-explicit-spawn-305ee3-6
worker/cb-551-idle-lead-heartbeat-f1633c-1
worker/cb-544-drain-preserves-worktree-925fad-3
worker/cb-552-docs-sync-1cb9cf-4
worker/cb-548-rendezvous-guard-rebased
worker/cb-548-rendezvous-guard-116b53-10
worker/cb-548-authz-v2-586df6-8
worker/cb-548-authz-264363-5
salvage/cb-528b-codex-home
salvage/cb-528a-codex-launcher
CB-518-primary-flow
feature/peer-launcher-spi
cb-103-injector
v1.1.0
v1.0.0
Labels
Clear labels
blocked
needs-live-proof
ready-to-delegate
silent-default
Cannot start until something else lands. The body says what.
Merged and green, but never shown working on the running daemon. Not the same as done.
Scope, files and acceptance criteria are written. A worker can be briefed from the body alone.
A feature that compiles, passes tests, and ships turned off. Nine recurrences and counting.
No Label
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: fleet/fleetd#333
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
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?
Follow-up to #330. Two findings, one unit. The first is a live under-claim; the second is why the new checker did not catch it.
F1 —
fleet:is split, and it is filed as hotI checked this myself after merging #330:
LeadLaunchertakes aFleetConfigin its constructor, not aSupplier<FleetConfig>.Fleetd.java:281builds the tab→name map from the startup snapshot and never rebuilds it. Sofleet.leadersis frozen, while the role pools,chartersandtabLabelare read live through the supplier onCompositePeerLauncher.That is the same shape as
health:andcoordinator:— read both ways, at different sites.fleet:is a split key.ConfigRef's class doc has said the frozen half out loud for a while: "This does NOT includefleet.leaders:Fleetd.mainreadscfg.fleet().leaders()once at startup ... so a lead added, removed, or re-tab'd underfleet.leadersneeds a restart, the same as any deferred key below." Nobody acted on it.Direction of harm. Today, changing
fleet.leadersin a reload reports nothing — not deferred, not split. The operator is toldconfig reloaded. This is not academic: a lead is found by its tab label, and a lead whose tab no longer matches is demoted to worker and refuses every orchestration call. So the operator edits the tab, seesconfig reloaded, and the lead stays broken with no message saying why.This is the third instance of the same bug — #323 (
worktreeGroup), #326 (primary,configReload), nowfleet.Whose fault it is. Mine. #330's brief listed
fleetunder "Hot" in its known-good starting values and scopedsplitto exactlyhealth/coordinator. The worker corrected me onprofilesand obeyed me onfleet, flagging the caveat in the exclusion set's javadoc — which is exactly what I asked for. So a genuinely split key ended up in the checker's escape hatch, blessed by the checker, on the checker's first commit.Goal: a reload that changes
fleet:reports it honestly — the frozen half needs a restart, the live half already applied.Invariants:
fleet.leaderstake effect live. Rebuilding the tab scanner andLeadLauncheron a running daemon is a separate, larger question. This ticket is about what a reload reports.fleet:really is live. Do not report the whole key as needing a restart.ConfigRefProfileCoverageTest's exclusion-set assertion stays untouched.Mechanism: this one is not a candidate — #330 built the class for it. Move
fleetout ofHOT_EXCLUDED_TOP_LEVEL_KEYSand intoSPLIT_KEYS, with a message naming both halves the wayhealthandcoordinatordo. What is yours to decide: the exact wording of the frozen half. ReadFleetd.java:281-300andLeadLauncherand say what actually needs a restart, rather than copying my summary.Also re-count the buckets and update the class doc's denominator note. It will move from
4 hot-excluded/2 splitto3 hot-excluded/3 split.F2 —
SPLIT_KEYSmembership does not prove any reporting code existsMeasured. I dropped the
coordinatorblock fromchangedSplitKeyswhile leaving"coordinator"inSPLIT_KEYS:Three hand-written behavioural tests caught it. Neither the new coverage test nor the
assertinchangedSplitKeysfired. Both only look one way.So for a future split key, the cheapest way to pass
ConfigRefTopLevelCoverageTestis to add one string to aSetand write no reporting code at all. The checker reads that name as "triaged" and stops. F1 is that failure already:fleetis in a bucket, the checker is green, and the reload says nothing.The same one-way shape is pre-existing, not invented by #330:
assert COLD_KEYS.containsAll(changed)catches "reported but not listed", never "listed but not reported".DEFERRED_TOP_LEVEL_KEYSlives in the test and is a second hand-written copy of whatchangedDeferredKeysdoes. Adding a name there with no matchingifpasses.Goal: for every name in
SPLIT_KEYS,COLD_KEYSand the test's deferred set, prove that changing that key actually produces a report — by name, not by a hand-written test per key.Candidate mechanism, as a candidate only: the reflection machinery is already there.
ConfigRefProfileCoverageTestbuilds one-field mutants of a record viagetDeclaredConstructor(types).newInstance(args). The same trick overFleetConfiggives you "a config where only<key>differs", and thenreload()must name that key in the right list. Decide it yourself and justify it — in particular, whether building a valid alternate value for every nested record type is worth it, or whether a narrower version (split and cold only, where the sets are small) buys most of the value for a fraction of the work. Either answer is fine; say which and why.If you conclude the full version is not worth building, say what it would have caught and what the narrow version misses, and write that into the test's javadoc. #330's checker already does this well — its javadoc states plainly what it cannot prove, and that disclosure is what let me find both of these quickly instead of trusting a green run. Keep that standard.
Order
F1 first — it is a live defect and it is small. F2 is what stops the fourth instance.
Rules
cd fleetd && mvn clean install, unpiped — and quote the realTests run:andBUILDlines. Never read$?after a pipe.git stash— the stash is shared across every worktree here.git worktree removeorgit worktree prune— other workers are live in those directories.git add -A. Never merge.fleetd/fleetd.yamlis gitignored and absent from your worktree. Do not report on its contents.fleet_reply.Already established, do not re-derive
splitmachinery are #330's, merged in7b918c5. Read them; do not redesign them.profilesbelongs in deferred, not hot. #330's worker corrected my list on this and was right.memberCredentials,memberLoginShellandplacementare genuinely hot. Leave them.Merged to
mainasb4f9d7f(--no-ff; the branch was behind main). Follow-up commiteee4d57fixes a doc gap the worker found and correctly left alone.
Build after the merge, unpiped:
Tests run: 1355, Failures: 0, Errors: 0, Skipped: 0,BUILD SUCCESS. (The worker measured 1352 on its branch; the extra three are #329's tests, alreadyon main.)
My own mutations — aimed at the half the worker did not mutate
The worker proved F2 by removing the
coordinatorsplit branch. I mutated the cold halfinstead, then the deferred half.
Mutation U — drop
memberHerdrSocket's branch fromchangedColdKeys, leave it inCOLD_KEYS:The new checker covers the cold half too, and names the key. Reverted.
Mutation V — drop
guard's branch fromchangedDeferredKeys, leaveguardin the deferred set:Nothing failed. The gap the worker declared in its own javadoc is real, and I have now measured
one confirmed instance of it. Opened as #337. Reverted; main is unchanged.
That declaration is the reason this took one command to find. A checker that says plainly what it
does not cover, next to what it does, is worth more than one that quietly covers more. This is the
second time in two tickets that a worker's honest caveat was the fastest route to the next bug.
The doc gap (commit
eee4d57)The class doc's Cold bullet listed four keys;
COLD_KEYShas five —memberHerdrSocket:wasmissing from the prose. The worker spotted it and left it as out of scope, which was right.
I fixed it by pointing the bullet at
COLD_KEYSinstead of re-listing its contents, so the proseand the set cannot drift apart a second time. Re-listing a set in prose next to the set is how this
happened.
What I checked on the worker's own claims
ConfigRefProfileCoverageTestuntouched — confirmed,git diffon it is empty.fleet.leaderswas not made live; only the reload report changed. Confirmed in the diff.Closing. Two fixes in, one measured gap out (#337).