Skip to content

fix(pi): heal sessions/memory schema so plugin_version column lands#264

Merged
khustup2 merged 3 commits into
mainfrom
fix/pi-sessions-plugin-version-schema-heal
Jun 15, 2026
Merged

fix(pi): heal sessions/memory schema so plugin_version column lands#264
khustup2 merged 3 commits into
mainfrom
fix/pi-sessions-plugin-version-schema-heal

Conversation

@khustup2

@khustup2 khustup2 commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Problem

The pi agent extension (pi/extension-source/hivemind.ts) hard-codes its sessions/memory CREATE TABLE inline instead of going through DeeplakeApi.ensureSessionsTable / healMissingColumns like every other agent (claude-code, codex, cursor, hermes).

When plugin_version was added to the canonical SESSIONS_COLUMNS (2026-05-18), the pi INSERT picked it up but the inline CREATE did not — so every pi-created sessions table was 13 columns from birth, and pi had no schema-heal to add the missing column. Result: every session write failed with

column "plugin_version" of relation "sessions" does not exist   (sqlstate 42703)

…permanently, with no recovery. Diagnosed in prod: pi org c2d29f27 generated 230 real 42703s over 2 days and ran zero information_schema introspections (pi never heals), while claude-code/codex/cursor/hermes orgs self-healed. The org's sessions dataset was literally "initialized with 13 columns" — the stale pi CREATE.

Fix

  • Add plugin_version to the inline sessCreate (and memCreate for consistency) so fresh pi tables match the canonical schema.
  • Add a session_start schema-heal: introspect information_schema once and ALTER ADD COLUMN only the genuinely-missing columns (never IF NOT EXISTS — Deeplake returns HTTP 500 when the column already exists). Best-effort so it never blocks capture. Existing 13-column pi tables self-heal on next start.
  • Lock an INSERT ⊆ CREATE schema-consistency invariant in the pi source test so the two can never silently drift again (the same source-level guard style as the existing message_embedding check).

Tests

  • tests/pi/pi-extension-source.test.ts: two new invariants — fail before the fix (missing: ['plugin_version']), pass after.
  • 106/106 pi + shared-schema tests pass.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added plugin_version tracking to session and memory tables.
  • Bug Fixes
    • Improved schema consistency by automatically healing missing plugin_version columns after the sessions table becomes queryable (non-blocking).
  • Tests
    • Added/expanded tests to verify session INSERT column lists match the canonical CREATE TABLE definitions, including plugin_version.
    • Added shared checks to prevent column drift between agent-maintained session INSERT statements and the canonical schema.

The pi extension hard-codes its sessions/memory CREATE TABLE inline instead
of going through DeeplakeApi.ensureSessionsTable / healMissingColumns like the
other agents. When `plugin_version` was added to the canonical schema
(2026-05-18) the pi INSERT picked it up but the inline CREATE did not, so every
pi-created sessions table was one column short from birth and every INSERT
failed with `column "plugin_version" of relation "sessions" does not exist`
(42703) — with no heal to recover (e.g. prod org c2d29f27 ran zero schema
introspections while peers self-healed).

- Add plugin_version to the inline sessCreate (and memCreate) so fresh tables
  match the canonical schema.
- Add a session_start schema-heal: introspect information_schema once and
  ALTER ADD COLUMN only the genuinely-missing columns (never IF NOT EXISTS —
  Deeplake returns 500 when the column already exists). Best-effort so it never
  blocks capture. Existing 13-column pi tables self-heal on next start.
- Lock an INSERT ⊆ CREATE schema-consistency invariant in the pi source test
  so the two can never silently drift again.
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a plugin_version column (with default) to the MEMORY_TABLE and SESSIONS_TABLE CREATE TABLE definitions in hivemind.ts. After the sessions table becomes queryable, a non-blocking schema heal routine introspects information_schema.columns and issues ALTER TABLE ADD COLUMN for any missing plugin_version columns. Regression tests enforce INSERT/CREATE column consistency in the pi extension, and a new canonical schema test validates all agent hooks maintain columns matching the canonical SESSIONS_COLUMNS.

Changes

plugin_version Column and Schema Heal

