Skip to content

Forward-reference bootstrap missing mcp_request_log.agent_name — pre-v0.26.3 PGLite brains wedge on upgrade #695

@lcosent

Description

@lcosent

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:

  1. connectEngineinitSchema() runs.
  2. applyForwardReferenceBootstrap() runs but doesn't bootstrap agent_name (not in REQUIRED_BOOTSTRAP_COVERAGE).
  3. 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.
  4. CREATE INDEX idx_mcp_log_agent_time ...(agent_name, ...)column "agent_name" does not exist → schema replay aborts.
  5. 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

  1. 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.
  2. gbrain upgrade (or any path that triggers initSchema()).
  3. 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.
    
  4. 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.
  5. 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:

  1. 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
  2. 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;
      `);
    }
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions