Skip to content

fix(store): detect 1.18→2.x migrated stores as v2 - #486

Open
DGVY wants to merge 2 commits into
cortexkit:masterfrom
DGVY:fix/migrated-store-generation
Open

DGVY wants to merge 2 commits into
cortexkit:masterfrom
DGVY:fix/migrated-store-generation

Conversation

@DGVY

@DGVY DGVY commented Sep 20, 2026

Copy link
Copy Markdown

Problem

A store that went through OpenCode's official 1.18 → 2.x in-place upgrade is misclassified as a v1 store, and the v2 fail-closed assert then refuses generation-specific access on every read:

[magic-context] v2 refuseIfUnsafe warn: OpenCode store generation mismatch at
~/.local/share/opencode/opencode.db: expected v2, found v1; refusing
generation-specific database access

The official migration keeps the retired message/part tables beside the new session_v2/session_message ones (tens of thousands of legacy rows on a long-lived install), so detectOpenCodeStoreGeneration — keyed on v1-table presence — reads every migrated store as v1.

Impact (observed on opencode 2.0.5/2.0.8 hosts)

Every prompt interrupts within ~20 ms of submission: the plugin's session hook fails during setup, the host swallows the error (zero server-side log lines at the moment of death), and no model call is ever made. Sessions show user → idle(interrupted) with no assistant turn. A clean-install store on the same host version works fine, which makes this look host-version-specific and sent us chasing opencode regressions for a long while before the mismatch warn surfaced in debug logs.

Fix

session_v2 is an unambiguous v2 signal — OpenCode 1.18.x never creates it while every 2.x store does — so prefer it over the v1-message heuristic:

if (tables.has("session_v2")) return "v2"   // new, strongest signal
if (tables.has("message") && tables.has("part")) return "v1"
...

Pure 1.18.x stores (no session_v2) keep reading as v1; the pinned live-1.18 fixture test is unchanged and still passes.

Tests

  • New: a migrated store (message+part+session+project+session_v2+session_message) detects as v2, asserts v2 fine, and asserts v1 throws.
  • Existing: 492 tests across packages/plugin/src/shared + src/v2 pass, 0 fail.

Related note

The 0.42.6 v2 lane also calls context.model.list() directly (pre-catalog shape), which throws on opencode 2.0.3 hosts whose plugin context predates the model domain — same swallowed-error instant-interrupt symptom. Main already uses context.catalog.model.list, so that one looks resolved on main; mentioning it here since the two combined made 0.42.6 fatal on 2.0.3.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fixes store generation detection so stores migrated through OpenCode's official 1.18 → 2.x upgrade are treated as v2 instead of v1, and keeps the legacy tool-owner backfill working on those stores.

Bug Fixes

  • session_v2 is now the strongest v2 signal; pure 1.18.x stores without it still detect as v1.
  • The backfill now checks for the v1 message tables directly instead of asserting a v1 store, so migrated stores are backfilled and pure v2 stores fail fast with a clearer message.
  • Adds a migrated-store test covering v2 detection, v2 assert pass, and v1 assert throw.
  • Restores bun.lock to the upstream resolution so bun install --frozen-lockfile passes.

Written for commit 145eb11. Summary will update on new commits.

Review in cubic

RetriggerConfidence Score: 4/5

The store-detection and backfill fixes appear sound, but the PR is not yet safe to merge because the lockfile still depends on an unconfigured third-party registry.

Findings

  1. P1 Third-party registry breaks installs
  2. P1 Migrated stores skip backfill
Summary

The PR corrects OpenCode store-generation detection and its related legacy owner-backfill behavior.

  • Treats session_v2 as the strongest v2 schema signal, including when migrated stores retain v1 tables.
  • Allows the owner backfill to process any store that still has the legacy message and part tables.
  • Adds regression coverage for generation detection and assertions on a migrated schema.
  • The earlier third-party registry change in bun.lock remains outstanding.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Inspect OpenCode schema] --> B{session_v2 exists?}
    B -->|Yes| C[Classify as v2]
    B -->|No| D{message and part exist?}
    D -->|Yes| E[Classify as v1]
    D -->|No| F{session_message exists?}
    F -->|Yes| C
    F -->|No| G[Empty or unknown]
    C --> H{Legacy message tables remain?}
    E --> H
    H -->|Yes| I[Run best-effort tool-owner backfill]
    H -->|No| J[Skip backfill and use lazy adoption]
Loading

Reviews (2) · Last reviewed commit: "fix(backfill): accept migrated stores in..."

Closes #489

