Skip to content

feat(native): docker-migration helpers — Docker → PGlite wizard pure-TS core (#176 sub-task 7)#205

Merged
Dewinator merged 1 commit into
mainfrom
agent/docker-migration-pure-ts
May 3, 2026
Merged

feat(native): docker-migration helpers — Docker → PGlite wizard pure-TS core (#176 sub-task 7)#205
Dewinator merged 1 commit into
mainfrom
agent/docker-migration-pure-ts

Conversation

@Dewinator

Copy link
Copy Markdown
Owner

Summary

Implements the pure-TS building blocks for the native-app first-run "Import from Docker install" wizard described in docs/native-migration-spike.md. Sub-task 7 of #176 (native standalone app, prio 0.98 / Wave 1).

After this lands, the orchestrator (migrateFromDocker()) that lives in the Tauri shell can call into these helpers without re-implementing dump-handling. The shell-bound steps (probe + docker exec pg_dump) stay where they belong (sub-task 3 / PR #203 follow-up).

What's in this PR

mcp-server/src/native/docker-migration.ts — three pure functions + one helper:

Function Purpose Spec ref
stripPsqlDirectives(sql) Drop \\restrict / \\unrestrict / \\connect lines that modern pg_dump emits but PGlite's exec() can't parse spike §4
applyDumpToPGlite(pg, rawDump) Single-shot restore of a stripped full dump into a fresh PGlite spike §3 + step 6 of "What the wizard implementation has to do"
countTables(pg, tables) Row counts behind an identifier-regex guard, safe to expose spike step 7
verifyMigration(source, target) Row-equality check pre/post-restore spike step 7

The stripper is conservative — only line-prefix matches are dropped, so SQL whose string literals happen to contain the directive token (e.g. 'please \\restrict me') is preserved verbatim.

Tests

mcp-server/src/__tests__/native/docker-migration.test.ts — 10 new tests, all green:

  • stripPsqlDirectives drops the three known directives, preserves literals containing the token, idempotent
  • applyDumpToPGlite restores a synthetic dump (CREATE EXTENSION vector, CREATE TABLE with vector(4), INSERTs, \\restrict/\\unrestrict book-end) — row count + vector + TEXT[] all round-trip
  • countTables returns counts for populated + empty tables, rejects injection attempts (`memories"; DROP TABLE x; --`, leading-digit names, dashes, empty)
  • verifyMigration ok=true on equality, reports drift, treats missing target tables as 0, ignores extra target tables (PGlite metadata is allowed)
✔ 10/10 pass under `node --test dist/__tests__/native/docker-migration.test.js`
✔ Full suite: 1032 pass / 0 fail / 1 pre-existing skip (~46s)

Out of scope (intentional)

These belong in the Tauri shell follow-ups, NOT here:

  • Probing for an existing Docker stack (psql -lqt / docker ps) — shell-bound
  • Invoking pg_dump (docker exec ... pg_dump) — shell-bound
  • Writing .migrated-from-docker.json post-success marker
  • User-facing migration card / EventEmitter progress

Documented in the file header so the next PR knows where the boundary is.

Test plan

  • cd mcp-server && npm test — full suite green
  • cd mcp-server && node --test dist/__tests__/native/docker-migration.test.js — 10/10 pass
  • Spot-check: stripPsqlDirectives is idempotent on its own output

Conflict-free with the queue

Touches only new files under mcp-server/src/native/ and mcp-server/src/__tests__/native/. Zero file overlap with:

Merge order between #202 / #203 / #204 / this PR is independent.

Related

🤖 Generated with Claude Code

…TS core (#176 sub-task 7)

Implements the pure-TS building blocks for the native-app first-run
"Import from Docker install" wizard described in
docs/native-migration-spike.md.

Three pure functions + one helper, all unit-tested:

- stripPsqlDirectives(sql): removes \restrict / \unrestrict / \connect
  lines that modern pg_dump emits but PGlite's exec() cannot parse.
  Conservative line-prefix match preserves SQL whose string literals
  happen to contain the directive token.
- applyDumpToPGlite(pg, rawDump): single-shot restore of a stripped
  full pg_dump output into a fresh PGlite (precondition: empty, no
  migrations applied — the dump carries its own schema, dodging the
  circular-FK warning called out in the spike §3).
- countTables(pg, tables): row counts behind an identifier-regex
  guard so the helper is safe to expose to less-trusted callers.
- verifyMigration(source, target): row-equality check the wizard
  uses post-restore to assert no data loss before persisting the
  dataDir or rolling back.

Out of scope (lives in the Tauri shell, sub-task 3 of #176):
  - probing for an existing Docker stack (psql / docker ps shell-out)
  - invoking pg_dump (docker exec shell-out)
  - writing the .migrated-from-docker.json marker
  - user-facing migration card

10/10 new tests pass under node --test. Full mcp-server suite still
green (1032 pass, 0 fail, 1 pre-existing skip).

Atomic and conflict-free with PR #202 (data-dir root) and PR #203
(Tauri shell scaffold) — different files in mcp-server/src/native/.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Dewinator Dewinator merged commit c9c3939 into main May 3, 2026
1 check passed
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 added a commit that referenced this pull request May 4, 2026
…sks 1/2/3-most/4/5/7-core landed

The 09024a2 (tick 103) snapshot is two days stale: 9 of the 9 PRs in its
"recommended merge order" have merged, plus #197/#198/#201/#202/#203/#204/
#205/#206/#207 landed in the same window. Refresh the doc that "is the
canonical entry point for the native-app initiative" so a fresh reader
does not get a 79-tick-old picture.

Concrete changes:
- Phase line: "spike phase complete · gated on PR-queue drain" →
  "implementation underway · sub-tasks 1, 2, 3 (most), 4, 5, 7 (core)
  landed; 5 PRs open, ~26 h Reed-lag since #202#207".
- End-state installer list: ".dmg / .msi / .AppImage" → ".pkg / .msi /
  .AppImage", with the 2026-05-04 epic-body decision (.pkg, not .dmg)
  cited.
- Sub-task table: legend (✅ landed, 🔄 PR open, ⏳ spike-only) plus
  per-row PR status reflecting the current main:
  - Row 1 picks up #204 (79-migration walk as CI gate).
  - Row 3 picks up #202, #203, #206, #207 as landed and #208#211 as
    open. Row was "_none yet_".
  - Row 4 / 5 reframed as "inherent" (PGlite is one WASM binary;
    node-llama-cpp ships per-platform bindings).
  - Row 7 picks up #205 (Docker → PGlite migration helpers core).
- New "DbClient sub-story" subsection: 22 services touch Supabase
  directly on main; 2 in flight (Skills, SwarmPin); 20 remain after
  the open stack lands. Pattern: one service per PR.
- "Recommended merge order — open PR queue (9 deep)" section replaced
  with "Open PR queue (5 deep, all CLEAN+MERGEABLE)" — the 9 it
  documented have all merged.
- "Post-drain implementation gate" → "Post-stack implementation gate":
  parallel tracks (DbClient long-tail of 20 services + the sub-tasks
  6/8/9 release-pipeline triangle on tauri-plugin-updater per #207).

Doc-only, zero risk, direct-to-main per the standing rule for this
file shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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