Layer / File(s) Summary
Add plugin_version to CREATE TABLE DDL
pi/extension-source/hivemind.ts
plugin_version column (with default) is inserted into the MEMORY_TABLE and SESSIONS_TABLE CREATE TABLE statements used during session_start.
Post-session schema heal routine
pi/extension-source/hivemind.ts
After polling for the sessions table to become visible, queries information_schema.columns for both tables and issues ALTER TABLE ... ADD COLUMN plugin_version for any missing columns; all errors are caught and logged without blocking capture.
PI extension regression tests
tests/pi/pi-extension-source.test.ts
Helper functions parse hivemind.ts source via regex to extract INSERT column lists and CREATE TABLE definitions; test cases assert every INSERT column exists in CREATE, that plugin_version appears in both, and that SCHEMA_HEAL includes heal entries for both tables.
Canonical schema validation test
tests/shared/agent-sessions-insert-schema.test.ts
New test module validates that all agent hook sessions INSERT column lists are subsets of the canonical SESSIONS_COLUMNS, preventing column-drift issues across the agent ecosystem.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • kaghni
  • efenocchi

Poem

🐇 A new column hops into tables with care,
plugin_version finds its rightful lair.
Old schemas get healed with ALTER TABLE grace,
While tests guard the columns in every place.
From pi to all agents, the schema stays tight—
A rabbit-blessed sync, perfectly right! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main fix: adding the plugin_version column to pi's sessions/memory schema and implementing automatic healing.
Description check ✅ Passed The description comprehensively covers the problem (schema mismatch causing 42703 errors), fix (adding plugin_version and schema-heal), and tests. However, the Version Bump section from the template is not completed.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/pi-sessions-plugin-version-schema-heal

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.

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

