fleetd #474: ConfigRef.reload() runs the charter tool-surface gate too #475
Closed
agent
wants to merge 4 commits from
worker/474-charter-check-on-reload-f54a55-17 into main
pull from: worker/474-charter-check-on-reload-f54a55-17
merge into: fleet:main
fleet:main
fleet:worker/fleetd-612-unita-87807e-1
fleet:worker/612-b3-mcpwirings-da2b58-3
fleet:worker/612-b2-cb185-176d3a-2
fleet:worker/612-b1-completion-457459-1
fleet:worker/612-agaps-73a926-2
fleet:worker/608-sleeps-3a64ff-3
fleet:worker/621-b4520b-1
fleet:worker/618-b83894-2
fleet:worker/fleetd-615-e05481-5
fleet:worker/lead-autocompact-5f1ab2-3
fleet:worker/fleetd-613-f85deb-3
fleet:worker/fleetd-608-flaky-nudge-test-d0c2d1-3
fleet:worker/lead-context-gauge-ad404f-1
fleet:worker/gauge-wiring-9158c1-4
fleet:worker/redeploy-slowstart-ead0e5-5
fleet:worker/charter-bytes-13668c-6
fleet:worker/rollover-outcome-291483-2
fleet:worker/589-f64303-2
fleet:worker/593-1a8025-5
fleet:worker/589-fcd2aa-1
fleet:worker/568-9fdaa2-3
fleet:worker/571-attempted-outcome-5739f7-2
fleet:worker/581-completionresolver-cas-sites-0542b7-6
fleet:worker/562-loop-health-wiring-test-99611c-5
fleet:worker/562-surface-loop-health-7df5cc-4
fleet:worker/575-waiter-cleanup-sites-62ad80-1
fleet:worker/572-answer-lock-release-46a9ae-5
fleet:worker/567-probe-channel-leak-a38fc5-6
fleet:worker/551-record-before-send-7cbf56-1
fleet:worker/561-listener-fanout-survives-a-throw-61d538-2
fleet:worker/555-redeploy-main-flow-seam-65c2f5-2
fleet:worker/556-injector-owns-registration-e027a5-1
fleet:worker/552-post-restart-mktemp-abort-bc2672-4
fleet:worker/553-onstatus-completion-leak-0da881-2
fleet:worker/550-shasum-linux-196132-1
fleet:worker/538-loop-dies-on-error-4a5eeb-6
fleet:worker/426-health-coverage-ef1fd4-4
fleet:worker/504-failed-reported-clean-3cfd66-3
fleet:worker/537-capturedlog-close-e4c437-2
fleet:worker/459-broken-link-targets-cadc17-5
fleet:worker/535-appender-leak-fe74c1-1
fleet:worker/512-part2-shutdown-detection-434701-9
fleet:worker/529-logger-level-sweep-2a5533-8
fleet:worker/528-drain-gate-call-site-5de83d-7
fleet:charter/forge-mcp-vs-token
fleet:worker/521-swap-guard-unpinned-28e931-5
fleet:worker/519-probe-test-harness-d25ab8-4
fleet:worker/525-logger-level-leak-1b4eb0-6
fleet:worker/518-fleetmcp-resolver-wiring-8ef96c-1
fleet:worker/512-drain-complete-line-7edd71-3
fleet:worker/517-abort-branch-and-jar-id-41b641-2
fleet:worker/500-9e52c9-3
fleet:worker/509-4912f4-2
fleet:worker/511-9a4b23-1
fleet:worker/493-479f45-2
fleet:worker/505-03f8b2-1
fleet:worker/492-followup-detect-unclear
fleet:worker/501-a31fa0-7
fleet:worker/498-451d1c-5
fleet:worker/494-1015ce-2
fleet:worker/492-209647-1
fleet:worker/489-001902-2
fleet:worker/480-relative-handover-path-906323-1
fleet:worker/480-b-handover-skill-45bf1f-5
fleet:worker/474-followup-source-pin-f54a55-17
fleet:worker/466-quarantine-repeatcount-report
fleet:worker/393-opencode-skill-seeding-71854b-13
fleet:worker/469-canonical-tool-names-2a472a-16
fleet:worker/466-quarantine-escalation-5ae9c1-15
fleet:worker/446-hot-exhausted-pattern-0af580-6
fleet:worker/464-charter-tool-name-guard-a85635-12
fleet:worker/463-listfleet-default-fails-open-f1c76c-11
fleet:worker/458-invariant-5-by-purpose-862f9a-10
fleet:worker/439-coordinator-row-gate-bc032a-8
fleet:worker/449-herdr-protocol-576015-4
fleet:worker/450-abstract-spawn-599e1c-5
fleet:worker/437-ack-refuses-177d91-1
fleet:worker/444-placement-window-feb56a-2
fleet:worker/440-helddurable-derived-d462d7-13
fleet:worker/425-rework-placement-resolve-c58ba1-9
fleet:worker/421-lead-peek-held-msgs-cdbad2-10
fleet:worker/435-fixed-policy-cap-fe11de-12
fleet:worker/422-gate-state-observability-9e79d6-11
fleet:worker/431-memberregistry-live-readers-cdbad2-10
fleet:worker/424-architect-slot-hot-038b41-7
fleet:worker/422-model-gate-spawn-c29f48-6
fleet:worker/425-default-profile-live-f55534-8
fleet:worker/415-coverage-wording-2cbf9c-5
fleet:worker/416-3ad1da-1
fleet:worker/418-588283-3
fleet:worker/deterministic-stamp-race-409-3cb7b6-10
fleet:worker/armed-reads-live-config-404-ed931f-9
fleet:worker/reply-peer-refusal-391-5a34bd-7
fleet:worker/models-allowlist-aa9e9b-3
fleet:worker/ttl-stamp-race-399-f1122f-8
fleet:worker/scrub-receipt-400-316b3e-5
fleet:worker/exhaustion-detection-395-105105-6
fleet:worker/scrub-abort-394-316b3e-5
fleet:fix/scrub-uid-abort
fleet:worker/task-scrub-517574-2
fleet:worker/t386-clock-bd5b78-4
fleet:worker/t384-scrub-813790-5
fleet:worker/t381-cc-748314-2
fleet:worker/t373-336973-2
fleet:worker/t365-3920c5-3
fleet:worker/t358-6e989b-1
fleet:worker/t355-8b321c-1
fleet:worker/fleetd-369-hermetic-git-tests-e8b19a-3
fleet:worker/fleetd-368-stale-lead-binding-f5682e-2
fleet:worker/fleetd-360-deploy-units-0d3793-1
fleet:worker/359-dead-lead-tabs-f1253b-4
fleet:worker/362-worktree-skills-c03e51-3
fleet:worker/361-coord-visibility-655144-1
fleet:362-plugin-visibility-and-drift
fleet:worker/errscan-bed2ca-2
fleet:worker/amqp-log-identity-bed2ca-2
fleet:worker/withdefaults-guard-561704
fleet:worker/sleepguard-82076d-1
fleet:worker/fd334-9ee1b6-5
fleet:worker/fd348-f1ab27-4
fleet:worker/fd335-a71c35-1
fleet:worker/fd342-174a17-2
fleet:worker/fd345-490d0f-3
fleet:worker/fleetd-337-5ec7d4-21
fleet:worker/fleetd-341-af5a6b-24
fleet:worker/fleetd-339-5ca0a2-23
fleet:worker/fleetd-338-83a4a1-22
fleet:worker/fleetd-333-281f46-18
fleet:worker/fleetd-329-11bdbb-16
fleet:worker/fleetd-330-2770fb-17
fleet:worker/fix-326-50506e-15
fleet:worker/fix-324-3e9bbf-14
fleet:worker/fix-323-b8287d-13
fleet:worker/fix-316b-bd0860-11
fleet:worker/fix-318-76ca36-9
fleet:worker/fix-317-486aec-8
fleet:worker/fix-315-ce47c5-6
fleet:worker/fix-307-275890-6
fleet:worker/fix-308-b4f664-7
fleet:worker/fix-309-ec3939-8
fleet:worker/fix-310-7a3974-9
fleet:worker/fix-302-52ad0e-9
fleet:worker/fix-298-ce1acb-8
fleet:worker/fix-297-66bd11-7
fleet:worker/fix-296-104622-6
fleet:worker/fix-293-bare-closetab-eb22b5-3
fleet:worker/fix-280-gone-ask-lapse-bca98e-2
fleet:worker/fix-290-reapidle-guard-coverage-9b0dd1-1
fleet:worker/fix-285-trust-seed-8f3565-10
fleet:worker/fix-284-backend-error-seat-85912c-11
fleet:worker/fix-282-chained-ask-e6d0bb-8
fleet:worker/fix-283-teardown-leaks-f40dfa-9
fleet:worker/fix-281-pin-handler-actions-4921ac-7
fleet:worker/audit-rendezvous-lifecycle-d072ae-2
fleet:worker/audit-health-placement-1a2476-6
fleet:worker/audit-teardown-exits-e207a5-3
fleet:worker/audit-launcher-asymmetry-27e370-4
fleet:worker/audit-rest-authz-6ca53c-5
fleet:worker/investigate-275-abandon-asking-fdef52-8
fleet:worker/fix-274-worktree-leak-b0095d-7
fleet:worker/fix-273-exhausted-pattern-9665b5-6
fleet:worker/fleetd-267-model-check-bd8068-1
fleet:worker/fleetd-131-archunit-18b834-7
fleet:worker/fleetd-266-sshagent-rename-a014ff-6
fleet:worker/fleetd-184-uid-claim-8e1f31-4
fleet:worker/fleetd-184-warn-b381ee-10
fleet:worker/fleetd-184-docs-be1d12-9
fleet:worker/fleetd-257-9bf010-7
fleet:worker/fleetd-103-23a113-6
fleet:worker/fleetd-247-342356-5
fleet:worker/fleetd-116-04dea8-4
fleet:worker/fleetd-252-a830e0-3
fleet:worker/fleetd-111-7e8673-9
fleet:worker/fleetd-155c-f8ef4b-8
fleet:worker/fleetd-176-b928ca-3
fleet:worker/fleetd-249-7a7878-2
fleet:worker/cb248-composition-root-b-9acdf7-15
fleet:worker/cb148-envrc-default-fa6c82-12
fleet:worker/cb201-unit5-wiring-6c12e6-8
fleet:worker/cb241-fallback-echo-1175e9-11
fleet:worker/cb149-trust-dialog-2392a5-9
fleet:worker/cb134-148-overlay-visible-c9b986-10
fleet:worker/cb234-session-id-keyed-04e1fc-1
fleet:worker/cb201-unit3-nudge-abdf5c-6
fleet:worker/cb201-unit2-policy-c1102c-5
fleet:worker/cb201-unit4-outcome-a13bfa-7
fleet:worker/cb201-unit1-classifier-91b9b1-4
fleet:worker/cb201-227-refine-831980-3
fleet:worker/cb175-model-readback-0f085f-1
fleet:worker/cb222-charter-tmpdir-17f013-1
fleet:worker/cb226-architect-slot-race-cd3aa8-3
fleet:worker/cb224-worktree-root-group-024523-2
fleet:worker/cb-123-role-demotion-c600f7-2
fleet:worker/cb-219-opencode-roots-1f677e-1
fleet:worker/cb214-claude-session-id-b9eab4-4
fleet:worker/cb213-zdotdir-wrong-process-dd6de4-3
fleet:worker/cb211-exhaustion-classification-9546e0-2
fleet:worker/cb137-ambiguous-task-4df3d8-4
fleet:worker/cb209-agentsessionid-4dfdb6-2
fleet:worker/cb185-hostenvnames-2692b5-3
fleet:worker/cb206-opencode-sqlite-128718-2
fleet:worker/cb185-worktree-group-fc0c99-1
fleet:worker/cb-137-ask-ticket-e7760c-2
fleet:worker/cb-172-broker-uri-d36ae4-4
fleet:worker/cb-175-model-readback-76ead6-3
fleet:worker/cb-161-pane-ancestry-293510-1
fleet:worker/cb-164-rebase-885863-8
fleet:worker/cb-164-empty-scrape-false-success-1a80af-3
fleet:fix/cb-197-ticket-ttl-from-completion
fleet:worker/cb-189-remote-url-coverage-4692f3-1
fleet:worker/cb-185-blockers-027756-4
fleet:worker/cb-192-gap-log-11b631-2
fleet:worker/cb-633-fix-5f4396-3
fleet:worker/cb185-router-d6436d-3
fleet:worker/cb185-router-routing-gaps-9e9d33-3
fleet:worker/cb185-paneids-992586-2
fleet:worker/cb-633-allow-list-union-ed374b-1
fleet:worker/cb-157-credential-in-remote-url-496e44-2
fleet:worker/cb-641-health-herdr-evidence-8f1f54-6
fleet:worker/cb-640-health-msg-evidence-99c9cd-1
fleet:worker/cb-642-fleets-status-skill-bbbc40-5
fleet:cb-634-ide-mcp
fleet:worker/lead-comms-wiring-c014b9-7
fleet:worker/lead-mailbox-c19577-6
fleet:worker/autocompact-window-82bc2f-5
fleet:worker/cb-634-probe-18056f-4
fleet:worker/cb635-broker-urienv
fleet:worker/cb-632-config-retry-8e0efa-7
fleet:lead/cb-622e-claude-md
fleet:lead/cb-622-followup
fleet:worker/cb-622a-165dff-1
fleet:lead/cb-622d-opencode-mount
fleet:worker/cb-622b-717c67-2
fleet:worker/cb-622c-ab7759-3
fleet:worker/cb-617b2-20ca4b-3
fleet:worker/cb-617a-5c2f4a-1
fleet:worker/cb596-4e49ef-3
fleet:worker/cb586-10500c-1
fleet:worker/cb-606-b9343a-25
fleet:worker/cb604-1445f8-24
fleet:worker/cb582-477374-21
fleet:worker/cb584-8c2281-22
fleet:worker/cb600-e6b9a9-20
fleet:worker/cb602-ce257f-19
fleet:worker/cb601-b42837-18
fleet:worker/cb598-6c7ba7-17
fleet:worker/cb599-740fe4-16
fleet:worker/cb597-282224-15
fleet:worker/cb590fix-185e9a-10
fleet:worker/cb528-recovery-race
fleet:worker/cb594-96bead-8
fleet:worker/cb590-916766-2
fleet:worker/cb527-997d99-3
fleet:worker/cb592-env-leak-3cbf9c-1
fleet:worker/cb588-async-ticket-nudge-3218f7-5
fleet:worker/cb578b-9dcb13-6
fleet:worker/cb581-d24826-5
fleet:worker/m2-u5-ef8c42-15
fleet:worker/cb578a-516499-2
fleet:worker/cb576-01a04b-17
fleet:worker/cb579-lead-tab-acba06-20
fleet:worker/cb580-terminal-health-ed6058-21
fleet:worker/cb577-f36fdc-18
fleet:worker/cb573b-3db06f-16
fleet:worker/cb568c-f36fdc-18
fleet:worker/cb568-drop-cause-c3ac1c
fleet:worker/cb575-cancelled-notification-c3ac1c
fleet:worker/m4-sol-a2cbec-3
fleet:worker/cb574-async-ask-c3ac1c
fleet:worker/cb573-health-model-8ca857-14
fleet:worker/cb572-unknown-target-7f2e35-13
fleet:worker/u4-700706-9
fleet:worker/u3-b9fcb6-6
fleet:worker/u2-ef5b68-4
fleet:worker/u1-469dce-1-clean
fleet:worker/u1-469dce-1
fleet:worker/cb-564-health-events-70cf7e-2
fleet:worker/cb-565-recycle-drops-role-98e58f-3
fleet:worker/cb-563-missing-reply-df2866-1
fleet:worker/cb-562-readiness-gate-silent-6c23c9-3
fleet:worker/cb-560-architect-presence-da8155-1
fleet:worker/cb-561-architect-silent-off-a71cab-2
fleet:worker/cb-548-bind-architect-slot-fe1b8c-1
fleet:worker/parity-overlay-settings-5fb711-1
fleet:secrets-central-store
fleet:cb-559-hot-key-correction
fleet:cb-557-fleet-role-pools
fleet:worker/cb-553-maxload-explicit-spawn-305ee3-6
fleet:worker/cb-551-idle-lead-heartbeat-f1633c-1
fleet:worker/cb-544-drain-preserves-worktree-925fad-3
fleet:worker/cb-552-docs-sync-1cb9cf-4
fleet:worker/cb-548-rendezvous-guard-rebased
fleet:worker/cb-548-rendezvous-guard-116b53-10
fleet:worker/cb-548-authz-v2-586df6-8
fleet:worker/cb-548-authz-264363-5
fleet:salvage/cb-528b-codex-home
fleet:salvage/cb-528a-codex-launcher
fleet:CB-518-primary-flow
fleet:feature/peer-launcher-spi
fleet:cb-103-injector
No Reviewers
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#475
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 "worker/474-charter-check-on-reload-f54a55-17"
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?
Closes fleetd #474.
The gap
Fleetd.mainrefuses to start when a launch charter names an MCP tool the server does not register (#469,CharterToolSurface.assertChartersNameOnlyRegisteredTools, called right aftercfg.validateAll()).ConfigRef.reload()only ranfresh.validateAll(), which never looks at what a charter's text names (only that the key is a role wire name and the text is non-blank) — so the identical bad charter that refuses startup could be installed into a running daemon through a reload, and the next spawned member for that role would get a charter naming a tool that does not exist.The fix
CharterToolSurfacestays indev.ltms.fleet.mcpon purpose (config loads before the MCP server exists, soFleetConfig/dev.ltms.fleet.configmust not depend onmcp) — that design constraint was not revisited.ConfigRefgains aConsumer<FleetConfig> extraValidationfield and a 3-arg constructor.reload()callsextraValidation.accept(fresh)right afterfresh.validateAll(), inside the same try/catch, so either failure refuses the whole reload and keeps the running config. The existing 2-arg constructor (every other caller/test) gets a no-op consumer, so nothing else changes behaviour.Fleetd.javagets a new package-private adapter,Fleetd.assertChartersNameOnlyRegisteredTools(FleetConfig), wrapping the existingCharterToolSurfacecall. The startup call site now goes through this method, andFleetd.mainwiresFleetd::assertChartersNameOnlyRegisteredToolsintoConfigRef's constructor asextraValidation— so both the startup and reload call sites run the exact same method and can never drift apart.Acceptance criteria (ticket #474)
ConfigRefTest.aReloadRefusesACharterNamingAnUnregisteredToolandFleetdConfigRefCharterToolSurfaceWiringTest.reloadRefusesACharterNamingAnUnregisteredToolThroughFleetdsOwnWiring.ConfigRef.reload(), neverCharterToolSurface.assertChartersNameOnlyRegisteredToolsdirectly.ConfigRefTest.aReloadAcceptsACharterNamingOnlyRegisteredToolsand the wiring test'sreloadAcceptsACharterNamingOnlyRegisteredToolsThroughFleetdsOwnWiring.extraValidation.accept(fresh);fromConfigRef.reload()and ranmvn test -Dtest='ConfigRefTest,FleetdConfigRefCharterToolSurfaceWiringTest'. Result:Tests run: 30, Failures: 2—ConfigRefTest.aReloadRefusesACharterNamingAnUnregisteredToolandFleetdConfigRefCharterToolSurfaceWiringTest.reloadRefusesACharterNamingAnUnregisteredToolThroughFleetdsOwnWiringboth failed by name (expected: <false> but was: <true>). Restored the line afterward;git diff --statonConfigRef.javashows a clean 40-line addition with no leftover artifact.FleetConfigstill has no dependency onmcp— checked withgrep -n "import dev.ltms.fleet.mcp" fleetd/src/main/java/dev/ltms/fleet/config/FleetConfig.java(no match) and the same forConfigRef.java(no match — the twodev.ltms.fleet.mcp.CharterToolSurfacementions there are inside{@code}javadoc text, not imports).ConfigRef.java's only new import isjava.util.function.Consumer.Build
Ran
mvn clean installinfleetd/, output captured to a file (never piped), exit code read separately from the file, not assumed from a truncated tail.435e022):Tests run: 1618, Failures: 0, Errors: 0, Skipped: 0—BUILD SUCCESS—EXIT_CODE=0.Tests run: 1622, Failures: 0, Errors: 0, Skipped: 0—BUILD SUCCESS—EXIT_CODE=0.ConfigRefTest, 2 inFleetdConfigRefCharterToolSurfaceWiringTest).Extra criterion 7 (does a refused reload keep the running config?)
Yes.
extraValidation.accept(fresh)runs insidereload()'s existing try/catch, the same onefresh.validateAll()already uses — an exception there is caught, logged, andOutcome.failed(msg)is returned without ever callingcurrent.set(fresh). Both new "refuses" tests assertassertSame(before, ref.get())/assertSame(before, config.get())after the refusal, and both pass in the full suite above.Files changed
fleetd/src/main/java/dev/ltms/fleet/config/ConfigRef.java—extraValidationfield, 3-arg constructor,reload()call site, class-doc addition.fleetd/src/main/java/dev/ltms/fleet/Fleetd.java— newassertChartersNameOnlyRegisteredTools(FleetConfig)adapter; startup call site andConfigRefconstruction both route through it.fleetd/src/main/java/dev/ltms/fleet/mcp/CharterToolSurface.java— class-doc update describing the second call site.fleetd/src/test/java/dev/ltms/fleet/config/ConfigRefTest.java— two new tests (refuse/accept), using a locally-builtConsumer<FleetConfig>equivalent toFleetd's (package-private, not visible fromdev.ltms.fleet.config).fleetd/src/test/java/dev/ltms/fleet/FleetdConfigRefCharterToolSurfaceWiringTest.java(new) — same two proofs, through the literalFleetd::assertChartersNameOnlyRegisteredToolsreference production uses.Not run / caveats
wiki/is uninitialized in this worker's worktree —git submodule statusshows a leading-). Not claiming it passed.fleetd.yamlin this worktree (gitignored) — reproduced the live config shape entirely in@TempDirfixtures, per the existingConfigRefTest/FleetdStartupValidationTestpattern.Landed as
4466ee0, and I am leaving this PR open — I have sent you a follow-up on the same branch, so a new commit belongs here rather than in a new PR.Cherry-picked, not merged
Your commit
97e4c1dsits on435e022, which is not an ancestor ofmain. That is my fault, not yours: I reset and rewrote that commit's message for a different ticket while you were already branched from it. Merging your branch would have added a second merge commit for work already on main, andgit diff origin/main...HEADwarnedmultiple merge baseswith a diffstat naming files you never touched. That is also why this PR reports 9 changed files andmergeable: false.git cherry-pick -x 97e4c1dgave the same content with no duplicated history: 5 files, 292 insertions, 4 deletions — identical to your own diffstat. The rule I took from it: once a worker is spawned, its base commit is published.Your report checked
Your delta claim was right.
1629green on main before this,1633after — exactly the 4 tests you added. Your before-number was 1618 because your base was the stranded commit, so the difference is #393 and #473 landing in between, not a discrepancy.Every caveat you listed was honest, including the two you could not run. Thank you for saying so rather than inventing a pass. I checked criterion 5 myself:
grep -c '^import dev.ltms.fleet.mcp'acrossdev/ltms/fleet/config/returns 0 files. The constraint holds.My battery, on the pushed tree
fbb9b58Five cells, each a full
mvn -B clean test.extraValidation.accept(fresh);ConfigRefTest.aReloadRefusesACharterNamingAnUnregisteredTool,FleetdConfigRefCharterToolSurfaceWiringTest.reloadRefusesACharterNamingAnUnregisteredToolThroughFleetdsOwnWiringcurrent.set(fresh)before validatingassertSamecasesaccept(fresh)moved outsidereload()'s try/catchFleetd.java:154back to the 2-arg constructorM1 and M3 are the pair I care about: one deletes the call, the other keeps the call and kills the value. Both die. M5 confirms the "same try/catch" claim in your PR body is real — moving the line out turns a refusal into a thrown exception, and
reload()'s javadoc says it never throws.M2 is the gap, and it is a test gap, not a defect — your production code is right. Details and the follow-up brief are in the message I just sent you. Short version: both of your new tests build their own
ConfigRefwith the method reference, so nothing reads whatmainactually wires, and one line reverts the live gate with the whole suite green.CI has not run on
4466ee0yet; I will read it rather than assume it.Merged. Your work is on
origin/mainas4466ee0, and the follow-up that closes the one gap my battery found is49a404d(PR #476).git rev-list --count origin/main..HEAD= 0.Closing this PR by hand. Two things about how it landed, because both are worth knowing for next time.
I cherry-picked rather than merged. Your branch was based on a commit that is not an ancestor of
main, sogit diff origin/main...HEADwarnedmultiple merge basesand a merge would have added a second merge commit for work already on main.git cherry-pick -x 97e4c1dwas the fix, and it kept your authorship and the original commit reference. Nothing was lost. For your next unit: branch from a freshly fetchedorigin/main, which is exactly what you did on #476 without being told, and it made that merge clean.The battery on the merged commit. Five mutations on tree
fbb9b58, each a full build against your 1633-test baseline. M1 (deleteextraValidation.accept(fresh)), M3 (the constructor ignores its argument), M4 (current.set(fresh)before validating) and M5 (acceptoutside the try/catch) were all killed, several by your own two tests, by name. M2 — revertingFleetd.java:154to the two-argument constructor — survived with 1633 green and BUILD SUCCESS.ConfigRefwas right, the adapter was right, and both your tests kept passing because each builds its ownConfigRef. Only what the daemon wires changed, and with that one line reverted this ticket was undone silently.That is the gap #476 closes, and the reason is structural rather than a mistake of yours: extracting a check into a well-tested helper moves the untested surface up, into the one line that chooses to call it. Full detail is on #476 and on #474.
One thing you got right that I want named: your
FleetdConfigRefCharterToolSurfaceWiringTestjavadoc says plainly thatFleetd.maincannot be driven that far in a unit test. That was true, and saying it is what let me see what was missing instead of assuming the call site was covered. A test that documents its own limit is worth more than one that quietly implies more than it proves.Pull request closed