Dashboard › opencode › Distillation
fe5053f2-62ef-402c-8013-b97b8df7c4b0["lore_tm_v1_Jh1wGygOLnQ3fYFIkDHbw-DWqUfeHl2tewhnLRT0V2A","lore_tm_v1_0MJZGf9VwrQd-N067H2Syko74dBMwD_dAnrs5BRIoV8","lore_tm_v1_s0j9yTFYCSlUKF2DSTISolQtbx5h4vPDlsLaT9D9kGU","lore_tm_v1_aH6C06pnicC6RxQgOY0q2bx9s6OzwfvJsb1hfOuzveQ","lore_tm_v1_SCaSUkzkRRtPk5AFxuhix4W-O0jKL1MzVys8a5ppG2E","lore_tm_v1_k_m-idw117GWGzxS9n3VVMWE4DOtX7EBa_vE9J43akk","lore_tm_v1_i42IPWhCi5_RdlryukPxCgEABXvlWsekOkr_tjr_7oE","lore_tm_v1_WVCMisLcDM1vOxzKfVTbbj1unhzXuCgiacK1NLoNgJA","lore_tm_v1_fGuBHwn9PzThQc4Hlj7kHfsbRpMCZPJORdke2TWwA9M","lore_tm_v1_IgQqNWJbp8x2AlMOGDzk-9erMfpJxwu3qe0BJk4A0Rk","lore_tm_v1_2og3f3v11IvKiry2tScAHYtlG1wwiE7lkclkRna0e8Y","lore_tm_v1_AB5ON8OWERZxIFnOvhkfEoLc22CxAm9TpGf3-VMBcn0","lore_tm_v1_oMpGFw4WR6MjTf8JUrqxXGtlspkRv5NG_nlKuFyMZ7c"]
Date: Sep 16, 2026
ab9408c81cc9916177641ae8e9f08624fc27b5b9 only inside disposable tree /tmp/opencode/session-recovery-review-c2c8afb0, which contained no VCS metadata.packages/core/src/session/execution/claim.ts specifies wall-clock leases: the lease interval must exceed the deployment’s maximum clock skew plus one renewal interval, and execution IDs immediately fence a node after takeover.packages/core/src/session/execution/claim.ts, claim ownership is fenced by session_id, execution id, owner_id, and expires_at > now; SessionExecutionClaim.update() renews to now + SESSION_EXECUTION_LEASE_MS only when all predicates match and dies with SessionExecutionClaim.Lost otherwise. SessionExecutionClaim.clear() uses the same live-claim predicates, while transaction() performs update(db, claim) before the supplied effect in an immediate database transaction.packages/core/src/session/execution/local.ts, each local executor receives a random ownerID; each drain creates a random executionID, inserts one SessionExecutionTable row with phase "ready" and expiry now + SESSION_EXECUTION_LEASE_MS, and aborts if onConflictDoNothing() does not return a claim. Active claims are tracked by sessionID.packages/core/src/session/execution/local.ts races input.run(claim, force, recovery?.continuationMessageID) against repeated SessionExecutionClaim.update(db, claim) heartbeats scheduled every leaseDuration / 3. On successful exit it clears the claim; on non-interrupt failure it clears only when the stored phase is neither "unknown" nor "continue". interrupt(sessionID) clears the active claim and suppresses only SessionExecutionClaim.Lost.packages/core/src/session/execution/local.ts chooses the earliest SessionRecoveryTable row for the session where wake_pending = true and recovery_error IS NULL, ordered by time_created then execution_id, and passes its continuation_message_id to the runner.packages/core/src/session/run-coordinator.ts serializes execution per key while allowing different keys concurrently. run() starts with force = true when idle or joins active work; wake() coalesces one follow-up using pendingWake; successful settlement launches a successor when pending; and interrupt() marks the entry stopping, clears the existing pending wake, interrupts its owner, runs cleanup, then starts work that arrived during stopping.packages/core/src/session/input.ts excludes recovery continuation inputs from ordinary promotion: promoteSteers() and promoteNextQueued() left-join SessionRecoveryTable on continuation_message_id and require SessionRecoveryTable.execution_id IS NULL.SessionInput.promoteExact() in packages/core/src/session/input.ts requires the exact message ID, matching session ID, unpromoted state, and "queue" delivery. A missing row dies with Pending recovery input not found: ${messageID}. If publishing raises RecoveryConflict, it stores recovery_error = defect.reason only for the matching execution where wake_pending = true and recovery_error IS NULL, then re-dies with the conflict.