FED-M1-06 — Adds mosaic gateway doctor [--json] [--config <path>] for tier-aware health reporting (postgres + valkey + pgvector). JSON mode emits a single parseable TierHealthReport for CI consumption; exit 1 on red.
Refactor: tier probes lifted from gateway to storage
The probes from apps/gateway/src/bootstrap/tier-detector.ts (FED-M1-04) needed to be reused by the new doctor command, but gateway is an app — not a library. Lifted them to @mosaicstack/storage:
detectAndAssertTier(config) — fail-fast on first failure (used by gateway boot)
probeServiceHealth(config) — non-throwing, runs ALL required probes, returns TierHealthReport with overall green/red verdict (used by doctor)
All 4 probe behaviors preserved verbatim from FED-M1-04 (verified by reviewer)
Old apps/gateway/src/bootstrap/tier-detector.ts + spec deleted; gateway main.ts now imports from @mosaicstack/storage.
Cycle break
Storage couldn't take a dependency on @mosaicstack/config (config already depends on storage for StorageConfig). Defined a local structural TierConfig interface in tier-detection.ts capturing only the fields the probes use. Callers continue passing full MosaicConfig objects via structural compatibility.
## Summary
FED-M1-06 — Adds `mosaic gateway doctor [--json] [--config <path>]` for tier-aware health reporting (postgres + valkey + pgvector). JSON mode emits a single parseable `TierHealthReport` for CI consumption; exit 1 on red.
## Refactor: tier probes lifted from gateway to storage
The probes from `apps/gateway/src/bootstrap/tier-detector.ts` (FED-M1-04) needed to be reused by the new doctor command, but gateway is an app — not a library. Lifted them to `@mosaicstack/storage`:
- `detectAndAssertTier(config)` — fail-fast on first failure (used by gateway boot)
- `probeServiceHealth(config)` — non-throwing, runs ALL required probes, returns `TierHealthReport` with overall green/red verdict (used by doctor)
- All 4 probe behaviors preserved verbatim from FED-M1-04 (verified by reviewer)
Old `apps/gateway/src/bootstrap/tier-detector.ts` + spec deleted; gateway `main.ts` now imports from `@mosaicstack/storage`.
## Cycle break
Storage couldn't take a dependency on `@mosaicstack/config` (config already depends on storage for `StorageConfig`). Defined a local structural `TierConfig` interface in `tier-detection.ts` capturing only the fields the probes use. Callers continue passing full `MosaicConfig` objects via structural compatibility.
## Tests
- `packages/storage/src/tier-detection.spec.ts` — **22 tests** (11 ported + 11 new covering `probeServiceHealth`, real-timer assertion, federated non-bullmq branch, lazyConnect)
- `packages/mosaic/src/commands/gateway-doctor.spec.ts` — **12 tests** (JSON contract, exit codes, output format, `--config` override, console.log silence in JSON mode)
```
22 passed (22) — tier-detection
12 passed (12) — gateway-doctor
```
## Process notes
- Independent code review (sonnet) flagged 2 important + 2 minor test gaps; all addressed in the same PR
- Independent verifier (haiku) confirmed surface claims (file paths, exports, deletion of old files, test counts)
- Cycle was caught by `pnpm typecheck` post-fix and triaged by structural typing rather than moving `MosaicConfig`
## Test plan
- [ ] CI green
- [ ] Manual smoke: `mosaic gateway doctor` against a running standalone stack returns green
- [ ] Manual smoke: `mosaic gateway doctor --json` produces valid JSON
Refs #460
Adds `mosaic gateway doctor [--json] [--config <path>]` for tier-aware
health reporting (postgres, valkey, pgvector). JSON mode emits a single
parseable TierHealthReport for CI consumption; exit 1 on red.
Refactors gateway-internal tier probes into @mosaicstack/storage so the
same probe logic is reused by both the gateway boot path
(detectAndAssertTier — fail-fast on first failure) and the doctor
command (probeServiceHealth — non-throwing, runs all probes, returns
report). Old apps/gateway/src/bootstrap/tier-detector.* files removed.
A local TierConfig interface in tier-detection.ts captures the minimal
structural shape from MosaicConfig without importing @mosaicstack/config
(would create a cycle since config already depends on storage for
StorageConfig).
Tests:
- packages/storage/src/tier-detection.spec.ts — 22 tests (11 ported from
gateway tier-detector, 11 new for probeServiceHealth + timing + branch
coverage)
- packages/mosaic/src/commands/gateway-doctor.spec.ts — 12 tests for
JSON contract, exit codes, output format, --config override
Refs #460
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.
Summary
FED-M1-06 — Adds
mosaic gateway doctor [--json] [--config <path>]for tier-aware health reporting (postgres + valkey + pgvector). JSON mode emits a single parseableTierHealthReportfor CI consumption; exit 1 on red.Refactor: tier probes lifted from gateway to storage
The probes from
apps/gateway/src/bootstrap/tier-detector.ts(FED-M1-04) needed to be reused by the new doctor command, but gateway is an app — not a library. Lifted them to@mosaicstack/storage:detectAndAssertTier(config)— fail-fast on first failure (used by gateway boot)probeServiceHealth(config)— non-throwing, runs ALL required probes, returnsTierHealthReportwith overall green/red verdict (used by doctor)Old
apps/gateway/src/bootstrap/tier-detector.ts+ spec deleted; gatewaymain.tsnow imports from@mosaicstack/storage.Cycle break
Storage couldn't take a dependency on
@mosaicstack/config(config already depends on storage forStorageConfig). Defined a local structuralTierConfiginterface intier-detection.tscapturing only the fields the probes use. Callers continue passing fullMosaicConfigobjects via structural compatibility.Tests
packages/storage/src/tier-detection.spec.ts— 22 tests (11 ported + 11 new coveringprobeServiceHealth, real-timer assertion, federated non-bullmq branch, lazyConnect)packages/mosaic/src/commands/gateway-doctor.spec.ts— 12 tests (JSON contract, exit codes, output format,--configoverride, console.log silence in JSON mode)Process notes
pnpm typecheckpost-fix and triaged by structural typing rather than movingMosaicConfigTest plan
mosaic gateway doctoragainst a running standalone stack returns greenmosaic gateway doctor --jsonproduces valid JSONRefs #460