Problem
resolveBindingOutcome in packages/opencode/src/altimate/workspace/state.ts scopes its per-process caches — lastValidatedAt, serverLookupMissed (via accountScopedKey) — and the on-disk binding cache by tenantKey(), which is {tenant, apiUrl} only. Two accounts on the same tenant and API host therefore share those entries.
Sequence (raised as MAJOR by the multi-model review on #1338; confirmed in the source):
- Alice resolves a linked project.
lastValidatedAt[tenant|apiUrl|dir] is stamped and the binding is written to the disk cache.
- Within
REVALIDATE_MS (5 min) the credentials switch to Bob — same tenant, same host, different personal API key.
- Bob's resolve sees the fresh stamp and returns Alice's cached binding as
bound with no server check. Whatever rides on the binding (skill-sync, memory-sync, the identity line) is attributed to the wrong account for up to five minutes.
This is the layer under the two caches v0.12.1 did scope by credential digest (identity's memo, and pinValidation in resolvePinnedBinding, which set the pattern). Not a warehouse-authorization bypass — that check is server-side — and not a regression: tenantKey/accountScopedKey predate v0.12.x.
Expected
Thread a short credential digest (the sha256(apiKey).slice(0,16) pattern resolvePinnedBinding already uses) through tenantKey(), accountScopedKey() and the disk-cache scope, so a same-tenant account switch never inherits the other account's fast path. Note the migration effect: re-keying the disk cache invalidates every existing cached binding once (one extra server round-trip per project after upgrade), and the sidebar, skill-sync and memory-sync callers read the same scope — review them together.
Priority
Deferred. Switching accounts within one tenant mid-process is not a common workflow; the window is five minutes and the consequence is misattributed sync, not data access. Called out in the v0.12.1 CHANGELOG ("tracked separately").
Related: #1337 (routing ignores the IDE pin — different gap, same file), #1335.
🤖 Generated with Claude Code
https://claude.ai/code/session_012Q51zFUmPg1WwtS5CrGJE6
Problem
resolveBindingOutcomeinpackages/opencode/src/altimate/workspace/state.tsscopes its per-process caches —lastValidatedAt,serverLookupMissed(viaaccountScopedKey) — and the on-disk binding cache bytenantKey(), which is{tenant, apiUrl}only. Two accounts on the same tenant and API host therefore share those entries.Sequence (raised as MAJOR by the multi-model review on #1338; confirmed in the source):
lastValidatedAt[tenant|apiUrl|dir]is stamped and the binding is written to the disk cache.REVALIDATE_MS(5 min) the credentials switch to Bob — same tenant, same host, different personal API key.boundwith no server check. Whatever rides on the binding (skill-sync, memory-sync, the identity line) is attributed to the wrong account for up to five minutes.This is the layer under the two caches v0.12.1 did scope by credential digest (identity's memo, and
pinValidationinresolvePinnedBinding, which set the pattern). Not a warehouse-authorization bypass — that check is server-side — and not a regression:tenantKey/accountScopedKeypredate v0.12.x.Expected
Thread a short credential digest (the
sha256(apiKey).slice(0,16)patternresolvePinnedBindingalready uses) throughtenantKey(),accountScopedKey()and the disk-cache scope, so a same-tenant account switch never inherits the other account's fast path. Note the migration effect: re-keying the disk cache invalidates every existing cached binding once (one extra server round-trip per project after upgrade), and the sidebar, skill-sync and memory-sync callers read the same scope — review them together.Priority
Deferred. Switching accounts within one tenant mid-process is not a common workflow; the window is five minutes and the consequence is misattributed sync, not data access. Called out in the v0.12.1 CHANGELOG ("tracked separately").
Related: #1337 (routing ignores the IDE pin — different gap, same file), #1335.
🤖 Generated with Claude Code
https://claude.ai/code/session_012Q51zFUmPg1WwtS5CrGJE6