Skip to content

feat(native): DbClient factory — MYCELIUM_USE_PGLITE switch (#176 follow-up) - #209

Open
Dewinator wants to merge 1 commit into
mainfrom
agent/db-client-factory
Open

feat(native): DbClient factory — MYCELIUM_USE_PGLITE switch (#176 follow-up)#209
Dewinator wants to merge 1 commit into
mainfrom
agent/db-client-factory

Conversation

@Dewinator

Copy link
Copy Markdown
Owner

Summary

Foundation for the next big native-app refactor — ships the boot factory atomically so each service can be migrated in its own follow-up PR without re-negotiating the env-flag plumbing.

PR #208 ('sidecar bundling pipeline') called out the next native-app PR explicitly:

Refactor [`mcp-server/src/index.ts`] to honour `MYCELIUM_USE_PGLITE=1` and route all services through the in-process adapter is the next big native-app PR.

That refactor touches ~30 service constructors. This PR is the small piece that goes first: it gives each future migration a single stable type to depend on.

Changes

mcp-server/src/services/db-client.ts (new, 82 LOC)

mcp-server/src/__tests__/db-client.test.ts (new, 4 tests, 128 LOC)

  • default (env unset) → `postgrest` mode
  • any non-"1" value → `postgrest` mode (covers "0", "false", "true", "yes", "")
  • "1" + temp `MYCELIUM_DATA_DIR` + `skipMigrations: true` → `pglite` mode; round-trips an insert/select through the adapter chain
  • `close()` in pglite mode releases the underlying PGlite handle (`adapter.raw().closed === true`)

What's intentionally not in this PR

  • No service migrated yet. `index.ts` still constructs each service with `(url, key, ...)`. The 30-site migration is split across follow-up PRs so each service is reviewed against both backends independently.
  • No prod boot path changed. `MYCELIUM_USE_PGLITE` has no effect on the running MCP server until the first service starts depending on `createDbClient()`.

Validation

```
npm run build → clean
node --test dist/tests/db-client.test.js → 4/4 passed (8.6s)
node --test dist/tests/native/*.test.js → 36/36 passed (43s, no regression)
```

Test plan

  • `cd mcp-server && npm run build` — clean
  • `node --test dist/tests/db-client.test.js` — 4 passes
  • Confirm no existing test imports `services/db-client.ts` (it's new — empty grep result expected)

Related

🤖 Generated with Claude Code

…-task 3 follow-up)

Foundation for the next big native-app refactor (PR #208's note: ~30
service constructors that currently hard-code `(supabaseUrl, supabaseKey)`
must migrate onto a shared DbClient). Ships the plumbing piece atomically
so each service can be migrated in its own follow-up PR without re-doing
env-flag negotiation.

`mcp-server/src/services/db-client.ts`:
  - DbClient = PostgrestClient | PGliteAdapter (both already speak the
    same `.from(t).select|insert|update|delete().eq|or|order|limit()` +
    `.rpc(name, args)` chain shape; the adapter contract tests gate that
    surface so it stays drop-in).
  - createDbClient({ supabaseUrl, supabaseKey, pglite? }) returns
    { client, mode, close() }. MYCELIUM_USE_PGLITE=1 routes through
    createNativeDb(); any other value (unset, "0", "false", "true",
    anything) keeps the PostgREST client. Strict 1-only matches the
    pattern PR #189 (MYCELIUM_LLAMA_REQUIRE_CHECKSUM) and PR #190
    (LLM_PROVIDER) already established for native-app feature flags.

`mcp-server/src/__tests__/db-client.test.ts` — 4 new tests:
  - default (env unset) → postgrest mode
  - any non-"1" value → postgrest mode
  - "1" + temp data dir + skipMigrations → pglite mode, .from()/.insert()/
    .select().single() round-trips through the adapter
  - close() in pglite mode releases the underlying PGlite handle

No service migrated yet — index.ts still constructs each service with
url/key. The migration is intentionally left for follow-up PRs (per the
"small atomic PR" cadence) so each service can be reviewed and validated
independently against both backends.

Validation:
  npm run build                       → clean
  node --test dist/__tests__/db-client.test.js  → 4/4 passed
  node --test dist/__tests__/native/*.test.js   → 36/36 passed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dewinator added a commit that referenced this pull request May 4, 2026
The previous "0 PRs offen" snapshot is stale: the agent itself opened a
4-PR queue in the last 4 ticks (#208 standalone + #209#210#211 stack).
Refresh the Aktiver-Code-Bestand block to credit landed sub-tasks (#202
DATA_DIR, #203 Tauri shell, #204 CI gate, #205 migration helpers) and
add a Queue-Stand note that names the open stack, the linear merge
constraint, and the ~19 still-supabase-direct services that the
DbClient migration sub-story will work through atomically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Dewinator

Copy link
Copy Markdown
Owner Author

Local validation (179th-tick fresh-clone walk, queue-bound, no-new-PR)

Walked the full DbClient stack #209#210#211 on a clean rebuild from each branch. All three green.

#209 (this PR — DbClient factory, branch agent/db-client-factory)

rm -rf dist && npm run build                  → clean
node --test dist/__tests__/db-client.test.js  → 4/4 pass (8.0s)
node --test 'dist/__tests__/native/*.test.js' → 36/36 pass (41s, no regression)

#210 (SwarmPin onto DbClient, branch agent/swarm-pin-dbclient-stacked)

rm -rf dist && npm run build                  → clean
node --test dist/__tests__/swarm-pin.test.js  → 14/14 pass (363ms)

#211 (Skills onto DbClient + shared dbClient, branch agent/skills-dbclient-stacked)

rm -rf dist && npm run build                                          → clean
node --test dist/__tests__/affect-skill-record-payload.test.js        → 8/8 pass (319ms)

(#211 is RPC-only and adds no new tests per the PR body; the Skills surface
is exercised through the existing affect-skill-record-payload regression
test, which still passes after the PostgrestClientDbClient rename.)

Merge-order confirmation

The stack is linear and the merges chain cleanly: #209 lands first, then
#210, then #211. Each rebuild was done from a clean dist/ after switching
branches (per pinned mcp-server lesson — stale dist/ would mask
"no tests collected" failures unrelated to the PR).

No queue growth from this validation tick.

🤖 Generated with Claude Code

Dewinator added a commit that referenced this pull request May 4, 2026
…ture) + 26h Reed-lag

Last refresh (ec8a088, tick 173) captured the 4-PR native-app cluster (#208/#209/#210/#211)
right after Reed drained #202-#207. Tick 174 then opened PR #212 (W4.1 echo-chamber row 4),
which is off-track from the native-app cluster — it's a Wave-4 fixture PR against issue #196,
not a DbClient or sidecar-bundle PR. CLAUDE.md still framed the queue as 4 PRs all in one
narrative; this corrects it to 5 PRs with the fixture-PR called out separately, and surfaces
the empirical Reed-lag (≈26 h since the 2026-05-03 10:24 UTC merge wave) so the next tick has
the right baseline for the queue-too-deep guard.

Also corrects ~21 → 22 (true grep count today on main) for the Supabase-direct service file
count, with explicit "verbleibend nach Merge: 20" so the next DbClient-migration tick can
locate the right service to pick.

No production code touched; pure CLAUDE.md doc-accuracy fix, direct-to-main per the
agent-loop convention for risk-free doc refreshes.
Dewinator added a commit that referenced this pull request May 4, 2026
The bird's-eye doc lagged the 2026-05-03 merge wave (PRs #202#207
landing sub-tasks 1, 2, 3-scaffold, 4, 5, 7-core) and the W3 spike
chain that settled the empirical mDNS budgets on `main`.

Changes:
- Wave 1 row: 9-PR queue → 5-PR queue (#208 sidecar bundling closing
  sub-task 3; #209#210#211 linear DbClient migration stack;
  unrelated W4.1 fixture #212). Note the 22-services DbClient sub-story
  with 2 already in flight.
- Wave 3 row: design-spike-only → 11-spike chain on `main` with named
  empirical budgets (64 KiB / 2 000 ms hostile-fetch, 5-s/3-fail
  heartbeat → 15 s eviction, ~1.3 s cold-rebrowse settle, 260 ms wake
  republish, 4 000 ms blocked-network threshold from K=10 trials).
  Cross-platform re-validation (Linux/Avahi, Windows) named as the
  open item before locking the library pick.
- Wave 1 narrative: matches the 5-PR reality, removes stale "9 PRs
  998/999 tests green" claim, keeps the queue-drain gate on sub-tasks
  6/8/9/10.

Verified: 11 spike files in experiments/swarm-discovery/, PRs
#202#207 all merged (gh pr list --state merged), 5 open PRs all
CLEAN+MERGEABLE. Refresh date bumped to 2026-05-04.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Dewinator

Copy link
Copy Markdown
Owner Author

Independent local revalidation — 2026-05-05 (Mac M4, 16 GB)

Re-ran the validation block in the PR body on a fresh checkout of agent/db-client-factory (commit 8b6a203), ~26h after CI:

rm -rf dist && npm run build                      → clean (tsc, no errors)
node --test dist/__tests__/db-client.test.js      → 4/4 passed (8.3s total)
  ✔ PostgREST mode (default — env unset)            (0.1s)
  ✔ PostgREST mode for any non-1 value              (0.001s)
  ✔ PGlite mode boots adapter with usable .from()   (4.4s)
  ✔ close() in PGlite mode releases handle          (3.4s)
node --test 'dist/__tests__/*.test.js'            → 1010 pass / 1 skip / 0 fail (14.9s)

No regressions across the broader suite. Foundation is merge-ready; #210 and #211 are stacked behind via base-branch retargeting (verified: gh pr view 210 --json baseRefNameagent/db-client-factory, gh pr view 211 --json baseRefNameagent/swarm-pin-dbclient-stacked), so GitHub will auto-retarget on merge.

🤖 Auto-tick empirical validation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant