You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Design: store generation detection for 1.18→2.x migrated opencode stores (backs PR #486) #489
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.
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.
Thank you for laying out D1 and D2 explicitly. The schema evidence supports a narrower conclusion than D1: session_v2 is an unambiguous marker that OpenCode 2 has touched the store, but not an unambiguous marker of the current writer. In the downgrade case the table remains while OpenCode 1 resumes writing message/part, so a global session_v2 => v2 rule rejects active v1 readers and can select frozen v2 rows.
The decision is #477's approach for the runtime defect, now on master (2c034c3): keep mixed-store detection conservative and allow an explicitly expected v2 reader when both session_message and session_v2 exist. That fixes the migrated OpenCode 2 prompt interruption without breaking downgraded stores.
D2's capability-based backfill gate is sound and we will carry it as a separate follow-up with credit to you. It is hardening rather than a prerequisite, because #477 leaves mixed detection as v1 and the existing backfill assertion already passes on that shape.
We will also follow up on doctor's table selection: #477's host override is wrong in the pre-migration upgrade window, and its fallback does not cover migrated Desktop installations. That diagnostic needs to combine host and store state, since table presence alone cannot distinguish a migrated v2 store from the same store after a downgrade. This issue stays open until the D2 follow-up lands.
Agreed on D1 — your downgrade analysis is exactly right, and I can confirm it with a live case: this reporter's machine just went through that path (OpenCode 2.0.8 → 1.18.31 rollback last night, with message/part restored beside the retained session_message/session_v2). My global session_v2 => v2 rule would have rejected the active 1.18 v1 reader on exactly this shape. #477's two-channel approach (conservative detect for expected-v1 readers, widened acceptance only for explicitly-expected-v2 readers) is the correct shape — closing #486 as superseded.
D2 as a credited follow-up works for us; the capability-based gate composes cleanly on top of either detection path. Happy to review the follow-up when it lands.
Implemented in 0.43.0, released today, with credit. Store generation detection now handles OpenCode stores migrated from 1.18 to 2.x, using the capability-gate shape from PR 486, and doctor picks its boundary table from the resolved host generation combined with the store schema. Thanks for the design and the live downgrade case.
Activity
magic-alfonso commentedon Sep 20, 2026
Thank you for laying out D1 and D2 explicitly. The schema evidence supports a narrower conclusion than D1:
session_v2is an unambiguous marker that OpenCode 2 has touched the store, but not an unambiguous marker of the current writer. In the downgrade case the table remains while OpenCode 1 resumes writingmessage/part, so a globalsession_v2 => v2rule rejects active v1 readers and can select frozen v2 rows.The decision is #477's approach for the runtime defect, now on master (2c034c3): keep mixed-store detection conservative and allow an explicitly expected v2 reader when both
session_messageandsession_v2exist. That fixes the migrated OpenCode 2 prompt interruption without breaking downgraded stores.D2's capability-based backfill gate is sound and we will carry it as a separate follow-up with credit to you. It is hardening rather than a prerequisite, because #477 leaves mixed detection as v1 and the existing backfill assertion already passes on that shape.
We will also follow up on doctor's table selection: #477's host override is wrong in the pre-migration upgrade window, and its fallback does not cover migrated Desktop installations. That diagnostic needs to combine host and store state, since table presence alone cannot distinguish a migrated v2 store from the same store after a downgrade. This issue stays open until the D2 follow-up lands.
DGVY commentedon Sep 20, 2026
Agreed on D1 — your downgrade analysis is exactly right, and I can confirm it with a live case: this reporter's machine just went through that path (OpenCode 2.0.8 → 1.18.31 rollback last night, with
message/partrestored beside the retainedsession_message/session_v2). My globalsession_v2 => v2rule would have rejected the active 1.18 v1 reader on exactly this shape. #477's two-channel approach (conservative detect for expected-v1 readers, widened acceptance only for explicitly-expected-v2 readers) is the correct shape — closing #486 as superseded.D2 as a credited follow-up works for us; the capability-based gate composes cleanly on top of either detection path. Happy to review the follow-up when it lands.
magic-alfonso commentedon Sep 24, 2026
Implemented in 0.43.0, released today, with credit. Store generation detection now handles OpenCode stores migrated from 1.18 to 2.x, using the capability-gate shape from PR 486, and doctor picks its boundary table from the resolved host generation combined with the store schema. Thanks for the design and the live downgrade case.