feat(fleet): native Mosaic backlog on @mosaicstack/db (atomic claim + TTL) #657

Merged
jason.woltje merged 2 commits from feat/a4-mosaic-backlog into main 2026-06-24 14:55:11 +00:00
Owner

Card A4 — native Mosaic Backlog of record

Builds Mosaic's OWN backlog-of-record on the existing Postgres storage layer. REPLACES the former Hermes adapter (no Hermes dependency) and the earlier sqlite idea (no sqlite, no new db client).

packages/db

  • New backlog table (drizzle) + backlog_status enum + generated migration 0011_bitter_gateway.sql. depends_on is jsonb string[] (matches existing jsonb-array style).
  • BacklogService takes a Db handle — identical code on createDb (server PG) and createPgliteDb (embedded). Ops: create (idempotency dedup), list (status/phase/ready-only DAG gate), claim, reclaim, link, stats, block, complete.
  • Atomic claim: SELECT ... FOR UPDATE SKIP LOCKED in one tx — two concurrent claimers can never both win. TTL claims (default 900s) + reclaim of expired.

packages/mosaic

  • mosaic fleet backlog <sub> --json. Embedded PGlite default at <mosaicHome>/fleet/backlog; full Postgres via DATABASE_URL — same code. Migrations run on first use. Added @mosaicstack/db workspace dep.

install.sh

  • Added fleet/backlog to PRESERVE_PATHS so mosaic update does not wipe the backlog.

docs

  • docs/fleet/backlog-conventions.md: schema, phase convention, atomic-claim + TTL semantics, PGlite-default/Postgres-by-config, Mosaic-native (no Hermes).

Tests (in-memory PGlite, real PG semantics)

  • create/list; idempotency dedup; filters
  • atomic claim exactly-one-winner + N-card no-double-claim
  • deps DAG gate; link edge; reclaim of expired (+ --id, fresh untouched); stats math

Gates green: mosaic typecheck/lint/vitest (554), db typecheck/vitest (backlog 14), prettier, plus end-to-end CLI smoke.

🤖 Generated with Claude Code

## Card A4 — native Mosaic Backlog of record Builds Mosaic's OWN backlog-of-record on the existing Postgres storage layer. REPLACES the former Hermes adapter (no Hermes dependency) and the earlier sqlite idea (no sqlite, no new db client). ### packages/db - New `backlog` table (drizzle) + `backlog_status` enum + generated migration `0011_bitter_gateway.sql`. `depends_on` is jsonb `string[]` (matches existing jsonb-array style). - `BacklogService` takes a `Db` handle — identical code on `createDb` (server PG) and `createPgliteDb` (embedded). Ops: create (idempotency dedup), list (status/phase/ready-only DAG gate), claim, reclaim, link, stats, block, complete. - Atomic claim: `SELECT ... FOR UPDATE SKIP LOCKED` in one tx — two concurrent claimers can never both win. TTL claims (default 900s) + reclaim of expired. ### packages/mosaic - `mosaic fleet backlog <sub> --json`. Embedded PGlite default at `<mosaicHome>/fleet/backlog`; full Postgres via `DATABASE_URL` — same code. Migrations run on first use. Added `@mosaicstack/db` workspace dep. ### install.sh - Added `fleet/backlog` to `PRESERVE_PATHS` so `mosaic update` does not wipe the backlog. ### docs - `docs/fleet/backlog-conventions.md`: schema, phase convention, atomic-claim + TTL semantics, PGlite-default/Postgres-by-config, Mosaic-native (no Hermes). ### Tests (in-memory PGlite, real PG semantics) - create/list; idempotency dedup; filters - atomic claim exactly-one-winner + N-card no-double-claim - deps DAG gate; link edge; reclaim of expired (+ --id, fresh untouched); stats math Gates green: mosaic typecheck/lint/vitest (554), db typecheck/vitest (backlog 14), prettier, plus end-to-end CLI smoke. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jason.woltje added 1 commit 2026-06-24 14:29:45 +00:00
feat(fleet): native Mosaic backlog on @mosaicstack/db (atomic claim + TTL)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
791d6b7c51
Add Mosaic's own backlog-of-record on the existing Postgres storage layer,
replacing the former Hermes adapter (no Hermes dependency) and the earlier
sqlite idea (no sqlite, no new client).

- packages/db: `backlog` table (drizzle) + enum + migration 0011; BacklogService
  taking a Db handle so it runs on both createDb (server PG) and createPgliteDb
  (embedded). Atomic claim via SELECT ... FOR UPDATE SKIP LOCKED inside one tx,
  TTL claims + reclaim of expired, deps DAG gate, idempotency-key dedup, stats.
- packages/mosaic: `mosaic fleet backlog <sub> --json` (create/list/claim/
  reclaim/link/stats/block/complete). Embedded PGlite default at
  <mosaicHome>/fleet/backlog; full Postgres via DATABASE_URL — same code.
  Migrations run on first use.
- install.sh: preserve fleet/backlog across `mosaic update`.
- docs/fleet/backlog-conventions.md: schema, phase convention, atomic-claim +
  TTL semantics, PGlite-default/Postgres-by-config, Mosaic-native (no Hermes).
- Tests (in-memory PGlite, real PG semantics): create/list, exactly-one-winner
  concurrency (and N-card no-double-claim), deps gate, reclaim of expired, stats.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jason.woltje force-pushed feat/a4-mosaic-backlog from 791d6b7c51 to aac4e51f14 2026-06-24 14:46:52 +00:00 Compare
jason.woltje merged commit f852250419 into main 2026-06-24 14:55:11 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#657