CB-612: the daemon warns at every boot about a token no profile needs, teaching operators to skim startup warnings #115
Closed
opened 2026-08-17 14:25:35 +02:00 by ltms
·
3 comments
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
2.0 — one operation centre, many hosts
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: fleet/fleetd#115
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 in a pre-tag scan on 2026-08-17, reading the live daemon's own startup output.
The warning
Every boot prints:
All three named profiles work without it. The warning is a false alarm.
Why it fires
BRIDGED_WORKER_TOKENappears nowhere in the config. It arrives as a default:requiredSecretEnvVars(Bridged.java:578-591) then demandstokenEnvfrom every non-subscription profile, with no filter onkindand no notion of a profile that needs no token. So any profile that simply does not settokenEnvis reported as broken.None of the three needs it:
local-direct—kind: claude-code,baseUrl: http://gx00.gw:8000, documented in the config as "direct vLLM — no auth, LAN only".ClaudeCodeLauncher.java:220usesputIfPresent, so a missing token is skipped, not fatal.sol,terra—kind: opencode.OpenCodeLauncher.java:348-349falls back to the literal"bridged-local-noauth"when the token resolves empty, and these profiles read their own provider credentials anyway.Why it is worth fixing rather than tolerating
The message is confidently wrong in both directions: it says the failure "stays invisible until a worker actually needs it" (no worker needs it) and tells the operator to edit
secrets.shand restart (nothing to add).The cost is not the noise itself — it is what the noise does to the channel. CB-596 shipped a real startup warning on this exact log level today, the one that fires when the member credential policy is missing and every member inherits the whole secret store. A permanent false alarm beside it trains an operator to skim past both.
This is the mirror image of CB-593's rule: there, a deliberate choice must not look like an oversight. Here, a non-problem must not look like a failure.
The fix
Distinguish "this profile needs a token and it is missing" from "this profile needs no token".
The cleanest cut is to stop defaulting
tokenEnvto a name nobody set. A profile that declares notokenEnvis stating it needs none; that is different from one naming a variable that turns out to be unset. If the default is kept for compatibility,requiredSecretEnvVarsmust skip profiles that never declared it explicitly.Acceptance criteria
tokenEnvand no auth requirement produces no startup warning.tokenEnvwhich is unset still warns, with the current wording. That case is real and CB-594 exists because of it — do not lose it.BRIDGED_WORKER_TOKENline at all, while theWORKER_GITEA_TOKENandAI_GATEWAY_TOKENlines are unchanged.kind: opencodeshould be in this check at all, given those profiles read their own provider credentials. Decide it explicitly and write the reason down — do not leave it implied.Also seen, and deliberately NOT filed
This one reports a deliberate setting (
notifications: mode: disabled), and the live config already explains it correctly — "nobody gets paged, NOT health is off". It is noisy but not misleading, and demoting it is a judgement call for whoever picks up this ticket, not a defect on its own.Milestone
2.0. Nothing misbehaves; the fleet runs correctly on all seven profiles. This is about keeping the startup channel trustworthy.
agent referenced this issue2026-09-03 04:51:17 +02:00
Already fixed and merged as
1c051c4, earlier today. Confirmed withgit merge-base --is-ancestor 1c051c4 origin/main.The current code on
main:FleetConfig.java:406—tokenEnv = (tokenEnv == null || tokenEnv.isBlank()) ? null : tokenEnv;. An unsettokenEnvnow staysnullinstead of being defaulted to a name nobody chose. That is the cut the ticket asked for.Fleetd.java:940—if (!profile.isSubscription() && profile.hasTokenEnv()). Only an explicitly namedtokenEnvis required.RequiredSecretEnvVarsTestcovers both directions:profileWithoutTokenEnvDoesNotRequireTheOldDefaultandexplicitlyConfiguredUnsetTokenEnvWarnsWithCurrentWording.Fleetd.java:938-939: all kinds are checked whentokenEnvis explicit, because an explicittokenEnvdeclares a required host secret whatever the backend does with its own provider credentials. The reason is written down, not implied.The merge also fixed a crash that fell out of the change: making
tokenEnvnullable brokeClaudeCodeLauncher's directSystem::getenvon a null name. It now uses the superclassresolveEnvhelper, and all four readers oftokenEnvwere audited.Mutation-checked, production code only, both reverted and
diff -q-confirmed clean:hasTokenEnv()filter inrequiredSecretEnvVarsprofileWithoutTokenEnvDoesNotRequireTheOldDefaultProfile.hasTokenEnv()always returnfalseexplicitlyConfiguredUnsetTokenEnvWarnsWithCurrentWording,aVarSharedByTwoProfilesIsReportedOnceNamingBothBuild: 1215 tests, 0 failures, 0 compile errors.
Criterion 4 stays open until I redeploy — "a boot after the fix prints no
WORKER_TOKENline, while the other two lines are unchanged". Nobody has seen a real boot log on this jar yet. I will confirm it at the next restart and post the result here.My own process error, recorded because it cost a worker run. I delegated this ticket without first checking it against
main. It had been merged hours earlier, in this same session. The worker did the right thing — it checked, found the fix already present, verified all four criteria against the live code, mutation-tested them, and opened no PR because there was no diff. That is the correct outcome for a wasted brief, but the brief should not have existed.git log --grepon the ticket number before writing a brief is the cheap check I skipped.Captured the before picture from the running daemon's log, so criterion 4 has something to compare against. It also turned up the strongest possible argument for this ticket, which I did not expect.
Here is the current boot, in order, from pid 45674 (old jar, before the fix is deployed):
The variable is named
FLEETD_WORKER_TOKENnow, notBRIDGED_WORKER_TOKEN— renamed with the rest of the product. Four profiles are named, not three:xfjoined them since this ticket was written. None of the four sets atokenEnvinfleetd.yaml; I checked. So the warning is exactly the false alarm described here, still firing, and now slightly wider.The part I did not expect
Read the last line again:
The exhaustion feature has been completely switched off on this host, and the daemon has been saying so plainly at every single boot, one line below the false alarm.
Nobody read it. I did not read it. This morning the shared OpenAI credential ran out, a member was spawned onto it anyway, and it died without starting — because no profile had an
exhaustedPattern, so nothing could classify the pane line and nothing quarantined the credential. See #176 for that incident.This ticket argued that a permanent false alarm "trains an operator to skim startup warnings". That was the right prediction, and this is the receipt: the thing that got skimmed was a correct report, sitting directly underneath the false one, saying a whole safety feature was off. The cost of the noise was not the noise.
Predicted after picture
Stating it before I redeploy, so the check cannot be fitted to the result:
FLEETD_WORKER_TOKEN: MISSINGWARN disappears entirely. No line at all for that name.AI_GATEWAY_TOKEN,WORKER_GITEA_TOKENandLAVINMQ_URIlines are unchanged, still naming the same profiles. Those are real, explicit, and set.offto a partial coverage line namingsolandterra— because I have now added the measuredexhaustedPatternto both. That is a separate fix, but it lands in the same restart, and if it does not appear, the config change did not take.I will post the real boot log against these three.
Criterion 4 measured. All three predictions confirmed. Closing.
I redeployed onto the merged jar and checked the boot log against the three predictions I posted here before the restart, so the check could not be fitted to its result.
Daemon: pid 16890, jar
b0679beb7e57.FLEETD_WORKER_TOKENlines in the startup logfleet_whoamistill answersprimaryafter the restart, so the tab pin survived.The bug this ticket was really about
The false
FLEETD_WORKER_TOKEN: MISSINGwarning was never itself harmful — the token resolves through a different name and always did. The harm was training. It printed on every single boot, so the startup block became something to skim past.One line below it sat this:
CB-578's whole quarantine path had been switched off on this host for months, and I had read past it every restart. I only saw it because this ticket made me read the block properly instead of skimming it. Fixing the noise is what exposed the real defect underneath — that is worth recording as the reason this small ticket earned its keep.
That line now reads:
after I added the measured
exhaustedPatternliteral to both profiles sharing the spent OpenAI credential. See #201 for the follow-on fix to how that line names its own config key.Criteria 1–3 were already verified by the worker against live code and mutation-tested. Criterion 4 was the one only a redeploy could answer. It is answered.