4.9 KiB
#1194 — Installed framework-tool drift detection and refresh analysis
Decision
The reported queue-guard source defect was already fixed on main by 58b971ab; the live failure came from a stale ~/.config/mosaic/tools/git/ci-queue-wait.sh. The durable fix is therefore a detector, not a duplicate queue-guard patch.
mosaic doctor now compares the framework tools bundled with the executing Mosaic package against the deployed tools tree. Doctor is the selected visibility boundary because it is observational and operator-invoked: unlike session start, it does not add a repository/network scan to every seat launch, and it cannot silently replace identity or messaging tools while seats are active. It reports drift without changing files. --fail-on-warn converts detected drift into a non-zero doctor result.
Classification
The existing framework-manifest.txt is authoritative:
- Every source file under
tools/**is framework-owned and required in the deployed tools tree. tools/_lib/credentials.jsonis explicitly operator-owned and excluded from byte comparison.- A file present only in the deployed tools tree is operator-owned/unknown by the manifest's fail-safe default. The detector reports it as
INSTALLED_ONLY operator-or-unknownbut does not fail or delete it.
This means NOT_INSTALLED is not suppressed by filename guesses such as “test” or “README”: if it ships below source tools/**, the installer contract says it should be installed. Source-only implementation files outside tools/** are outside this detector population by construction.
Current host analysis (observation only; no refresh performed)
A direct source-vs-installed census showed broad drift, including identity and messaging behavior:
- Identity/provider operations: stale
git/detect-platform.sh,issue-comment.sh,issue-create.sh,issue-close.sh,issue-view.sh,pr-create.sh,pr-merge.sh,pr-review.sh,pr-metadata.sh; missingpr-edit.shand several identity/read-back regression tools. - Messaging/session: stale
tmux/agent-send.sh,tmux/send-message.sh, their regressions, andfleet/start-agent-session.sh. - Gate enforcement: stale
git/ci-queue-wait.sh; missing the queue tri-state/process-level suites and terminal-green verifier. - Lease/QA behavior: stale lease-broker launch/mutation/receipt tools and QA hooks.
Counts vary with source head and installed local/operator files; the detector prints measured counts every run rather than baking this snapshot into policy.
Reviewed refresh command — analyse only, do not run during active seats
Use the package/release updater's manifest-driven keep-mode sync during a quiet maintenance window:
MOSAIC_SYNC_ONLY=1 \
MOSAIC_INSTALL_MODE=keep \
MOSAIC_HOME="$HOME/.config/mosaic" \
bash /path/to/reviewed/@mosaicstack/mosaic/framework/install.sh
For the globally installed package, resolve the reviewed installer rather than guessing its path:
PACKAGE_ROOT="$(dirname "$(node -p "require.resolve('@mosaicstack/mosaic/package.json')")")"
MOSAIC_SYNC_ONLY=1 MOSAIC_INSTALL_MODE=keep MOSAIC_HOME="$HOME/.config/mosaic" \
bash "$PACKAGE_ROOT/framework/install.sh"
Do not run this while agent seats are active: the stale set includes identity selection, provider mutation, messaging, queue/merge guards, lease enforcement, and session launch. Syncing those files in place can change behavior between a seat's preflight and mutation.
Post-refresh verification
- Run
mosaic doctor --fail-on-warn; requirestale=0 not-installed=0from the framework drift summary (other unrelated doctor warnings must also be adjudicated). - Re-run the constructed process-level queue probes against the installed path, not the source checkout. Use the source suite while overriding its subject path in a reviewed scratch copy, or reproduce these exact observations:
- pending provider payload: guard must print
state=pending, print the pending context, wait, and exit non-zero/timeout — never return immediately with rc 0; - malformed payload: guard must print
state=malformedand exit non-zero; - unsupported but valid status vocabulary: guard must print
state=unknownand exit non-zero.
- pending provider payload: guard must print
- Run provider author read-back for one deliberately low-risk wrapper operation before resuming fleet mutation work; wrapper self-report is not identity evidence.
- Relaunch seats only after the quiet-window verification, because existing processes retain loaded environment/context.
Probe evidence
The detector regression constructs a stale installed tool plus a missing shipped tool and observes rc 1 with distinct STALE and NOT_INSTALLED lines. That case would pass or be invisible before this change because no installed-vs-shipped comparison existed. Controls prove byte-identical tools pass, the credential carve-out is ignored, installed-only paths are classified without deletion/failure, and comparing a tree to itself refuses with CANNOT_ASSERT.