A detector keyed on v1-table presence misclassifies every store that
went through OpenCode's official 1.18 → 2.x in-place upgrade: the
migration keeps the retired message/part tables beside the new
session_v2 ones, so the store reads as v1 and the v2 fail-closed
assert refuses generation-specific access on every read.

On opencode 2.x hosts this surfaced as every prompt interrupting
within ~20 ms of submission: the plugin's session hook fails during
setup, the host swallows the error, and no model call is ever made.

session_v2 is an unambiguous v2 signal — OpenCode 1.18.x never
creates it while every 2.x store does — so prefer it over the
v1-message heuristic. Pure 1.18.x stores (no session_v2) keep
reading as v1.
@cortexkit-ci

cortexkit-ci Bot commented Sep 20, 2026

Copy link
Copy Markdown

Waiting for design-approved on #489.

This PR needs a linked issue with the design-approved label before it can be reviewed or merged. Add Closes #<issue> to the description; a maintainer will apply the label on the issue once the design is agreed. Trivial fixes: a maintainer can add the trivial label to this PR instead.

Comment thread bun.lock
@@ -168,225 +168,225 @@
"adm-zip": "0.6.0",
},
"packages": {
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.82", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-WKKou2wbhGGYV8PSALAPyV2YY4nfCqCPkyBzYtJtDA9yCcIFwsbtkTNgg7bqtLCVzeEsY7wwxRoCWy+EMfrw/A=="],
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.82", "https://registry.npmmirror.com/@ai-sdk/anthropic/-/anthropic-3.0.82.tgz", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-WKKou2wbhGGYV8PSALAPyV2YY4nfCqCPkyBzYtJtDA9yCcIFwsbtkTNgg7bqtLCVzeEsY7wwxRoCWy+EMfrw/A=="],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Third-party registry breaks installs

The regenerated lockfile pins every dependency tarball to registry.npmmirror.com, although the repository has no committed configuration for that registry. CI uses bun install --frozen-lockfile, so an unavailable or blocked mirror will break installs across the project. Restore the default resolution entries or configure this registry as an intentional, separate change.

schema: "main" | "oc_backfill" = "main",
): OpenCodeStoreGeneration {
const tables = schemaTableNames(db, schema);
if (tables.has("session_v2")) return "v2";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Migrated stores skip backfill

Prioritizing session_v2 also affects runToolOwnerBackfill. Migrated stores retain the legacy message and part tables that this backfill reads, but this line now classifies them as v2 before the backfill's hard-coded v1 assertion. The assertion therefore throws during a normal database open, leaving eligible legacy tool-owner rows to the slower lazy-adoption fallback instead of completing the intended boot-time backfill. The backfill must explicitly accept migrated stores whose legacy tables remain.

Review feedback (PR cortexkit#486): prioritizing session_v2 also flipped
runToolOwnerBackfill's hard-coded v1 assert — migrated stores retain
the legacy message/part tables this backfill reads, but now detect as
v2, so the assert threw during a normal database open and every
eligible legacy row silently degraded to the slower lazy-adoption
fallback.

Gate on what the backfill actually needs — the v1 message tables
being present — via the new hasV1MessageTables helper, instead of
asserting a single generation. Pure v2 stores (tables absent) still
fail fast with a clearer message.

Also restore bun.lock to the upstream resolution (CI runs
bun install --frozen-lockfile; the local mirror-pinned regeneration
was flagged by review).
@DGVY

DGVY commented Sep 20, 2026

Copy link
Copy Markdown
Author

Both review findings addressed in 145eb11:

  • bun.lock: restored to the upstream resolution (the mirror-pinned regeneration came from my local install; CI's --frozen-lockfile would indeed break).
  • backfill: runToolOwnerBackfill no longer asserts a single generation — it now gates on the new hasV1MessageTables(db, "oc_backfill") helper, i.e. exactly what it reads. Migrated stores (v2 + legacy tables) backfill normally; pure v2 stores fail fast with a clearer "no v1 message tables; nothing to backfill" message.

Verified: shared+v2+features suites — 2197 pass, 1 fail where the failing test (transformers-node-wasm fixture, builds a model from network) also fails on unmodified master under the same sandbox, so it is unrelated to this change.

@DGVY

DGVY commented Sep 20, 2026

Copy link
Copy Markdown
Author

Linked design rationale in #489 (gate now reads "Waiting for design-approved on #489"). Happy to iterate there if any decision needs discussion — D1/D2 and the rejected alternatives are laid out per-decision. If this qualifies as trivial in your judgment, the trivial label on the PR works too.

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.

Design: store generation detection for 1.18→2.x migrated opencode stores (backs PR #486)

1 participant