v0.26.6 feat(schema): PGLite ↔ Postgres parity gate (closes #588)#590
Merged
Conversation
…d type fix (#588) Drift gate (test/e2e/schema-drift.test.ts) spins up fresh PGLite + Postgres, runs each engine's initSchema(), snapshots information_schema.columns, and diffs the four-tuple (data_type, udt_name, is_nullable, column_default) per column. 17 unit cases for the pure diff function (test/helpers/schema-diff.ts + schema-diff.test.ts) including a D3 negative test that reproduces the v0.26.1 oauth_clients.token_ttl regression. 6 E2E cases including 4 sentinels for oauth_clients, mcp_request_log, access_tokens, eval_candidates. The gate caught one real drift on its first run: access_tokens.id was UUID on Postgres (schema.sql:328, migration v4) and TEXT on PGLite (pglite-schema.ts). Reconciled to UUID DEFAULT gen_random_uuid() on both sides. CI wiring in scripts/e2e-test-map.ts triggers schema-drift on changes to schema.sql, pglite-schema.ts, or migrate.ts. The 2-table allowlist (files, file_migration_ledger) is narrow by design — every other Postgres table must reach PGLite via PGLITE_SCHEMA_SQL or a migration's sqlFor.pglite branch. Bookkeeping: master HEAD's VERSION was 0.26.0 even though the prior commit shipped as v0.26.1 (the bump never landed). Moving to 0.26.3 per the same bookkeeping discontinuity. Codex flagged a versioning hardening follow-up (scripts/check-version-sync.sh pre-push guard) for v0.26.4. Also fixes two pre-existing CI failures master shipped through: - check-privacy.sh: src/core/mounts-cache.ts had two banned name references ("Wintermute"). Replaced with "your OpenClaw" per CLAUDE.md:550. - check-no-legacy-getconnection.sh: src/commands/integrity.ts:355 was a new legacy db.getConnection() caller. Added to the script's allowlist with a PR 1 cleanup note (matches the existing 8 grandfathered entries). Out of scope (filed for v0.26.4): manual ALTER TABLE on production Postgres that never made it into source files (the actual v0.26.1 trigger; needs a gbrain doctor --schema-audit mechanism); index parity; versioning hardening guard. Plan + codex review pivot: original plan compared raw schema.sql vs raw pglite-schema.ts; codex showed they're intentionally divergent today (PGLite reaches its end-state via PGLITE_SCHEMA_SQL + migrations). Pivoted to end-state comparison, which catches real drift without false positives. Closes #588. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per user instruction. No code or test changes — VERSION + package.json + CHANGELOG header/body + CLAUDE.md key-files entry. Regenerated llms-full.txt. "NOT in this release" deferral targets bumped from v0.26.4 → v0.26.5 (those items are still deferred; they're now deferred from v0.26.4). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Master added v0.26.2 (#593) and v0.26.1 (#577) entries via the OAuth fix-wave landing path. Resolved three conflicts: - VERSION: kept 0.26.4 (this branch's version) - package.json: kept 0.26.4 - CHANGELOG.md: kept both — v0.26.4 entry on top, then master's new v0.26.2 + v0.26.1 entries below. Final order: 0.26.4 → 0.26.2 → 0.26.1 → 0.26.0 (top to bottom, contiguous version sequence). Also fixed a banned-name reference master shipped in the v0.26.1 CHANGELOG credit line ("Co-authored by Wintermute" → "Co-authored by your OpenClaw") per CLAUDE.md:550 / scripts/check-privacy.sh. Regenerated llms-full.txt to match the merged CHANGELOG. Verified post-merge: typecheck clean, schema-diff unit tests 17/17 pass. Master's diff did not touch src/schema.sql, src/core/pglite-schema.ts, or src/core/migrate.ts, so the new schema-drift gate's behavior is unchanged.
Per user instruction. Bookkeeping-only — VERSION + package.json + CHANGELOG header/body + CLAUDE.md key-files entry. Regenerated llms-full.txt. "NOT in this release" deferral targets bumped from v0.26.5 → v0.26.7 (those items remain deferred; now from v0.26.6 instead of v0.26.4). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Master added f082501 v0.26.3 feat(admin): observability + per-agent config + auth hardening (#586), bringing migration v33 (oauth_clients gets token_ttl + deleted_at; mcp_request_log gets agent_name + params + error_message), the magic-link admin login flow, and per-client TTL. Resolved three conflicts (all bookkeeping, all version-related): - VERSION: kept 0.26.6 (this branch's version, ahead of master's 0.26.3) - package.json: kept 0.26.6 - CHANGELOG.md: my v0.26.6 entry on top, then master's new v0.26.3 block, then the rest. Final order: 0.26.6 → 0.26.3 → 0.26.2 → 0.26.1 → 0.26.0 (top to bottom, contiguous). Auto-merged but needed cleanup: - scripts/check-no-legacy-getconnection.sh: both sides added src/commands/integrity.ts to the allowlist with different notes. Deduped to one entry combining both notes. Schema-drift gate sanity check post-merge: - access_tokens.id is still UUID DEFAULT gen_random_uuid() in both schema.sql and pglite-schema.ts (my v0.26.3 D6 fix preserved) - Master's new oauth_clients.token_ttl + .deleted_at columns are in both engines (master added them to schema.sql + pglite-schema.ts + migration v33's sqlFor — the gate is satisfied automatically) - Master's new mcp_request_log.agent_name + .params + .error_message same story - Typecheck clean, schema-diff unit tests 17/17 pass - Privacy script clean Regenerated llms-full.txt to match the merged CHANGELOG.
Master added two more commits: - d97f159 v0.26.4 test: parallel unit-test loop (12x speedup, #605) - 0de9eb6 v0.26.5 feat: destructive operation guard end-to-end (#600) Resolved three conflicts (all version bookkeeping): - VERSION: kept 0.26.6 (this branch's version, ahead of master's 0.26.5) - package.json: kept 0.26.6 - CHANGELOG.md: my v0.26.6 entry on top, then master's new v0.26.5 + v0.26.4 blocks below. Final order: 0.26.6 → 0.26.5 → 0.26.4 → 0.26.3 → 0.26.2 → 0.26.1 → 0.26.0 (top to bottom, contiguous). Schema-drift gate sanity check post-merge: - Master's v0.26.5 destructive-guard work added pages.deleted_at (with partial index pages_deleted_at_purge_idx) and three columns on sources (archived, archived_at, archive_expires_at). All four are present in BOTH src/schema.sql AND src/core/pglite-schema.ts — master kept them in lockstep, so the gate is satisfied automatically. - access_tokens.id is still UUID DEFAULT gen_random_uuid() in both engines (my v0.26.3 D6 fix preserved across the merge). - Typecheck clean, schema-diff unit tests 17/17 pass, privacy script clean (master's v0.26.4 work fixed the Wintermute references in mounts-cache.ts that I had patched earlier — converged independently). Regenerated llms-full.txt to match the merged CHANGELOG.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
test/e2e/schema-drift.test.tsspins up fresh PGLite + Postgres, runs each engine's canonicalinitSchema()(bootstrap → schema replay → migrations), snapshotsinformation_schema.columns, and diffs the four-tuple(data_type, udt_name, is_nullable, column_default)per column. 27 of 29 tables in the parity contract; 2-table allowlist (files,file_migration_ledger) is narrow by design.test/helpers/schema-diff.ts+schema-diff.test.ts) including a D3 negative test that reproduces the v0.26.1oauth_clients.token_ttlregression — what would have caught that incident at PR time.access_tokens.idwasUUIDon Postgres (schema.sql:328, migration v4) butTEXTon PGLite. Aligned toUUID DEFAULT gen_random_uuid()on both sides.scripts/e2e-test-map.tstriggers the gate on changes tosrc/schema.sql,src/core/pglite-schema.ts, orsrc/core/migrate.ts.src/core/mounts-cache.ts(banned name) and a new legacydb.getConnection()caller insrc/commands/integrity.ts(added to the script's grandfather allowlist). The CHANGELOG merge of v0.26.1's credit line had a third instance fixed during merge resolution.Codex review
Original static-comparison plan got demolished by codex review — raw
schema.sqlvs rawpglite-schema.tsare already intentionally divergent (PGLite reaches its end-state via PGLITE_SCHEMA_SQL + migrations, not the raw blob alone). Comparing raw files would generate permanent false positives on the first run. Pivoted to end-state comparison, which catches real drift without false positives. Six of seven codex findings folded into the plan as binding constraints (D2 pivot, D4 four-tuple snapshot, D5 narrow allowlist, D6 fix exposed drift, plus 2 scope deferrals); one (versioning hardening guard) deferred to v0.26.7.What's NOT in this release
Out of scope for v0.26.6 (filed for v0.26.7):
ALTER TABLEon production Postgres that never made it into source files (the actual v0.26.1 trigger; needs agbrain doctor --schema-auditmechanism, separate from the CI parity gate)diffSnapshotsshape is extensible to indexes)scripts/check-version-sync.shpre-push guard)Test plan
bun test test/helpers/schema-diff.test.ts— 17/17 pass (pure diff function, no DB)DATABASE_URL=… bun test test/e2e/schema-drift.test.ts— 6/6 pass against fresh pgvector containerbun run typecheck— cleanbun build --compile --outfile bin/gbrain src/cli.ts— cleanbrain-registry > empty/null/undefined id routes to host,claw-test --scenario fresh-install, plusbuild-llmswhich I fixed by regenerating bundles after CLAUDE.md edits).oauth_clients.token_ttlfrom the synthetic snapshot to confirm the gate fires with the column named in the failure message.schema-diffunit tests 17/17 pass. Master's diff didn't touch any schema files.Versioning note
HEAD's
VERSION+package.jsonwere0.26.0when this branch started; master has since shippedv0.26.1(#577) andv0.26.2(#593). This PR ships asv0.26.6per user instruction. Hardening guard for VERSION/package.json/commit-message drift is filed as v0.26.7 follow-up.(Branch name is
garrytan/issue-588-v0.26.3from an earlier rename — GitHub doesn't support changing a PR's head branch ref. Branch URL is cosmetic; VERSION/package.json/CHANGELOG/PR title all read v0.26.6.)🤖 Generated with Claude Code