Two convenience overloads have dangerous defaults, and one of them fails open: pin that no production code reaches for MessageService.poll(String) #718
Closed
opened 2026-10-04 07:35:37 +02:00 by ltms
·
3 comments
No Branch/Tag Specified
main
worker/702-4f5c7f-2
worker/721-70f9ea-5
worker/718-99362b-2
worker/task-15-af0d10-12
worker/task-16-50a702-13
worker/task-12-4d0479-9
worker/task-13-823ce2-10
worker/705-ticket-owner-af9928-8
worker/703-list-collaborators-9c06c2-7
worker/669-example-truth-0b303d-6
worker/669-collab-deliverability-9ba859-3
worker/669-collab-reload-report-2a21bd-4
worker/669-7e80a6-1
worker/669-unit-d-efbbd7-1
worker/669-1b786a-1
worker/669-1d1d9f-1
worker/692-4afb9d-2
worker/689-02fced-13
worker/693-cf23fa-14
worker/677-fix-lead-collision-f69073-12
worker/638-fix-overmask-dbb1bf-11
worker/675-5b7478-4
worker/669-unit-a-70cc8f-3
worker/677-8cdaaf-5
worker/638-a7b391-1
worker/683-4536d6-2
worker/651-a75bbe-8
worker/680-20607d-7
worker/664-c12e95-3
worker/668-08534d-4
worker/672-0f2469-2
worker/670-7d1022-1
worker/661-ac7c28-2
worker/664-37fb9b-3
worker/663-remove-3arg-read-3f6783-1
worker/659-remove-dead-backcompat-ba5e6f-1
worker/637-revision-60a488-23
worker/656-redact-regression-tests-892903-19
worker/637-context-gauge-threshold-466eb5-16
worker/639-redact-line-numbers-de4ac4-17
worker/641-set-reformat-guard-6f96a4-18
worker/642-herdr-guard-scope-5de0e4-15
worker/650-javadoc-scope-95f3b3-14
worker/612-01e9f7-13
worker/612-a-r4-quarantine-outage-7ab0e8-5
worker/612-a-r9-r11-capacity-coverage-peers-cfcc79-7
worker/612-a-r10-loophealth-ccc872-8
worker/612-a-r12-turnregistrar-9e3bb7-9
worker/612-a-r5-leadconfigdir-9e70cf-6
lead/config-edit-redact-anchor-wording
worker/config-edit-seam-ca8dc1-1
worker/612-r67-630-lifecycle-290b8d-3
worker/629-625-ports-seams-da7d5d-4
worker/612-r12-exhaustion-f37cd7-1
worker/612-r38-amqp-24b083-2
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#718
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?
Found by me (lead) while verifying PR #716. Everything below is measured in the main clone at
95311c6unless it names a branch.The shape
Both
MessageService.pollandAuthz.permitshave a shorter convenience overload that forwards tothe real one with a default argument. A future call site can reach for the short form, compile, pass
the whole suite, and silently get the default. The two differ in which way they fail, and that is
what makes one of them urgent.
MessageService.poll(String)— fails open, silentlynullis the "no caller terminal" value, andownsTicketiscallerTerminal == null || callerTerminal.equals(task.creatorTerminal). So the one-argument formskips the ownership check entirely. That is exactly the hole #705 was filed for: before PR #716,
FleetApp.taskStatuscalled this overload, and any worker could read any ticket.After PR #716 merges there are zero production callers. I measured both call sites on that
branch:
So the fix is complete today, and nothing stops it being undone by a one-word edit that no test
notices.
Authz.permits3-arg — fails closed, loudlyThe three-argument form defaults the classifier to
NO_KNOWN_LEAD_OR_COLLABORATOR, a deny-all. Afuture call site reaching for it would refuse every collaborator send. That is a real defect, but it
is loud and self-correcting: the refusal shows up the first time anyone tries. It has no production
caller — both gates call the four-argument form.
Why not just delete
poll(String)I measured the test usage before proposing anything:
44 test call sites. Deleting the overload means editing all 44 for no behaviour change, and a large
mechanical diff is its own risk. Keep the overload.
What to do
fleetd/src/main/javacallsMessageService.pollwith a single argument. This codebase already uses that idiom — seeFleetMcpAuthzTest.theFleetListHandlerActuallyConsultsCollaboratorsVisibleToand the two testsPR #716 adds. It needs its own control assertion: prove the scan really reached the production
sources and found the two-argument calls, so a glob that matches nothing cannot pass as "no
violation found".
mvn -o compilegreen first so the mutation is live and not a compile error, confirm the new testgoes red, then restore and confirm the file is byte-identical.
Authz.permitssaying it is a test convenience and that itsdefault classifier denies every collaborator. State the current contract only — no ticket number,
no history. This is the follow-through on a decision the previous lead recorded and deliberately
left for the next change in this area.
Not measured
I have not written the test, so I do not know whether the scrape can be written without being
brittle against formatting. If it cannot be made to hold without a control that really fires, say so
rather than shipping a test that passes on an empty scan — a zero match is not a finding.
Blocked on
PR #716. Point 1 is only true once that merges; until then
FleetApp.javastill has a productioncaller of the one-argument form.
No longer blocked, and there is a second instance
PR #716 merged as
9a64d42. So point 1 is now true:MessageService.poll(String)has zeroproduction callers. I measured it on
mainat that commit:A second instance of the same shape
FleetMcp.java:973-975forwards the five-argumentsendAsyncto the six-argument one withcreatorTerminaldefaulted tonull:nullis the "no creator" value, and a ticket with no recorded creator matches no terminal-bearingcaller at all — so that default does not merely skip a check, it makes the resulting ticket
unreadable by its own creator. That is the exact failure PR #716's second commit had to fix on the
REST path, where the defaulting happened by accident rather than deliberately.
It is test-only today: the one production caller is
FleetMcp.java:493, which passes a realcaller. So it is the same class of hazard aspoll(String)— a convenience overload whose defaultis wrong in a way the compiler and the suite both accept.
Scope, updated
Cover both methods with the one scrape test rather than writing two: assert that no file under
fleetd/src/main/javacalls eitherMessageService.pollwith a single argument or the five-argumentFleetMcp.sendAsync. One control assertion proving the scan really read the production sources andfound the long-form calls still covers both, and a single test is easier to keep honest than two that
drift apart.
The mutation proof in point 2 then has two halves, one per method. Each needs
mvn -o compileconfirmed green first so the mutation is live rather than a compile error.
Everything else in the original scope stands, including the
Authz.permitscomment in point 3.Correction to my own evidence above, before anyone builds a test from it
I wrote this ticket. Re-running its greps on current
main(9a64d42) shows two problems with theevidence, and both change the test this ticket asks for.
1. The quoted grep output is incomplete
The body shows two lines. The real command returns three:
Injector.java:493was missing from the quote. It is not new — I checked it is present at9a64d42~3and on the PR branch9a64d42^2, so it was there when I ran the original command andthe output I pasted had been trimmed.
t.queue.poll()is ajava.util.Queue.poll(), completelyunrelated to
MessageService, so the conclusion is unaffected. The evidence was still wrong.Also note
FleetMcp.java:1203in the body is now:1231— the line moved in the merge.2. The obvious regex gives a false positive, not a false negative
This is the part that matters for the test. I tried to count single-argument calls with the pattern
from the body and got 2, when the true answer is 0. Both were false positives:
Injector.java:493— right method name, wrong receiver type.FleetApp.java:899— genuinely two-argument, butpathParam("ticket")contains a), sopoll([^)]*,can never reach the comma. A nested call with parentheses defeats the pattern.So the usual warning here is inverted. The documented trap is that a broken pattern reads as a
clean zero; this pattern reads as a confident two. Either way the pattern was not measuring what
it claimed.
What this means for the scrape test
The test cannot be a naive method-name-and-comma regex. It must:
queue.poll()must not be a violation andmessages.poll(...)must be. Matching on the bare name.poll(conflates two unrelated types.)is wrong. Either balancethe parentheses or match on something other than argument-separating commas.
two-argument sites are found, so a pattern that silently matches nothing cannot pass.
If a text scrape cannot be made to hold on both counts, say so and do not ship it. A test that
reports "no violations" because its pattern is broken is worse than no test — it is the exact defect
this ticket exists to prevent, moved one layer up.
The conclusion of the ticket is unchanged and still measured: zero production callers of the
one-argument
MessageService.poll, read off the three lines above by eye rather than by regex.Merged locally as
6e06058and pushed tomain.What landed
Two files, +283 lines, no production behaviour change:
fleetd/src/test/java/dev/ltms/fleet/msg/MessageServicePollUsageTest.java(new, 280 lines)fleetd/src/main/java/dev/ltms/fleet/auth/Authz.java(+3, javadoc only)Verification I ran myself
mvn clean installone5f4fb8: Tests run: 2020, Failures: 0, Errors: 0, Skipped: 0 — BUILD SUCCESS, exit 0. That is 2018 onmainplus the 2 new tests.The merge commit's tree is byte-identical to the branch tree I built:
So the green build covers the merge exactly, and no post-merge rebuild was needed. Normally a clean auto-merge still needs its own build, because the merge tree differs from both parents. Here it provably does not.
I read the full 280-line test myself. Both tests carry loud control assertions, so a drifted anchor fails instead of passing on an empty match:
noProductionFileCallsTheSingleArgumentPollOverload— assertsfilesScanned > 0, andassertEquals(2, twoArgSites.size())naming bothFleetMcp.javaandFleetApp.java. If the anchor stops matching, that second assertion goes red.everyMessageServiceDeclarationIsNamedMessages— assertsfilesScanned > 0andnames.size() > 0. It deliberately does not hardcode a declaration count, so adding a newMessageServicefield does not make it red for the wrong reason.Two corrections to my own brief, for the record
Injector.java:493 t.queue.poll()was missing. The paste had been trimmed. I verified the line is present on the branch.)defeated[^)]*. A broken pattern read as a confident count, not as a clean zero. Those two traps became the acceptance criteria.I also claimed 43
MessageServicedeclarations. The worker corrected it to 41, and the worker is right. 43 raw hits minusFleetdRuntime.java:106 MessageService messages()(a method declaration) minusFleetMcp.java:486(a//comment reading "MessageService has won the session lock", which the un-stripped scan would have reported as a violation). I re-checked both exclusions in my own earlier output.One residual gap, recorded not fixed
The scan's needle is the literal
messages.poll(, and the declaration test deliberately skips method declarations. Soruntime.messages().poll(ticket)— a call through theFleetdRuntime.messages()accessor — is invisible to both tests.I measured whether that shape is reachable. Production has zero callers of
.messages(). The only call sites are in tests, which this scan does not read:FleetdAssemblyReleaseCleanupBehaviouralTest.java:162FleetdAssemblyHealthFailTargetBehaviouralTest.java:155FleetHealthMonitorTest.java:537,:560,:568So this is a defect on paper until someone names a path in — the same judgement I applied to #722. It did not block the merge. If a production caller ever reaches
MessageServicethrough the accessor, this guard goes quiet rather than red, and that is the thing to remember.Closing.