Skip to content

fix(db): native genie → autopg/pgserve-v3 migration (embed migrations + self-provision DB) - #2456

Merged
namastex888 merged 2 commits into
mainfrom
fix/native-pgserve-v3-migration
May 19, 2026
Merged

namastex888 merged 2 commits into
mainfrom
fix/native-pgserve-v3-migration

Conversation

@namastex888

@namastex888 namastex888 commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

genie could not natively migrate onto autopg/pgserve v3

Three coupled defects, all reproduced and fixed against a live autopg v3 host (freshly compiled binary, zero env hacks, zero manual DB creation):

1. KEYSTONE — migrations absent from the compiled binary

src/lib/db-migrations.ts loaded SQL via readdirSync(import.meta.dir/../db/migrations) + Bun.file(). bun build --compile does not bundle runtime FS reads, so the shipped binary saw zero migrations → genie db migrate reported Applied: 0 on a completely empty DB and the schema was never created.
Fix: scripts/gen-migrations-manifest.ts generates src/db/migrations.generated.ts — static with { type: 'text' } imports Bun embeds into the binary. Loader prefers the embedded set; the FS scan stays as a dev-only fallback. scripts/build-binary.sh regenerates the manifest pre-compile so it can't go stale. src/types/sql.d.ts ambient for the text import.

2. autopg v3 not detected as a direct postmaster

readPostmasterDiscovery() only read <socketDir>/admin.json; autopg v3 writes live discovery to <socketDir>/runtime.json (admin.json moved to ~/.autopg/). So directPostmaster was always false → genie stayed on the legacy accept-hook/postgres path that pgserve v3 deleted.
Fix: read runtime.json (v3) then admin.json (v2 legacy), shared parse/validate.

3. No native database provisioning

resolveDatabaseName() always returned postgres, relying on the deleted pgserve-v2 accept-hook to auto-create + route app_<name>_<fp>. No production code ever created genie's DB.
Fix: on the direct-postmaster path, target NATIVE_DB_NAME (genie; GENIE_DB_NAME override) and ensureDatabaseExists() creates it from the postgres maintenance DB (allowlisted identifier; duplicate_database race tolerated). database is reassigned in-place so the bootstrap pool, role-cutover GRANTs, and migrations all agree on the target DB (an earlier split granted the scoped role in postgres while the pool ran in genie → "no schema has been selected to create in"). Legacy pgserve-v2 router path unchanged.

Evidence (live autopg v3, compiled binary, no hacks)

genie db migrate
  → [genie] provisioned database "genie" on direct postmaster
  → role-cutover.cutover database=genie
  → All migrations are up to date. Applied: 63 migrations
  → [pg-seed] re-seeded 132 teams
genie db (genie) = 63 migrations / 52 tables
genie ls → connects, reads PG cleanly

bun run check:fast (typecheck, lint, dead-code, skills:lint, wishes:lint, lint:emit) + biome all green.

Scope / safety

  • Legacy pgserve-v2 (accept-hook router) path is untouched — only the direct-postmaster (autopg/pgserve-v3) branch changes.
  • New env: GENIE_DB_NAME (optional override; defaults to genie on v3).
  • Generated manifest committed so a plain bun build works without the codegen step.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added support for explicit database name configuration via environment variable
    • Enhanced database discovery and provisioning for direct postmaster connections
    • Compiled binaries now embed all database migrations, eliminating filesystem dependencies at runtime and ensuring deployment consistency

Review Change Stack

… + self-provision DB)

genie could not migrate onto autopg/pgserve v3. Three coupled defects,
all reproduced + fixed against a live autopg v3 host:

1. KEYSTONE — migrations absent from the compiled binary.
   db-migrations.ts loaded SQL via readdirSync(import.meta.dir
   /../db/migrations) + Bun.file(); `bun build --compile` does NOT bundle
   those runtime FS reads, so the shipped binary saw ZERO migrations →
   `genie db migrate` reported "Applied: 0" on an empty DB, schema never
   created. Fix: scripts/gen-migrations-manifest.ts →
   src/db/migrations.generated.ts (static `with { type: 'text' }` imports
   Bun embeds); loader prefers the embedded set, FS scan kept as a dev
   fallback; build-binary.sh regenerates pre-compile so it can't go
   stale; src/types/sql.d.ts ambient for the text import.

