greenfield install never enables mosaic-lease-broker.service; fleet start then reports rc0 over a 4s seat death (mechanism behind #1267) #1279
Open
opened 2026-08-17 06:31:26 +00:00 by fred
·
2 comments
No Branch/Tag Specified
next
ci/push-ci-comment-model
merge/main-into-next
fix/1323-gitea-legacy-recipe
fix/ci-queue-wait-no-status
fred/code-review-pinned-tool-rules
docs/ri-050-release-evidence
fred/guides-seat-identity-fleet-comms
fred/credential-fail-closed-seat-slots
feat/ri-050-qr-evaluator
docs/ri-050-forge-docs-fastfollow
fix/ri-050-registry-secrets
test/ri-050-publish-gate-negative
fix/ri-050-verify-pglite-path
docs/ri-050-qr-probe-inventory
feat/ri-050-web-stale-safety
docs/ri-050-mission-bootstrap
fix/ri-050-forge-fail-closed
feat/ri-050-publish-gate
fix/1292-lease-broker-activation
fleet/continuation-record-2026-08-17
feat/ri-050-prd-authority
fix/ri-050-macp-fail-closed
fix/1280-identity-first-resolution
feat/w-f4-store
fix/1264-fleet-unattended-first-start
fix/1269-ci-chain-unblock
fix/1256-fleet-runtime-preflight
fix/1256-fleet-pane-path-node
fix/1257-e7-draft-transition
fix/1017-enumeration-guard-population
fix/1240-fleet-transport-check
fix/1017-wire-start-agent-session
e2e-compose
fix/1241-launch-failure-visible
fix/1237-fleet-v2-dispatch
fix/1236-installer-dir-modes
fix/installer-path-and-node
docs/1216-trunk-parameterization
docs/ia-merge-current
fix/869-lease-probe-timeout
main
feat/workspace-hygiene-tool-enforcement
feat/1080-pr-edit
fix/1182-fail-closed-launch
fix/1179-required-security-di
feat/p3-slice0-task5-chat-runtime-router-shaggy
feat/p3-slice0-task5-chat-runtime-router
feat/wf1-composition
feat/p3-slice0-task4-web-catalog-selection
feat/lease-promotion-and-harness-isolation
ci/provision-pi-runtime
feat/p3-slice0-task3-catalog-selection
feat/p3-slice0-task2-harness-registry
adopt/965-mos-ste-writing-standard
fix/991-comment-url-scheme-normalise
feat/wf2-bundle-migration
feat/wf4-plugin-acquisition
feat/wf5-refresh-safety
fix/1145-coord-di-compiled-boot
feat/p3-slice0-task1-harness-contracts
docs/webui-phase-p-structure
feat/1150-pi-goal-extension
feat/webui-p3-chat
fix/1146-ci-queue-purpose
fix/1138-conditional-federation
feat/webui-p2-data-auth
fix/gateway-runner-image
feat/webui-p1-vite-skeleton
fix/break-c-hooks-and-web-image
docs/webui-fleet-claude-bridge-plan
fix/wizard-gateway-failure
fix/next-node-gate
fix/mosaic-init-rce
greenfield/fomo-lin
fix/1099-pipefail-wake
fix/1099-pipefail-tests
fix/1099-pipefail-sweep
fix/framework-shell-portability
fix/1043-pane-git-identity
fix/1081-issue-close-silent-comment-failure
fix/1090-enrollment-wallclock-tolerance
feat/1082-tea-stale-token-diagnostic
fix/detect-platform-silent-128-outside-repo
feat/1050-install-state-machine-red-fixture
fix/pr-merge-message-field
feat/1051-mosaic-brain-installer
feat/1045-mosaic-cred
remediation/state
fix/1056-upgrade-rollback-control-race
fix/1019-ci-queue-timeout-harness
feat/rm-02-gate-registry
fix/rm-01-reproducible-checkout
remediation/mission-setup
fix/hygiene-inert-format-gate
fix/1019-queue-guard-stdin
feat/mos-ste-writing-standard
fix/1007-suite-hermeticity
feat/push-guard-null-case-verification
mos-comms-live
docs/heartbeat-framework-layering-ms-lead
feat/869-c4-version-coupling
feat/869-c2-install-ordering-guard
feat/869-c5-doctor-activation-check
feat/per-agent-gitea-identity
fix/875-belongs-case-insensitive-slug
fix/ci-queue-wait-404-branch-absent
feat/869-c1-activation-probe
feat/869-c3-broker-supervisor
fix/865-tea-cli-comment-invocation
feat/glpi-skills
fix/860-deflake-mutator-lease-gate
fix/850-detect-platform-port-normalization
fix/856-worktree-deps-preflight
fix/835-pr-review-approve-reject-comment-flag
fix/848-truthful-evidence
fix/812-pr-review-comment
fix/849-recovery-runtime-fixture-race
docs/758-ledger-m5-001-sync
feat/834-tc-server-side-doc
feat/833-constrained-recovery-command
feat/827-gate0-probe
governance/gate0-probe3-amendment
fix/795-codex-pr-diff
fix/795-ci-base-jq
fix/795-ci-base-git
feat/791-pr3-fleet-regen
feat/791-pr2-snapshot-restore
fix/807-glpi-206
fix/808-agent-send-false-sender
feat/791-upgrade-config-protection
feat/790-mosaic-yolo-claudex-pr2
feat/790-mosaic-yolo-claudex
feat/758-v1-v2-migrator
fix/766-exact-fleet-comms
test/758-reconciler-lifecycle-gates
docs/771-kbn101-db-role-split
test/758-example-profile-dispositions
feat/758-shared-role-resolution
feat/mos-logical-identity-fencing
feat/769-kbn100-unified-schema
docs/753-kbn010-threat-gate
feat/758-roster-v2-compiler
feat/756-official-discord-plugin
docs/758-fleet-config-management
fix/mos-option2-qualification-format
docs/issue-758-m0
docs/mos-option2-qualification
mos-comms
feat/tess-interaction-agent
fix/tess-docs-format
draft/mosaic-platform-prd
fix/installer-provider-gate-and-local-gateway-redis
release/mosaic-cli-0.0.37
feat/framework-constitution-alpha
fix/git-wrapper-repo-detection
fix/woodpecker-wrapper-legacy-mosaic
fix/t-a292e96f-gitea-pr-metadata
fix/gitea-pr-metadata-login-t-a292e96f
fix/t_a292e96f-pr-metadata-gitea
fix/t_3a368a52-gitea-usc-login
fix/bootstrap-hotfix
fix/populate-known-packages-list
fix/idempotent-init
v0.0.39-alpha
mosaic-v0.0.31
fed-v0.2.0-m2
fed-v0.1.0-m1
mosaic-v0.0.29
mosaic-v0.0.28
mosaic-v0.0.27
mosaic-v0.0.26
mosaic-v0.0.25
mosaic-v0.0.24
v0.2.0
v0.1.0
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Assignees
fargo
fred
happy
jason.woltje (Jason Woltje)
merge-gate
ops-01 (Mosaic fleet seat ops-01)
ops-02 (Mosaic fleet seat ops-02)
ops-03 (Mosaic fleet seat ops-03)
ops-ci-01 (Mosaic fleet seat ops-ci-01)
pepper
rev-code-01
rev-code-02
rev-security-01
rev-security-02
sanity
scooby (Scooby)
scrappy
shaggy
tiny
velma
vision
woodpecker
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#1279
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.
A greenfield install produces a host with no running lease broker, so the first
mosaic fleet start <seat>launches a runtime that is immediately denied and reaped at ~4 s — whilefleet startreturns rc 0 and prints nothing. Measured independently on two hosts.This is the mechanism behind #1267. The two are separate defects and fixing either alone leaves a hole: #1267 is "
startreports success it did not verify"; this is "the thing it was not verifying was never installed to begin with."The locus
enableFleetUnits()inpackages/mosaic/src/commands/fleet.tsis the install's auto-enable step. It enables exactly two classes of unit:mosaic-tmux-holder.servicemosaic-agent@<name>.service, once per roster agentmosaic-lease-broker.serviceis not in that list. Measured on bothorigin/mainandorigin/nextby extracting the function body and grepping it;mosaic-tmux-holder.servicereturns 2 on both refs as the control, so the extraction resolves. This is not amain-vs-nextregression — both lanes behave the same way.The unit itself is fine and is shipped:
packages/mosaic/framework/systemd/user/mosaic-lease-broker.service, with[Install] WantedBy=default.target.broker-supervisor.tsmaterializes the wrapper and the unit, and its own docstring is explicit that finishing the job belongs to someone else:Nothing takes that step. Shipped, materializable, documented, never enabled.
Evidence — host 1, canary sandbox VMID 1125 (@daphne)
Framework
0.0.50-next.2439. Walked past thefleet startwall by hand:start-lease-broker.shis not standalone: without the unit'sRuntimeDirectoryit diesINSECURE_PARENT_MODE. The unit's own comment says so — "daemon.py'ssecure_parent()fails closed unless this directory is exactly 0700, soRuntimeDirectoryModeis not cosmetic."/run/user/1000/mosaic-leaseplus the exact ExecStart env, no code and no unit installed — the probe seat stayed alive past two minutes with node→pi present and heartbeat plus.nativemarker advancing repeatedly, then stopped at the authentication gate as expected.Evidence — host 2, fomo-lin, real hardware, Debian 13, framework 0.0.49 (@scooby)
A deliberate two-arm differential, same command both arms, only the broker state changed. Broker
is-activewas confirmedactivein A andinactivein B, so the variable demonstrably moved.fleet startrcrc=0in both arms — the return code is not the discriminator.The events log gives the mechanism more cleanly than the pane text. In
fleet/run/sessions/events.ndjson:mswub5xu→ bothsession.launchandlease.register.mswud7ch→session.launchonly,lease.registerabsent.session.launchagainst 8lease.registerfile-wide, solease.registeris genuinely per-launch conditional rather than a field that is always emitted.Why established hosts do not show this
Both fomo-lin and sb-it-1-dt have the unit
enabledand the broker running, which is why the defect has stayed invisible: every "known-good" observation on those hosts was made with a broker up. On fomo-lin the on-disk unit is byte-identical to the shipped template (sha256 match against both the framework copy and the npm copy, with a broker-vs-holderdiffreturning rc 1 as the control that the comparison is live), enabled and started during 08-08 provisioning. The only local departure is file mode, 664 → 777.So the enable happened on those hosts by some route that is not
enableFleetUnits(), and that route is not established from the code. It does not happen on a fresh VM.Suggested direction, not a prescription
mosaic-lease-broker.serviceto the auto-enable step, and start it, before anyfleet startcan run. Enable alone is not sufficient —WantedBy=default.targetonly helps at next login, and a greenfield install expects to work in the session that ran it.fleet start, gets rc 0, and no seat exists 6 seconds later." There must be a named check that goes red on a broker-absent host, and it cannot be a check that only passes because the developer's box has a broker running.Filed by @fred. Measured by @daphne (canary 1125) and @scooby (fomo-lin); neither holds an authorized principal on this repo and both decline to borrow one. @scooby's fomo-lin manifest at
docs/reports/2026-08-16_fomo-lin-greenfield-fleet-manifest.mdwas corrected by its own author at8533ec55f— it had previously called the unit hand-tailored and said no.servicetemplate shipped. Both were wrong and the corrected version is the one to read.The enable step has never existed — measured, and this closes the one open question above
The issue body said the enable happened on two established hosts "by some route that is not
enableFleetUnits()" and that the route was unidentified. The history question is now answered, and the answer is simpler than a regression.The string
mosaic-lease-broker.serviceappears in exactly one commit in the entire history of bothorigin/mainandorigin/next:That is the commit that introduced the template and the materializer. There is no second commit, on either lane, that ever put the unit into an enable path and no commit that later removed one. Whole-repo scope, all paths, not just
fleet.ts.Corroborating grep on the tree at
origin/next: nosystemctl enable/starttouches the broker anywhere underpackages/mosaic. The only lease-broker invocations are therevoke-lease.pysession hooks inruntime/claude/settings.jsonandcommands/claudex.ts, plus theExecStart=line inside the unit template itself.Controls, because an empty result is the one output that means both "measured, none" and "did not measure"
mosaic-tmux-holder.servicereturns many commits on both lanes (c1aecfa,4990905,191efae,463745e,67135d3,bf2a674, …). The query resolves.fatal: cannot simplify commit 98a771c8) and returned empty, and I very nearly published that empty as "never present". The control errored too but still printed rows, which is the only reason the failure was visible. The run reported here is from a clean clone with no errors on either arm.-Ssemantics: it reports a change in occurrence count, so it matches deletions as well as additions. "Exactly one commit, and it is an addition of +513 lines" is therefore the strong reading, not a weak one — the string has entered the tree once and never left.What this means
Not a regression, not a lane difference, not a lost step: the last mile was never written.
broker-supervisor.tsmaterializes the unit and says in its own docstring that enabling is "a separate, later, out-of-scope step", and no later step was ever added. That is consistent withenableFleetUnits()omitting it on both lanes.So the brokers running on fomo-lin and sb-it-1-dt were enabled by an operator route rather than by any install. The one physical trace is the file mode on fomo-lin's unit — 664 as shipped, 777 on disk — which is not what a plain copy leaves behind. That is a provenance detail on two hosts, and it does not change the fix: a fresh host gets no broker, and
fleet startreports rc 0 over the resulting 4-second seat death.The fix surface is unchanged and is now unambiguous — there is no prior implementation to restore, so whatever lands here is new code, and it needs the acceptance test named in the body: a check that goes red on a broker-absent host.
-- @fred
One corroborating work-record line — scope-limited, and it does NOT name the broker
Following @scooby's fomo-lin provenance (an enable symlink dated 2026-08-08 14:55:11 pointing at the template dir in place, which is a different convention from
install-systemd's copy-then-enable), I went looking for a route my literal-string-Sprobe could not have seen. A glob-based enable would evade it entirely.What I found, and what it is not.
refreshActiveFleetUnits()inpackages/mosaic/src/runtime/update-checker.tsdoes globmosaic-*.service— but it copies template→active dir and does not enable:That explains why the broker unit exists in both directories on established hosts while never being enabled by code. It is the mechanism behind "the unit is present everywhere and running almost nowhere".
A whole-repo search for
systemctl enable(control: 28 files matchsystemctl; nonce → 0, so the search discriminates) returns exactly one reference, and it is documentation:docs/archive/work-records/fleet-observability-phase2.md:93The scope limit matters and I am stating it rather than letting the quote imply more than it says. I grepped that file for broker/lease mentions: 1. It does not name
mosaic-lease-broker.service. What it establishes is the practice — units on this fleet have been enabled by hand, and there is a never-completed TODO to move that intofleet init. It is corroborating context for how a host ends up with a hand-enabled unit. It is not attribution of the broker enable, and it should not be read as one.Net effect on this issue: none of the conclusions move. The
-Sresult stands after the falsification attempt, which is worth more than the original run — the conclusion was tested against the one route that could have overturned it and survived. There is still no enable step for the broker anywhere in either lane's history, so the fix remains new code rather than a restoration.On provenance of @scooby's symlink: he labelled the actor unrecoverable from that host's surviving logs — bash_history rotated, no install log, and systemd does not journal symlink creation. That is a bounded negative result, not an open thread, and I am not asking anyone to keep digging for it.