馃攳 Problem Description
OpenCode V2 emits durable session.inbox.enqueued events that can replay after restart. PR #1240 deduplicates a live local prompt by (session_id, source_inbox_id), but sync/export/import drops that identity and deletion retains only a sync_id tombstone. After restore or delete, a replay can insert the same admitted message again. This cross-package storage and HTTP contract exceeds adapter issue #1220 and needs its own approval.
馃挕 Proposed Solution
Introduce optional source_inbox_id for prompt writes through the local store and /prompts. Keep a unique identity per (session_id, source_inbox_id) for nonempty IDs: replay returns the existing result without a new row, sync mutation, or write notification; distinct IDs with identical text remain distinct. Carry that identity in prompt sync push/pull and export/import, including restored rows. On deletion retain identity in the existing tombstone lifecycle; replays of the deleted inbox ID must not resurrect a prompt or enqueue an upsert, including after sync/restore. A new inbox ID is a new message. Existing clients omitting the field keep append-per-request behavior. Preserve project ownership and previous wire compatibility.
Acceptance: focused store and server regressions for same-key replay, same text/different IDs, legacy no-ID clients, sync push/pull plus export/import round-trip, and delete-then-replay locally and after restore; assert no redundant notification or sync mutation. Document the optional HTTP field and deletion semantics. No V2 hook, installer, UI, or generic cross-version adapter framework in this issue.
馃摝 Affected Area
Store (database, queries), local HTTP API, and Sync (multi-instance).
馃攧 Alternatives Considered
AddPromptIfMissing uses content as identity and collapses distinct admitted messages with identical text; an in-memory adapter set is lost on restart. Allowing the deleted key to reinsert would undo an intentional deletion.
馃搸 Additional Context
Foundation dependency for #1240; approved #1220 remains the V2 adapter/setup feature. Build this PR from main so the adapter diff is not imported. Preserve contributor history: after the foundation merges, integrate it into #1240 with a normal merge, not a rebase or force-push.
馃攳 Problem Description
OpenCode V2 emits durable
session.inbox.enqueuedevents that can replay after restart. PR #1240 deduplicates a live local prompt by(session_id, source_inbox_id), but sync/export/import drops that identity and deletion retains only async_idtombstone. After restore or delete, a replay can insert the same admitted message again. This cross-package storage and HTTP contract exceeds adapter issue #1220 and needs its own approval.馃挕 Proposed Solution
Introduce optional
source_inbox_idfor prompt writes through the local store and/prompts. Keep a unique identity per(session_id, source_inbox_id)for nonempty IDs: replay returns the existing result without a new row, sync mutation, or write notification; distinct IDs with identical text remain distinct. Carry that identity in prompt sync push/pull and export/import, including restored rows. On deletion retain identity in the existing tombstone lifecycle; replays of the deleted inbox ID must not resurrect a prompt or enqueue an upsert, including after sync/restore. A new inbox ID is a new message. Existing clients omitting the field keep append-per-request behavior. Preserve project ownership and previous wire compatibility.Acceptance: focused store and server regressions for same-key replay, same text/different IDs, legacy no-ID clients, sync push/pull plus export/import round-trip, and delete-then-replay locally and after restore; assert no redundant notification or sync mutation. Document the optional HTTP field and deletion semantics. No V2 hook, installer, UI, or generic cross-version adapter framework in this issue.
馃摝 Affected Area
Store (database, queries), local HTTP API, and Sync (multi-instance).
馃攧 Alternatives Considered
AddPromptIfMissinguses content as identity and collapses distinct admitted messages with identical text; an in-memory adapter set is lost on restart. Allowing the deleted key to reinsert would undo an intentional deletion.馃搸 Additional Context
Foundation dependency for #1240; approved #1220 remains the V2 adapter/setup feature. Build this PR from
mainso the adapter diff is not imported. Preserve contributor history: after the foundation merges, integrate it into #1240 with a normal merge, not a rebase or force-push.