fleet.js: unhandled ENOENT on missing roster (+ sweep class); install.sh mangles @mosaicstack/mosaic heading #792
Reference in New Issue
Block 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?
Summary
Two robustness defects observed on a fresh
install.shrun (framework v3,mosaic@0.0.48,Node v24.13.1). Primary:
mosaic fleet pscrashes with a raw unhandledENOENTstack trace whenthe fleet roster is absent. Secondary: the installer prints a mangled package heading. Both are
mechanical, capacity-fill fixes under normal gates.
Primary — unhandled ENOENT class in fleet.js (treat as a class, not one line)
Repro
Actual
(Node v24.13.1, mosaic@0.0.48.)
Expected
Graceful, actionable error and a nonzero exit — no stack trace. e.g.:
No fleet roster found at <path>. Run \mosaic fleet init` (or see docs: ).`Scope — sweep, don't spot-fix
loadFleetRosteris one instance. Sweepfleet.jsand sibling command modules for the samepattern: an expected-config/state file read (
readFileSync/JSON.parse/open) with no ENOENT(or parse-error) guard that lets a raw Node error escape to the user. Each such read of an
expected-but-optional config should produce an actionable message + nonzero exit, not a trace.
Consider a shared helper (e.g.
readConfigOrExit(path, hint)) to standardize the pattern.Secondary — installer heading escaping bug
install.shoutput shows a corrupted heading: the raw text printedaicstack/mosaic (npm package)— a mangled@mosaicstack/mosaic. Looks like an escaping/echo bug in the installerheading (leading
@moseaten — possibly a variable-expansion,printfformat, or ANSI/@handling issue). Fix the installer heading/echo so it prints
@mosaicstack/mosaicintact.Acceptance criteria
mosaic fleet pswith no roster prints an actionable message + nonzero exit, no stack trace.fleet.js+ siblings swept; every expected-config read has ENOENT/parse guards (sharedhelper preferred). List the sites fixed in the PR.
@mosaicstack/mosaiccorrectly.new shared helper); independent review.
Gates & scope
TDD tests-first ≥85%; trunk-based squash PR; independent review. Mechanical — GPT/Codex lane is
fine. Capacity-fill; below #790 and the agents-dir protection task in priority. May be delivered as
one PR (both fixes) or two; reviewer's call. Framework-PR firewall: operator-agnostic.
Backlog (non-blocking, from #818 RoR MINOR-2):
normalizeFleetRosterV1(fleet-roster-v1.ts:199-207) rewraps asnew FleetRosterConfigurationError(error.message), dropping the originalcause/stack; theinstanceof Errorcatch is also broad enough to relabel a genuine programmerTypeErrorinside the validation body as a user configuration error. Low risk (pure-validation body). Suggested follow-up: pass{ cause: error }and/or narrow the catch. Captured here per coordinator ruling — non-blocking, did not gate the #818 merge.