Skip to content

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

Description

@DGVY

Context

OpenCode's official 1.18 → 2.x in-place upgrade keeps the retired message/part tables beside the new session_v2/session_message ones. detectOpenCodeStoreGeneration is keyed on v1-table presence, so every migrated store reads as v1 — and the v2 fail-closed assert then refuses generation-specific access on every read. On opencode 2.0.5/2.0.8 hosts this surfaces as every prompt interrupting within ~20 ms (session hook dies during setup, host swallows the error, zero log lines). Full incident write-up in PR #486.

Design decisions in PR #486

D1 — session_v2 table presence is the strongest v2 signal, checked first.
1.18.x never creates session_v2; every 2.x store has it from first write. The v1 heuristic (message+part) stays as the fallback for pure 1.18.x stores. Consequence: migrated stores (both table sets) classify as v2, which is correct — the v2 readers are the ones that must own them.

D2 — the tool-owner backfill gates on what it reads, not on a single generation.
The backfill reads the v1 message/part tables, which exist in pure v1 stores and in migrated stores. Asserting expected "v1" (the pre-existing hard-code) throws on migrated stores at normal database open, silently degrading every eligible legacy row to the slower lazy-adoption fallback — flagging exactly the stores that most need backfill (tens of thousands of legacy rows). New hasV1MessageTables(db, schema) helper: tables present → backfill runs; absent (pure v2) → fail fast with a clearer message.

Alternatives rejected

  • Tolerate both generations in every reader (no detection change): spreads "v1-or-v2" branching through every query site; the fail-closed guard exists precisely to prevent that.
  • PRAGMA user_version bump: the opencode host owns that schema; a plugin-side convention on host-owned metadata is fragile across host versions.
  • Row-count heuristics (e.g. "v2 tables non-empty → v2"): a migrated store that upgraded before writing any v2 row would misclassify; table existence is decided by DDL, not workload.

Verification

  • Unit tests cover all four store shapes: pure v1, pure v2, migrated (both table sets), fresh/unknown — pinned live-1.18 fixture unchanged and passing.
  • shared + v2 + features suites: 2197 pass / 1 fail, the failure (transformers-node-wasm fixture, network model build) reproduces on unmodified master under the same sandbox.
  • Exercised on a real migrated store (~46k legacy message rows, opencode 2.0.8 host): pre-patch every prompt died in <20 ms; post-patch the full chain (session hook, compaction, memory) is healthy.

Requesting design-approved so PR #486 can proceed past the design gate. If maintainers consider this a trivial fix, the gate also accepts the trivial label on the PR itself — either way works.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions