Skip to content

feat(migrations): Unify schema and data journals#896

Draft
dcramer wants to merge 4 commits into
mainfrom
codex/unified-migration-journals
Draft

feat(migrations): Unify schema and data journals#896
dcramer wants to merge 4 commits into
mainfrom
codex/unified-migration-journals

Conversation

@dcramer

@dcramer dcramer commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

  • add the publishable @sentry/junior-migrations package for mixed SQL and TypeScript Drizzle journals
  • generate 0001_name.ts data migrations through the same Drizzle Kit workflow used for schema migrations
  • run core and enabled-plugin migrations through one ordered, resumable journal runner
  • expose the exact host database adapter as context.database instead of rebuilding partial SQL capabilities
  • embed every historical data migration implementation directly in its migration file
  • add an append-only @sentry/junior/migration-helpers/v1 export for reusable parsers, stores, adapters, and key resolution
  • remove context.tasks, plugin migrationTasks, and the duplicate hardcoded migration implementations from Junior runtime code
  • include the new package in Craft, CI, release alignment, package validation, and migration documentation

Migration contract

Each journal entry resolves to exactly one immutable <tag>.sql or <tag>.ts file. TypeScript migrations target the versioned MigrationV1 capability API and contain their permanent parsers, transforms, and migration-specific helpers. They cannot import relative application modules or unversioned @sentry/junior modules. They may import the append-only @sentry/junior/migration-helpers/v1 surface for infrastructure helpers, while one-off record transformations remain owned by the migration file.

The runner tracks each entry by its journal timestamp and source hash, persists resumable TypeScript progress, serializes execution with the owning SQL lock, and supports SQL-only setup where tests or bootstrap paths do not have data-migration capabilities. TypeScript entries receive the same database adapter used by the journal runner, so connection setup, drivers, transactions, and lock implementations are not duplicated into frozen migrations.

Drizzle Kit remains the authoring and snapshot system. Its stock migrate() executor is intentionally unsupported for mixed journals; Junior and plugins execute them through runMigrationJournal.

Test Plan

  • pnpm --filter @sentry/junior-migrations test
  • typecheck @sentry/junior-migrations, @sentry/junior-plugin-api, @sentry/junior-scheduler, and @sentry/junior
  • run 53 focused core, plugin, scheduler, legacy-history, and conversation migration tests
  • pnpm lint
  • pnpm release:check
  • pnpm docs:check
  • git diff --check

Add a publishable migration package that executes SQL and TypeScript entries
from one Drizzle-compatible journal. Route core and plugin upgrades through the
shared runner so schema changes and resumable data migrations use one ordered
ledger.

Keep historical scripts isolated behind versioned capabilities, and wire the
package into release, CI, Craft, documentation, and package validation.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview Jul 14, 2026 12:13am

Request Review

Comment thread packages/junior-migrations/package.json
Comment thread packages/junior/src/chat/conversations/sql/migrations.ts
Remove the migration task registry and keep historical data migration code in each journal entry. This prevents future runtime refactors or deletions from breaking pending upgrades.

Expose versioned migration capabilities, move scheduler and core backfills into their migration files, and update migration tests and documentation.

Co-Authored-By: GPT-5.6 Codex <noreply@openai.com>
Comment thread packages/junior/migrations/0005_redis_conversation_state.ts
Comment thread packages/junior/migrations/0006_conversations_to_sql.ts Outdated
Expose the exact host database adapter through MigrationContextV1 instead of reconstructing a partial SQL capability.

Rebuild the SQL-heavy frozen migrations without connection setup and driver implementations so migrations retain transformation logic without duplicating database infrastructure.

Co-Authored-By: GPT-5.6 Codex <noreply@openai.com>
return {
bot: botConfig,
state: { keyPrefix: process.env.JUNIOR_STATE_KEY_PREFIX?.trim() || void 0 },
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Advisor import builds broken adapter

High Severity

When a conversation has advisor/subagent history and no advisorSessionStore is injected, importConversationFromLegacy falls back to createLegacyAdvisorSessionReader, which calls capsule getStateAdapter(). The stub getChatConfig only exposes keyPrefix and omits adapter/redisUrl, so createStateAdapter throws REDIS_URL is required even when REDIS_URL is set in the environment.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b26c218. Configure here.

Allow migrations to import append-only infrastructure helpers from @sentry/junior/migration-helpers/v1 while continuing to reject unversioned Junior runtime imports.

Keep one-off Redis transformations and backfill decisions in their journal entries, replace generated capsules for migrations 0004 through 0006 with readable source, and publish explicit helper types without private module references.

Co-Authored-By: GPT-5.6 Codex <noreply@openai.com>

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fd37ff2. Configure here.

SET status = 'completed', result = $1, completed_at = NOW()
WHERE created_at = $2`,
[result ?? null, args.migration.when],
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

JSONB params break on strings

Medium Severity

progress.save and the migration result write bind MigrationJsonValue directly into JSONB columns. For string primitives, node-pg sends the raw text rather than a JSON-encoded string, so values like a string cursor fail with invalid JSON syntax. Objects work because they are stringified; the public value type still allows strings.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fd37ff2. Configure here.

...current
} = run;
return current;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Scheduler migration under-validates records

Medium Severity

The embedded scheduler data migration accepts tasks and runs after checking only a few fields, then inserts them into SQL. The removed migrateSchedulerStateToSql path used strict schema parsing before write, and the SQL readers still use those strict schemas, so partial or legacy-shaped Redis records can be stored as rows the runtime later silently drops.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fd37ff2. Configure here.

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.

1 participant