2. autopg v3 not detected as a direct postmaster.
   readPostmasterDiscovery() only read `<socketDir>/admin.json`; autopg
   v3 writes live discovery to `<socketDir>/runtime.json` (admin.json
   moved to ~/.autopg/). directPostmaster was always false → genie stayed
   on the legacy accept-hook/`postgres` path pgserve v3 deleted. Fix:
   read runtime.json (v3) then admin.json (v2), shared parse/validate.

3. No native DB provisioning. resolveDatabaseName() always returned
   `postgres`, relying on the deleted pgserve-v2 accept-hook to
   auto-create+route `app_<name>_<fp>`. Fix: on the direct-postmaster
   path target NATIVE_DB_NAME ('genie'; GENIE_DB_NAME override) and
   ensureDatabaseExists() creates it from the `postgres` maintenance DB
   (allowlisted ident; duplicate_database race tolerated). `database` is
   reassigned in-place so the bootstrap pool, role-cutover GRANTs and
   migrations agree on the target DB (an earlier split granted the scoped
   role in `postgres` while the pool ran in `genie` → "no schema has been
   selected to create in"). Legacy router path unchanged.

Proven on a live autopg v3 host, freshly compiled binary, zero env hacks
/ zero manual DB creation: genie db migrate → provisioned database
"genie" → role-cutover database=genie → 63 migrations → pg-seed 132
teams → genie db = 63 migrations / 52 tables → `genie ls` reads PG
cleanly. biome + tsc clean on changed files.

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

coderabbitai Bot commented May 19, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@namastex888 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 42 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b08196f8-0293-4ae7-9de7-cc6f16805254

📥 Commits

Reviewing files that changed from the base of the PR and between 31b241e and caf7041.

📒 Files selected for processing (1)
  • src/lib/db.ts
📝 Walkthrough

Walkthrough

This PR enables migration embedding in compiled binaries by generating a TypeScript manifest at build time, switching runtime migration loading to prefer embedded assets, and updating database provisioning to work correctly with direct-postmaster and autopg/pgserve v3 discovery.

Changes

Embedded Migration Support for Compiled Binaries

Layer / File(s) Summary
SQL Import Type Declaration
src/types/sql.d.ts
Declares TypeScript module declaration for *.sql imports to enable type-safe usage with Bun's text loader.
Build-Time Migration Manifest Generation
scripts/gen-migrations-manifest.ts, src/db/migrations.generated.ts, scripts/build-binary.sh
Generator scans src/db/migrations/ for .sql files, creates manifest with static imports using with { type: 'text' } for Bun embedding, validates basenames, and integrates into build script as pre-compile step.
Runtime Migration Loading
src/lib/db-migrations.ts
loadMigrationFiles() prefers EMBEDDED_MIGRATIONS when available, falling back to on-disk scanning only in development.
Database Naming and Provisioning Helpers
src/lib/db.ts
Introduces NATIVE_DB_NAME constant, ensureDatabaseExists() helper with allowlist validation and race-tolerant CREATE DATABASE, and GENIE_DB_NAME override support.
Postmaster Discovery Parsing Refactoring
src/lib/db.ts
Adds parsePostmasterDiscovery() validator and updates readPostmasterDiscovery() to support both v3 (runtime.json) and v2 (admin.json) discovery layouts, verify socket existence, and normalize port/pid.
Bootstrap Connection Setup Integration
src/lib/db.ts
buildAndOpenConnection() resolves database target earlier, switches from legacy DB_NAME to NATIVE_DB_NAME on direct postmaster, pre-provisions database before pool creation, and removes redundant downstream recomputation.

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main change: native Postgres support for autopg/pgserve-v3 with embedded migrations and database self-provisioning, matching the PR's core purpose.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/native-pgserve-v3-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/db.ts`:
- Around line 1299-1301: The code currently gates direct-postmaster detection
behind isRoleCutoverEnabled() (cutoverEnabled), which prevents direct-postmaster
boot when GENIE_ROLE_CUTOVER=0; change the logic so directPostmaster is computed
purely from transport.useSocket and readPostmasterDiscovery() !== null (i.e.,
set directPostmaster = transport.useSocket && readPostmasterDiscovery() !==
null) and remove the dependency on cutoverEnabled; also update the DB
retarget/provisioning checks that currently use cutoverEnabled (the block
referencing DB retarget/provisioning) to instead rely on directPostmaster where
appropriate so retarget/provisioning is not skipped when cutover is disabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 08eb073b-ec3a-4ac1-b35e-c32936533002

📥 Commits

Reviewing files that changed from the base of the PR and between cf2104e and 31b241e.

📒 Files selected for processing (6)
  • scripts/build-binary.sh
  • scripts/gen-migrations-manifest.ts
  • src/db/migrations.generated.ts
  • src/lib/db-migrations.ts
  • src/lib/db.ts
  • src/types/sql.d.ts

Comment thread src/lib/db.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31b241eeb4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lib/db.ts Outdated
Comment on lines +1313 to +1314
if (directPostmaster && !isTestMode && database === DB_NAME) {
database = NATIVE_DB_NAME;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate native DB fallback to v3 runtime discovery only

directPostmaster now becomes true for both runtime.json and admin.json because readPostmasterDiscovery() checks both files, but this branch rewrites the default DB to NATIVE_DB_NAME whenever database === DB_NAME. On pgserve v2 hosts that still publish admin.json, this changes the default target from postgres to genie, so upgraded processes can start against a new empty DB instead of their existing one. This is a behavior regression for existing v2 deployments and should be limited to the v3 (runtime.json) case.

Useful? React with 👍 / 👎.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mechanism to embed SQL migrations into the compiled binary using a generated manifest and Bun's static text imports, ensuring migrations are available without runtime filesystem access. It also adds support for detecting and connecting to direct postmasters (autopg/pgserve v3), including automatic database provisioning. Review feedback suggests optimizing performance by skipping database existence checks for short-lived CLI processes and refining error handling by removing an unnecessary 'unique_violation' check during database creation.

Comment thread src/lib/db.ts
Comment on lines +148 to +149
// 42P04 duplicate_database / 23505 unique_violation → another booter won the race.
if (code !== '42P04' && code !== '23505') {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Error code 23505 (unique_violation) is typically associated with DML operations (like INSERT or UPDATE) violating a unique constraint on a table. For the CREATE DATABASE command, the standard Postgres error code for a database that already exists is 42P04 (duplicate_database). Including 23505 here is likely unnecessary and could be confusing to future maintainers.

    // 42P04 duplicate_database → another booter won the race.
    if (code !== '42P04') {

Comment thread src/lib/db.ts Outdated
Comment on lines +1316 to +1318
if (directPostmaster && database !== DB_NAME) {
await ensureDatabaseExists(pgModule, transport, database);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ensureDatabaseExists function performs a relatively heavy operation, including creating a temporary connection pool and executing a catalog query. For short-lived processes like hook forks (which set GENIE_SKIP_DB_BOOT=1), this adds significant overhead to every invocation. Since database provisioning is a one-time setup task that should be handled by the daemon or migration commands, we should skip this check in short-lived CLI processes to improve performance.

  if (directPostmaster && database !== DB_NAME && !cliShortLived) {
    await ensureDatabaseExists(pgModule, transport, database);
  }

…ple from role-cutover

CodeRabbit (Major) + Codex (P1) both correct:
- Native-DB provisioning was gated on `directPostmaster`, which is
  `cutoverEnabled && … && readPostmasterDiscovery()`. With
  GENIE_ROLE_CUTOVER=0 it was skipped → v3 fell back to `postgres` and
  re-broke (CodeRabbit).
- readPostmasterDiscovery() now also matches v2 `admin.json`, so
  `directPostmaster` was true on pgserve v2 too → my branch retargeted v2
  hosts from `postgres` to `genie`, booting them against a new empty DB
  (Codex P1 regression).

Fix: new `hasV3RuntimeDiscovery()` — true ONLY when `<socketDir>/
runtime.json` (the v3, router-less marker; v2 publishes only admin.json)
parses. Native-DB now keys off `v3NativeDb = transport.useSocket &&
hasV3RuntimeDiscovery()` — NOT cutoverEnabled, NOT v2 admin.json.
`directPostmaster` (role-cutover) is left exactly as-is, so v2 + v3
role-cutover behavior is unchanged.

Validated on a live v3 host, freshly compiled binary:
- default (cutover ON): 63 migrations → `genie` DB ✓
- GENIE_ROLE_CUTOVER=0: 63 migrations → `genie` DB ✓ (no postgres fallback)
- v2 (no runtime.json): v3NativeDb=false → stays on `postgres` (router path)
check:fast (typecheck/lint/dead-code/skills/wishes/emit) + biome green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@namastex888
namastex888 merged commit 4087168 into main May 19, 2026
11 checks passed
namastex888 added a commit that referenced this pull request May 19, 2026
…-dev

fix(db): sync native pgserve-v3 migration fix to dev (already on main via #2456)
@automagik-genie
automagik-genie deleted the fix/native-pgserve-v3-migration branch September 25, 2026 04:50
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.

2 participants