No src/*.ts files changed in this PR.

Generated for commit 431012e.

@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

🧹 Nitpick comments (2)
tests/pi/pi-extension-source.test.ts (1)

61-69: ⚡ Quick win

Add a regression guard for the schema-heal contract too.

These assertions prove fresh-table sessions DDL is correct, but they stay green if SCHEMA_HEAL drops plugin_version or stops healing MEMORY_TABLE—which would re-break pre-existing 13-column pi tables while the suite still passes. Please add a source-level assertion that the heal config covers both tables with plugin_version TEXT NOT NULL DEFAULT ''.

As per coding guidelines, tests/**: "Prefer asserting on specific values (paths, messages) over generic substrings."

🤖 Prompt for 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.

In `@tests/pi/pi-extension-source.test.ts` around lines 61 - 69, The current tests
verify that plugin_version exists in sessionsCreateColumns() and
sessionsInsertColumns(), but they do not verify the SCHEMA_HEAL configuration
itself, which could drop plugin_version or fail to heal MEMORY_TABLE while tests
still pass. Add a new regression test after the existing plugin_version
assertions that directly verifies the SCHEMA_HEAL config includes both the
sessions table and MEMORY_TABLE with the exact column specification
plugin_version TEXT NOT NULL DEFAULT '', using specific value assertions (not
substring matching) to ensure the heal contract is properly enforced.

Source: Coding guidelines

pi/extension-source/hivemind.ts (1)

1308-1310: 🏗️ Heavy lift

Keep the heal set sourced from the full inline schema.

SCHEMA_HEAL only knows about plugin_version, so the next column added to the canonical memory/sessions schema will strand already-created pi tables again even if memCreate/sessCreate are updated. The shared path heals against the full column list for exactly this reason; please generate the CREATE SQL and the heal list from the same local column definitions so existing tables keep self-healing on future schema changes.

🤖 Prompt for 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.

In `@pi/extension-source/hivemind.ts` around lines 1308 - 1310, The SCHEMA_HEAL
array is hardcoded with only the plugin_version column, which means future
schema changes won't be automatically healed in existing tables. Instead of
maintaining SCHEMA_HEAL as a separate hardcoded list, generate it from the same
column definitions used to create the SESSIONS_TABLE and MEMORY_TABLE in the
memCreate and sessCreate functions. Extract the column definitions from those
creation statements and dynamically build SCHEMA_HEAL to include all missing
columns from the canonical schema, ensuring that any future columns added to the
table creation logic will automatically be included in the heal logic.
🤖 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 `@pi/extension-source/hivemind.ts`:
- Around line 1314-1318: The dlQuery call in the information_schema columns
selection is directly interpolating the table name and creds.workspaceId into
the SQL string without escaping, which allows SQL injection if either value
contains a single quote. Escape both the table and creds.workspaceId values
before interpolating them into the query string, or use parameterized query
parameters if the dlQuery function supports them, to prevent the query from
becoming invalid or allowing malicious injection.

---

Nitpick comments:
In `@pi/extension-source/hivemind.ts`:
- Around line 1308-1310: The SCHEMA_HEAL array is hardcoded with only the
plugin_version column, which means future schema changes won't be automatically
healed in existing tables. Instead of maintaining SCHEMA_HEAL as a separate
hardcoded list, generate it from the same column definitions used to create the
SESSIONS_TABLE and MEMORY_TABLE in the memCreate and sessCreate functions.
Extract the column definitions from those creation statements and dynamically
build SCHEMA_HEAL to include all missing columns from the canonical schema,
ensuring that any future columns added to the table creation logic will
automatically be included in the heal logic.

In `@tests/pi/pi-extension-source.test.ts`:
- Around line 61-69: The current tests verify that plugin_version exists in
sessionsCreateColumns() and sessionsInsertColumns(), but they do not verify the
SCHEMA_HEAL configuration itself, which could drop plugin_version or fail to
heal MEMORY_TABLE while tests still pass. Add a new regression test after the
existing plugin_version assertions that directly verifies the SCHEMA_HEAL config
includes both the sessions table and MEMORY_TABLE with the exact column
specification plugin_version TEXT NOT NULL DEFAULT '', using specific value
assertions (not substring matching) to ensure the heal contract is properly
enforced.
🪄 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: CHILL

Plan: Pro Plus

Run ID: 2dce2cb9-3cac-4663-a4b4-c5304c77a3d7

📥 Commits

Reviewing files that changed from the base of the PR and between c8cda4f and 9429e45.

📒 Files selected for processing (2)
  • pi/extension-source/hivemind.ts
  • tests/pi/pi-extension-source.test.ts

Comment thread pi/extension-source/hivemind.ts
…S_COLUMNS

The other agents (claude_code/codex/cursor/hermes + session-queue) hand-maintain
their own inline sessions INSERT column lists — the same shape of drift that
broke pi (INSERT wrote plugin_version, schema didn't). They derive CREATE + heal
from SESSIONS_COLUMNS, so the protecting invariant is INSERT ⊆ SESSIONS_COLUMNS.
They all satisfy it today; this locks it so the pi 42703 bug can't reappear in
any agent via a future INSERT edit that adds a column not in the canonical set.
@CLAassistant

CLAassistant commented Jun 14, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@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.

🧹 Nitpick comments (1)
tests/shared/agent-sessions-insert-schema.test.ts (1)

6-39: ⚡ Quick win

Well-structured guard against schema drift.

The regex-based extraction correctly anchors on the canonical leading columns and normalizes case. The assertion on line 33 will fail clearly if the pattern is missing, and the outer test description (line 43) will show which file was being processed.

💬 Optional: improve error message for regex mismatch

Consider adding a descriptive message to the assertion on line 33:

-  expect(m).not.toBeNull();
+  expect(m, 'sessions INSERT with canonical leading columns (id, path, filename, message, ...) not found').not.toBeNull();

This would make failures slightly easier to debug, though the current approach is already adequate.

🤖 Prompt for 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.

In `@tests/shared/agent-sessions-insert-schema.test.ts` around lines 6 - 39, The
assertion on line 33 in the sessionsInsertColumns function can be improved by
adding a descriptive error message as the second parameter to the expect() call.
This message should explain what the regex pattern is looking for (the canonical
leading columns of the INSERT statement) and help developers understand why the
pattern match failed. This makes test failures easier to debug when the regex
fails to match the expected structure in one of the files listed in
SESSIONS_INSERT_FILES.
🤖 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.

Nitpick comments:
In `@tests/shared/agent-sessions-insert-schema.test.ts`:
- Around line 6-39: The assertion on line 33 in the sessionsInsertColumns
function can be improved by adding a descriptive error message as the second
parameter to the expect() call. This message should explain what the regex
pattern is looking for (the canonical leading columns of the INSERT statement)
and help developers understand why the pattern match failed. This makes test
failures easier to debug when the regex fails to match the expected structure in
one of the files listed in SESSIONS_INSERT_FILES.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c847a3ba-cf8a-4083-ac03-b4a1c318b0b4

📥 Commits

Reviewing files that changed from the base of the PR and between 9429e45 and 7c20e93.

📒 Files selected for processing (1)
  • tests/shared/agent-sessions-insert-schema.test.ts

…contract

- Escape table + workspaceId with sqlStr in the schema-heal information_schema
  query (matches buildIntrospectionSql); an unescaped quote in a custom
  HIVEMIND_*_TABLE / workspace id would otherwise break the heal and silently
  disable recovery.
- Add a test that locks the SCHEMA_HEAL contract (heals both sessions + memory
  for plugin_version), so dropping it can't silently re-break existing tables.

@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.

🧹 Nitpick comments (1)
tests/pi/pi-extension-source.test.ts (1)

77-86: ⚡ Quick win

Consider parsing the SCHEMA_HEAL structure instead of substring checks.

The test uses generic substring checks (lines 81-82) and a count-based assertion (line 85), which is inconsistent with the existing test helpers (sessionsInsertColumns(), sessionsCreateColumns()) that parse the source into structured arrays. As per coding guidelines, tests should prefer asserting on specific values over generic substrings.

The current approach could miss structural issues, such as:

  • A table appearing in the wrong position within a tuple
  • A third table accidentally added
  • The healing entry paired with the wrong table
♻️ Suggested refactor to parse and verify the structure
- it("session_start SCHEMA_HEAL heals sessions + memory tables for plugin_version", () => {
-   const block = PI_SRC.match(/const SCHEMA_HEAL[^=]*=\s*\[([\s\S]*?)\];/);
-   expect(block).not.toBeNull();
-   const heal = block![1];
-   expect(heal).toContain("SESSIONS_TABLE");
-   expect(heal).toContain("MEMORY_TABLE");
-   const pluginVersionHeals =
-     heal.match(/\["plugin_version",\s*"TEXT NOT NULL DEFAULT ''"\]/g) ?? [];
-   expect(pluginVersionHeals.length).toBeGreaterThanOrEqual(2);
- });
+ function parseSchemaHeal(): Map<string, string[]> {
+   const block = PI_SRC.match(/const SCHEMA_HEAL[^=]*=\s*\[([\s\S]*?)\];/);
+   expect(block).not.toBeNull();
+   const entries = new Map<string, string[]>();
+   // Match each [TABLE_NAME, [[col, type], ...]] tuple
+   for (const m of block![1].matchAll(/\[([A-Z_]+),\s*\[([\s\S]*?)\]\]/g)) {
+     const table = m[1];
+     const colDefs = m[2];
+     const cols: string[] = [];
+     for (const col of colDefs.matchAll(/\["([^"]+)",\s*"[^"]+"\]/g)) {
+       cols.push(col[1]);
+     }
+     entries.set(table, cols);
+   }
+   return entries;
+ }
+
+ it("session_start SCHEMA_HEAL heals sessions + memory tables for plugin_version", () => {
+   const heal = parseSchemaHeal();
+   expect(heal.has("SESSIONS_TABLE")).toBe(true);
+   expect(heal.has("MEMORY_TABLE")).toBe(true);
+   expect(heal.get("SESSIONS_TABLE")).toEqual(["plugin_version"]);
+   expect(heal.get("MEMORY_TABLE")).toEqual(["plugin_version"]);
+ });

This approach:

  • Parses the actual array structure into a Map<table, columns[]>
  • Asserts specific table names and their exact column lists
  • Would catch if plugin_version is missing, duplicated, or paired with the wrong table
  • Follows the same pattern as the existing sessionsInsertColumns() / sessionsCreateColumns() helpers
🤖 Prompt for 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.

In `@tests/pi/pi-extension-source.test.ts` around lines 77 - 86, The test
currently uses generic substring checks with toContain() and count-based
assertions on the SCHEMA_HEAL structure, which is inconsistent with existing
test helpers like sessionsInsertColumns() and sessionsCreateColumns(). Refactor
this test to parse the SCHEMA_HEAL array into a structured format (such as a Map
mapping table names to their column definitions), then replace the generic
substring assertions with specific assertions on the parsed structure. Verify
that the SESSIONS_TABLE and MEMORY_TABLE are present with their exact column
lists, and check that the plugin_version column with its specific definition
appears in the correct tables, rather than relying on substring matching and
length counts.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@tests/pi/pi-extension-source.test.ts`:
- Around line 77-86: The test currently uses generic substring checks with
toContain() and count-based assertions on the SCHEMA_HEAL structure, which is
inconsistent with existing test helpers like sessionsInsertColumns() and
sessionsCreateColumns(). Refactor this test to parse the SCHEMA_HEAL array into
a structured format (such as a Map mapping table names to their column
definitions), then replace the generic substring assertions with specific
assertions on the parsed structure. Verify that the SESSIONS_TABLE and
MEMORY_TABLE are present with their exact column lists, and check that the
plugin_version column with its specific definition appears in the correct
tables, rather than relying on substring matching and length counts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1618b4c8-9b1f-47a6-915e-f93e2730b873

📥 Commits

Reviewing files that changed from the base of the PR and between 7c20e93 and 612b384.

📒 Files selected for processing (2)
  • pi/extension-source/hivemind.ts
  • tests/pi/pi-extension-source.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • pi/extension-source/hivemind.ts

@khustup2 khustup2 merged commit cf36747 into main Jun 15, 2026
11 checks passed
@khustup2 khustup2 deleted the fix/pi-sessions-plugin-version-schema-heal branch June 15, 2026 01:44
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.

3 participants