What happened?
Upgrading from a pre-v0.26.3 PGLite brain wedges on column "agent_name" does not exist and the user can never reach schema v36 unaided.
applyForwardReferenceBootstrap in src/core/pglite-engine.ts:227 is missing a probe for mcp_request_log.agent_name. Migration v33 (admin_dashboard_columns_v0_26_3, shipped in v0.26.3) introduces the column, but PGLITE_SCHEMA_SQL already references it in:
// src/core/pglite-schema.ts:445
CREATE INDEX IF NOT EXISTS idx_mcp_log_agent_time
ON mcp_request_log(agent_name, created_at DESC);
On a brain whose mcp_request_log table predates v33, the upgrade path collapses:
connectEngine → initSchema() runs.
applyForwardReferenceBootstrap() runs but doesn't bootstrap agent_name (not in REQUIRED_BOOTSTRAP_COVERAGE).
PGLITE_SCHEMA_SQL replays. CREATE TABLE mcp_request_log is IF NOT EXISTS → no-op on the pre-existing table; the column is not added.
CREATE INDEX idx_mcp_log_agent_time ...(agent_name, ...) → column "agent_name" does not exist → schema replay aborts.
- Migration v33 (the one that would
ALTER TABLE ... ADD COLUMN IF NOT EXISTS agent_name TEXT) never runs because initSchema() failed before the migration runner.
This is the same forward-reference bug class CLAUDE.md describes (#239/#243/#266/#357/#366/#374/#375/#378/#395/#396) — the maintenance contract on applyForwardReferenceBootstrap was missed when v33 landed.
What did you expect?
gbrain upgrade (or gbrain init --migrate-only) should walk a pre-v0.26.3 PGLite brain forward to v36 cleanly, the same way the existing four probes do for pages.source_id, links.link_source/origin_page_id, content_chunks.symbol_name/language, and pages.deleted_at.
Steps to reproduce
- Have a PGLite brain that predates v0.26.3 (i.e.
mcp_request_log table exists without agent_name column). In my case the brain was at schema_version = 4.
gbrain upgrade (or any path that triggers initSchema()).
- Watch the upgrade chain fail:
=== Applying migration v0.11.0: GBrain Minions — durable background agents ===
Pre-v0.21 brain detected, applying forward-reference bootstrap
column "agent_name" does not exist
Phase A (schema) failed: Command failed: gbrain init --migrate-only. Aborting; re-run after fixing.
Migration v0.11.0 reported status=failed.
gbrain doctor confirms the wedge:
[FAIL] minions_migration: MINIONS HALF-INSTALLED (partial migration: 0.11.0). Run: gbrain apply-migrations --yes
[WARN] schema_version: Version 4, latest is 36. Fix: gbrain apply-migrations --yes
…but the suggested fix loops back to the same error.
gbrain apply-migrations --force-retry 0.11.0 does not help — the failure is in initSchema() upstream of the migration runner, not in v0.11.0's orchestrator.
Environment
- gbrain version: 0.28.1
- OS: macOS 26.3 (Darwin 25.3.0)
- Bun version: 1.3.12
- Database: PGLite (embedded)
Suggested fix
Two-line change matching the existing pattern in applyForwardReferenceBootstrap:
-
Probe. Extend the SELECT EXISTS(...) AS ... round-trip in src/core/pglite-engine.ts:229-249 with:
EXISTS (SELECT 1 FROM information_schema.tables
WHERE table_schema='public' AND table_name='mcp_request_log') AS mcp_log_exists,
EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='public' AND table_name='mcp_request_log' AND column_name='agent_name') AS agent_name_exists
-
Bootstrap. Add the parallel branch to the if (...) chain:
const needsAgentName = probe.mcp_log_exists && !probe.agent_name_exists;
// ...
if (needsAgentName) {
// v33 (admin_dashboard_columns_v0_26_3) adds full column set + backfill.
// Bootstrap only adds enough for PGLITE_SCHEMA_SQL's
// `CREATE INDEX idx_mcp_log_agent_time ON mcp_request_log(agent_name, ...)`
// not to crash. v33 runs later via runMigrations and is idempotent.
await this.db.exec(`
ALTER TABLE mcp_request_log ADD COLUMN IF NOT EXISTS agent_name TEXT;
`);
}
-
Pin it in CI. Add to REQUIRED_BOOTSTRAP_COVERAGE in test/schema-bootstrap-coverage.test.ts:47:
// v0.26.3 — forward-referenced by `CREATE INDEX idx_mcp_log_agent_time
// ON mcp_request_log(agent_name, created_at DESC)`.
{ kind: 'column', table: 'mcp_request_log', column: 'agent_name' },
And extend the strip-block at test/schema-bootstrap-coverage.test.ts:78-98 to drop the index + column so the test exercises the new branch:
DROP INDEX IF EXISTS idx_mcp_log_agent_time;
ALTER TABLE mcp_request_log DROP COLUMN IF EXISTS agent_name;
The mirror change to PostgresEngine.applyForwardReferenceBootstrap is likely warranted too — the same failure mode applies to any old Supabase/self-hosted brain that pre-dates v0.26.3 and goes through connectEngine on a v0.28.x binary. (I didn't hit it; only the PGLite path bit me.)
Workaround for affected users
For anyone hitting this in the wild: gbrain export still works against the wedged brain (the read path doesn't trigger initSchema()'s schema replay). Export markdown, move the broken brain dir aside, run gbrain init --pglite on a fresh dir (initializes cleanly at v36), then gbrain import the rescued markdown. Embeddings + links + timeline get rebuilt from scratch via gbrain embed --stale && gbrain extract all.
Why CI didn't catch it
test/schema-bootstrap-coverage.test.ts is the right shape (declarative REQUIRED_BOOTSTRAP_COVERAGE + drift guard), but it only covers what's listed in that array. v33's agent_name column was added to pglite-schema.ts and migrate.ts but never propagated to the bootstrap probe or the coverage list. The maintenance contract in the docstring at pglite-engine.ts:222-225 is the right place — it just got missed when v33 landed. Worth considering: a stricter CI check that greps pglite-schema.ts for CREATE INDEX ... ON <table>(<col>) patterns and asserts each <table>.<col> either appears in the original CREATE TABLE before the migration adds it, or has a matching entry in REQUIRED_BOOTSTRAP_COVERAGE. Out of scope for this issue, but flagging.
What happened?
Upgrading from a pre-v0.26.3 PGLite brain wedges on
column "agent_name" does not existand the user can never reach schema v36 unaided.applyForwardReferenceBootstrapinsrc/core/pglite-engine.ts:227is missing a probe formcp_request_log.agent_name. Migration v33 (admin_dashboard_columns_v0_26_3, shipped in v0.26.3) introduces the column, butPGLITE_SCHEMA_SQLalready references it in:On a brain whose
mcp_request_logtable predates v33, the upgrade path collapses:connectEngine→initSchema()runs.applyForwardReferenceBootstrap()runs but doesn't bootstrapagent_name(not inREQUIRED_BOOTSTRAP_COVERAGE).PGLITE_SCHEMA_SQLreplays.CREATE TABLE mcp_request_logisIF NOT EXISTS→ no-op on the pre-existing table; the column is not added.CREATE INDEX idx_mcp_log_agent_time ...(agent_name, ...)→column "agent_name" does not exist→ schema replay aborts.ALTER TABLE ... ADD COLUMN IF NOT EXISTS agent_name TEXT) never runs becauseinitSchema()failed before the migration runner.This is the same forward-reference bug class CLAUDE.md describes (#239/#243/#266/#357/#366/#374/#375/#378/#395/#396) — the maintenance contract on
applyForwardReferenceBootstrapwas missed when v33 landed.What did you expect?
gbrain upgrade(orgbrain init --migrate-only) should walk a pre-v0.26.3 PGLite brain forward to v36 cleanly, the same way the existing four probes do forpages.source_id,links.link_source/origin_page_id,content_chunks.symbol_name/language, andpages.deleted_at.Steps to reproduce
mcp_request_logtable exists withoutagent_namecolumn). In my case the brain was atschema_version = 4.gbrain upgrade(or any path that triggersinitSchema()).gbrain doctorconfirms the wedge:gbrain apply-migrations --force-retry 0.11.0does not help — the failure is ininitSchema()upstream of the migration runner, not in v0.11.0's orchestrator.Environment
Suggested fix
Two-line change matching the existing pattern in
applyForwardReferenceBootstrap:Probe. Extend the
SELECT EXISTS(...) AS ...round-trip insrc/core/pglite-engine.ts:229-249with:Bootstrap. Add the parallel branch to the
if (...)chain:Pin it in CI. Add to
REQUIRED_BOOTSTRAP_COVERAGEintest/schema-bootstrap-coverage.test.ts:47:And extend the strip-block at
test/schema-bootstrap-coverage.test.ts:78-98to drop the index + column so the test exercises the new branch:The mirror change to
PostgresEngine.applyForwardReferenceBootstrapis likely warranted too — the same failure mode applies to any old Supabase/self-hosted brain that pre-dates v0.26.3 and goes throughconnectEngineon a v0.28.x binary. (I didn't hit it; only the PGLite path bit me.)Workaround for affected users
For anyone hitting this in the wild:
gbrain exportstill works against the wedged brain (the read path doesn't triggerinitSchema()'s schema replay). Export markdown, move the broken brain dir aside, rungbrain init --pgliteon a fresh dir (initializes cleanly at v36), thengbrain importthe rescued markdown. Embeddings + links + timeline get rebuilt from scratch viagbrain embed --stale && gbrain extract all.Why CI didn't catch it
test/schema-bootstrap-coverage.test.tsis the right shape (declarativeREQUIRED_BOOTSTRAP_COVERAGE+ drift guard), but it only covers what's listed in that array. v33'sagent_namecolumn was added topglite-schema.tsandmigrate.tsbut never propagated to the bootstrap probe or the coverage list. The maintenance contract in the docstring atpglite-engine.ts:222-225is the right place — it just got missed when v33 landed. Worth considering: a stricter CI check that grepspglite-schema.tsforCREATE INDEX ... ON <table>(<col>)patterns and asserts each<table>.<col>either appears in the originalCREATE TABLEbefore the migration adds it, or has a matching entry inREQUIRED_BOOTSTRAP_COVERAGE. Out of scope for this issue, but flagging.