Dashboard › opencode › Distillation
4b108490-ae38-4582-be6b-785df17e94c8["lore_tm_v1_NQqw4VcPppSj0n-DKl8iwtcDNR-h7yt_3BwC-AKVM1s","lore_tm_v1_iIIIfw-qeRQgQSfPi0oTW2aQB3N7bkSUkDJy5aUXOzc","lore_tm_v1_TyIggTrNwlRrWehpRl1GYAyDOlOjSeETUIeQZry8ZZA","lore_tm_v1_HPIj9fA00HRc4uT9KFM3VQI0BBdGMJVZf8m33fNrWKg","lore_tm_v1_9uCd_n4YrXiaJAmmePXLrJTD9hI5j3uX09YMELvBmc8","lore_tm_v1_T9loLNTeLUNJZkA-zLwBFCP0Y7w1bhhUr9zJr2yF2zk","lore_tm_v1_iI1CDkAojIxUldh9NIvySESvgBIY7NVl_9kNYFRkmTQ","lore_tm_v1_xWX3GL87pMq4g7S_73W9CfyoTpoTbxoce6TOpoMZOH0","lore_tm_v1_IGEPQCQbMVgHZDT3YojywGqFaGKWdaujFG4FcJrO4zw","lore_tm_v1_HFv6HvO6K4UQEXVJWskf8BjbwNQMvLqtbY_UyWy6Fkg","lore_tm_v1_3nNrqGf4q_R87-Q2vpmuWsuQVsVTmUbjsyaejXAy514","lore_tm_v1_UiMfi5EfuMselNvTdeRGQ966P9PkQ98SLtbnuBzOCWQ","lore_tm_v1_gRUKGIvByFVKfykH7NplGLCmRY1_LO3yaG1OWPYd96Q","lore_tm_v1_-Pn-H2gWtpy7p4MGxInUry9P6AdTwoErauXzZS2vZx8","lore_tm_v1_0efyIVTpJRC9AcEOVFHsoMlqTTftE9xLdHfFLy4sE64","lore_tm_v1_NS2mfiKTwilcYsa6HPLhQPU4Ek3xDkGYlCfl4NET-Bw","lore_tm_v1_ihZfB2btojlCFYcI6fE6XKOyb7aEP-Cb2aWZhthxYfk","lore_tm_v1_TO920f7ZWYCdChRV3037LqZPChTULVbAB3TcfOPEB08","lore_tm_v1_mlr7vMYCUE3gCrraEhWZWEVCf1U6ynx31Lc_0SWaUs4","lore_tm_v1_lShRhyKYqp6cuDliKvipUW5HigKg1faS4QUIyGz0Cvc","lore_tm_v1_8dulOVgb2KYrbDlVwfNLT2dHIrq6tyGk6DrKcw3EFCE","lore_tm_v1_KwA98zT8_ax-RmklM3VaLplq1nmo9pOdIKRpWX_4dSQ","lore_tm_v1_SFUUY_jRpCheBFZDeDhCGKlWzdZ53VZfLb6WulqWPQ0","lore_tm_v1_tfhBDKBX8ZPqURmB95ef95S1xmQtgj8c0LsmdRbsJlg","lore_tm_v1_3SaJk9kMJr9FCaX0scGSdzElob5Jznfx8laaCioZYcI","lore_tm_v1_Xj-jK9W7yetSZCKOMXhzhKmEvfg_d1YaFQLky7KNsak","lore_tm_v1_6XiiLlVq2W4eMx5lqmo_wSUuRP0LAPZU8zp2fGTz4QY","lore_tm_v1_2NxCg0QqFWerUlqt2Pk0IbxlqYeoRd2EcpO85RcFu5M","lore_tm_v1_Yb2ZKsuqGWF3pUBA7bPqe45vHB4jt1SoF0t6fNSfo8s","lore_tm_v1_dHJsql-QAUgg7M0ad5D622Oxs8baicw4AjJ8Ps44Eeo","lore_tm_v1_H-jjDI9qXrV2TtKDFVkbu79hURAVW4_QaRbraKwci-0","lore_tm_v1_TavEj-vLiYN8jo9uqJ3SO36k030dc42AR52dE8U-aco","lore_tm_v1_a5wN-j3uIp8tNS202MhzLbAg7ooFD9C3f1NXyRUjRkU","lore_tm_v1_pOUGBDHq0yDJKzLZpQkKQ_7IkVewwe4F7CJeikFfPf0","lore_tm_v1_x6LvFdF9DETq7KifqfHnXe5cYumajjSfol0vRvcWtIM","lore_tm_v1_6uIf-Jt0zDT-EIXuC69A9Vqab9p9599dRKfGSwLgzlQ","lore_tm_v1_EweyvuTe4cbva_XRI_j4ZjNVvviz6ZZcUE1Z8i2npRk","lore_tm_v1_krOl8w7AQ_TbwRq2eMtl2j2vDuxonmfqruOqryfziuo","lore_tm_v1_JYTLhisqGRZAziES0US0faBRGC4J-Mlwjt5S9v5vx6U","lore_tm_v1_OqAJ260trJ5c5AFZEnYBA6Q7gpS1mJLVvvicpTnwCW8","lore_tm_v1_9YJskpVZOb835uQXZIPGStetChM2uXJDaJ0k5CkIAc0","lore_tm_v1_1m7O_mgcvXmgo2sfwTUkCl9DFpyMF-08nVXRTtZxjTw","lore_tm_v1_aG5iVgZYQf6_4INSBr_7E4LANlr4d2UMNKfk3zcHS4Y","lore_tm_v1_Mf4keBPBtI2JWfeJa2Nmj1Z484kWIXG3WKIDscO_Rqc","lore_tm_v1_zCWzwqkffXXYBUhhRwrsae_4hllUBdvsnbcTyZoWClU","lore_tm_v1_cb76wHLavuVxrXpo5kvAeRSFQKAvT1hGznmb7RZYZfE","lore_tm_v1_NssT7uPeH5daYT-EqlRBMd9gcGftLfUuKy_fQ9gxN3o","lore_tm_v1_1cqwpt-q9z0MQU7303I3MI9HpNMxgL0JrNW2YeJh0PA","lore_tm_v1_FHRr6dyab1p4pJOaWb2IWmH8D2zUaeW-FqypcIDY4CQ","lore_tm_v1_6Sk18PH30l438Rg0Jqm_06nF1Ae8wsRi97qSKAjeIHk","lore_tm_v1_Jy5LHgE1-5ecfbbGm3BLOmHadBhJgjvK1UuBegwObf4","lore_tm_v1_MFGv0H0zXAp-MPAkSJqGaOWpu7U8-hFs4NHbX6yYKDs","lore_tm_v1_7uWq1WSH5Oq_rhOB1Vt0ChP-PP1tk-dgSFKjahN6ji8","lore_tm_v1_Lp2UKQk0YqS3l-Ac-ZZJDfVi8sLSGx6GRMXvvDYUDis","lore_tm_v1_5UcjS1pjYu0ARFEaoct5OSjZQFGnGiMaxCSIFOF2p9w","lore_tm_v1_3vec6y8ei2oAKTtV0DhRXBl0MEAVryklNFESnJqQyFg","lore_tm_v1_AQsvRlH5uSKtZEfDgHO63sFzlGHDWFvZbM3hleOMDww","lore_tm_v1_J1_BWREjaovnKlkS56F2Oro3HdkKT0_nLkmIKmrzabI","lore_tm_v1_znVaXDBki6XhEWSqOdJs0TrGWlOSW15ItLcmKu6zkg8","lore_tm_v1_GWsY7NYAEA0z6VOGRLr2D8-WJfGT9D1KG0rIq7kpDhA","lore_tm_v1_yFnwCpy9kq7f3Ty9WAoOHZCyC3rk7uzbnBYjGsCi67A","lore_tm_v1_kbY9C0eQl7arXZGB0mooQalBF4f4GebI9s1ZCfnobYs","lore_tm_v1_WIDjfwbPBaB6CwGeNoi5L5MKGJ9h3rqzd8cxsRQjf6s","lore_tm_v1_iwfIu7C9EDviEJy7fOyHKidPrWvIjILbnKliy_cn_Gc","lore_tm_v1_3WWHxwIJ92x0G1_cc-ZDSvKwezcJI7FIkwIH95rhm08","lore_tm_v1_sr59E44Q1oBbNWbCMlCsU32cvXvlE162qMhOhGMDjOA","lore_tm_v1_H7EsP2RlFlxue-I0Y98SzJKDvT5xdmrTsOllnKI9tD8","lore_tm_v1_NR1s-2Lm3YmLNmLKk8wIx2KfgV0S-JzbeiAYvJI763c","lore_tm_v1_wgZlgVIzMrPDdwSSLsjO1NUrmo-B3X6-HHJQyaHldEk","lore_tm_v1_6MQWPxezlVWTPmDw9aedwOO0gHi7jwWlttgxnzFXu0c","lore_tm_v1_WUtOD7GJWdHqEgQDUojUwg_fcouQve0DW7fAgHBMpzU","lore_tm_v1_OtHavxN3TwSMMgnostINQOKNN5kHJfqv6hpaOhAYv3A","lore_tm_v1_YLt9RBgrJShCQZzWDXHyh6YDynA1QmrSjY3MnjkH7LY","lore_tm_v1_5XHeV_qt_Y19JHP8cm95uduG8lqnQAToxu5nD1SKpqk","lore_tm_v1_b8GrxLKsFm5EDODtDaqtbFfzhg8cYGmL6uhbnoyE2Tc","lore_tm_v1_lRhqDYHwDbpxIm4nDz81vaxOcgI2tRTi1zmh8N1hBhg","lore_tm_v1_aEb1FoyU1X4uSDWZWVlWhmlvm_3xCXdmouoAffDsG18","lore_tm_v1_OaOTufOEOfgVknuKANk6sGaRtkeUkvE7XjU9H_p0u5M","lore_tm_v1_QO98f92RRLOUHRO9olLeTN5YWBFihvgSYfQGKt2ACeI","lore_tm_v1_9L_mZ3Qfu-FItjttROVkBUwuSagYAte-qBrQyqN_XI4","lore_tm_v1_3NvX12piqF8zn1r-cQ7nB10XJ5ReQS4F45lwuSpN8sM","lore_tm_v1_kopiUjnMLVv0g0_PKuTjwvcF8SquC3nlliHNRn4cc0g","lore_tm_v1_APfA22BJp86rkmV02VG0QREbeCNpmUFdTkaawh2x79s","lore_tm_v1_hJa4VWJuFtNGs0f5v-y6DQv8-grPEpP1lRi7umGttWY","lore_tm_v1_QmB_N9ft0F1Jg4Sutpy7dDYES35qOEEeA7yKZSJDUms","lore_tm_v1_bL30wXY3bqtaQSKG0jGsTXOtk71vNsCdzgp6SjMQwCg","lore_tm_v1_KnjE2tgFqlq3Z6jS5AY7Qz__Te_NX-NjRpfgzqLxcA4","lore_tm_v1_pNPskKcQ_lck7sOBxj1J48vhoBgPQjESg7Sh0XxRYS8","lore_tm_v1_80gDzUrOZSwm5NLkr4dwVx_3rqrGfOOjpH_MtIR2f50","lore_tm_v1_6Q6antWrERWR22sagmu4XiQska_tnR1CMJvlFiz9_3A","lore_tm_v1_lJyvQmzRsvClaJAUBvP_nIjwWdMPwXxv8tGAuQwM2C4","lore_tm_v1_EkLcc6_6p14k20YuVYpaZatI6TQ873GswB6SMNzUVFY","lore_tm_v1_6LTfVrU6TdhLt2UgoAS7ehOfonhkxBo-6D4fsg0dSuo","lore_tm_v1__qcQNeshkUd7UDP7aqDpLJHy2cNMqcES4GlV3YzSMuk","lore_tm_v1_dQDoTEIh_5tMuTP_7iBFiborZMTzKTcjMhS1_zufsZI","lore_tm_v1_STFSfSyw5k4kvs_xiCYIIS4b4Xdri2nWZAf8puVZOoA","lore_tm_v1_xp5EzPWZ0_GL9uEo4d-UCFkwcg54GELEqgHFhfs4eUc","lore_tm_v1_9qrva1g1KCA7EiiQClDoP-q9riGeTlZnoFwKS96QFuE"]
/home/byk/Code/opencode. No files may be edited, no formatters/tests/services may be run if they mutate state, Git must not be changed, production data must not be touched, and Lore recall was prohibited for this review.ab9408c81cc9916177641ae8e9f08624fc27b5b9dc661f30cb2055ad6248fdc59b14998d834497be/tmp/opencode/session-recovery-full.patchf051a53df476dd924bda0a14c4cd91a63c9e7eafff53bbe71f0460571335fcbdpackages/opencode/dist/server/opencode-server1ecc9afe36c12b31a8892cdbfb8a1560ceec97255c3537c073b795351233be40sha256sum: /tmp/opencode/session-recovery-full.patch: No such file or directory; search returned No files found), but it was restored and verified at 07:47 and again at 12:35. Both Git revisions resolve as commit objects, and HEAD remains dc661f30cb2055ad6248fdc59b14998d834497be. The review is therefore no longer blocked by missing evidence.PASS, CONCERN, or MUST-FIX.file:line evidence.MERGE or DO-NOT-MERGE.DO-NOT-MERGE.packages/core/src/database/migration/20260914235657_session-execution-lease.ts directly executes ALTER TABLE \session_execution` ADD `expires_at` integer NOT NULL;. SQLite rejects adding a required column without a default when an upgraded database already has session_executionrows. Required sequence is nullable/defaulted add, explicit backfill policy, then optional table rebuild to enforceNOT NULL`.packages/core/src/session/run-coordinator.ts:81-101 allows wake() to set pendingWake = true after interrupt() has set stopping = true and cleared it, potentially scheduling a successor during shutdown.SIGTERM smoke tests. New regressions reportedly failed on base dc661f30cb2055ad6248fdc59b14998d834497be with exactly 6 failures across focused ownership/recovery files and passed on the candidate. These are user-supplied results, not rerun during the frozen review.bun typecheck from the relevant package directory; never invoke tsc directly.do-not-run-tests-from-root; use directories such as packages/opencode.effect-smol source and nearby repository patterns first. If .opencode/references/effect-smol is absent, clone https://github.com/Effect-TS/effect-smol there, not into a skill directory.AGENTS.md, .lore.md, generated-file workflows, architecture/import direction, and package-specific commands.SessionPrompt / SessionPrompt.loop(...).llm.stream(request) per physical provider attempt.EventV2 replay ownership remains separate from Session execution ownership.SessionV2.prompt(...) first durably admits one session_input, then schedules advisory SessionExecution.wake(sessionID) unless resume: false."steer"; steers promote at the next safe provider boundary, while explicit "queue" remains pending until otherwise idle.SessionExecution remains process-global and Session-ID based.SessionRunCoordinator joins explicit same-Session resumes, coalesces prompt wakes, and allows different Sessions concurrently.SessionStore and LocationServiceMap.get(session.location).Location.workspaceID means implicit-local; explicit workspace identity is reserved for future placement."safe" claims are disposable without recovery."ready" and "unknown" recovery produce explicit continuation/information rather than replaying uncertain effects.Effect.gen(function* () { ... }) for multi-step workflows.Effect.fn("Name") or Effect.fnUntraced(...) for reusable service methods/important workflows.Schema, branded schemas, and Schema.TaggedErrorClass.any, non-null assertions, unchecked casts, or old Effect APIs merely to satisfy types.testEffect(...) from packages/opencode/test/lib/effect.ts for Effect services/layers/runtime/scopes; use it.live(...) for filesystem, Git, HTTP, sockets, processes, locks, and real time; use explicit layers and scoped fixture finalizers.SessionRecovery.node must be composed into both hosted/server and local opencode application graphs with SessionExecution.node substituted by SessionExecutionLocal.node.Layer.provideMerge(Observability.layer) must remain last in the opencode HTTP server graph so eager fibers inherit the configured logger rather than corrupting the TUI (#34730)..lore.md:225: update inventory and release activation-lock ownership before asynchronously closing scopes; never join disabled-plugin finalizers while holding activation/readiness locks; always release the readiness token even if cleanup/reporting fails.π΄ [canonical-patch-files] The immutable patch contains exactly 24 diff headers, in this order:
packages/core/schema.json β patch line 1packages/core/src/database/migration.gen.ts β 732packages/core/src/database/migration/20260914170650_session-recovery.ts β 746packages/core/src/database/migration/20260914214636_session-execution.ts β 777packages/core/src/database/migration/20260914222526_session-execution-phase.ts β 809packages/core/src/database/schema.gen.ts β 826packages/core/src/session/compaction.ts β 891packages/core/src/session/execution/local.ts β 964packages/core/src/session/message-updater.ts β 1113packages/core/src/session/projector.ts β 1177packages/core/src/session/recovery.ts β 1249packages/core/src/session/runner/index.ts β 1376packages/core/src/session/runner/llm.ts β 1388packages/core/src/session/runner/publish-llm-event.ts β 1657packages/core/src/session/sql.ts β 1882packages/core/test/session-execution-local.test.ts β 1940packages/core/test/session-projector.test.ts β 2107packages/core/test/session-runner-recorded.test.ts β 2405packages/core/test/session-runner-tool-events.test.ts β 2439packages/core/test/session-runner.test.ts β 2453packages/opencode/src/server/routes/instance/httpapi/server.ts β 2610packages/schema/src/session-event.ts β 2631packages/server/src/routes.ts β 2685packages/core/src/database/migration/20260914235657_session-execution-lease.ts β 2705Schema and migrations
packages/core/src/session/sql.ts:140-166 defines SessionInputTable with id, session_id, JSON prompt, delivery, admitted_seq, nullable promoted_seq, and time_created; indexes:
session_input_session_pending_delivery_seq_idxsession_input_session_admitted_seq_idxsession_input_session_promoted_seq_idxpackages/core/src/session/sql.ts:168-191 defines SessionRecoveryTable with session_id, execution_id, non-null assistant_message_id, continuation_message_id, and time_created; composite PK (session_id, assistant_message_id); unique indexes session_recovery_execution_idx and session_recovery_continuation_message_idx.packages/core/src/session/sql.ts:193-211 defines SessionExecutionTable with id, unique session_id, owner_id, nullable assistant_message_id, phase "ready" | "safe" | "unknown", time_created, and expires_at; indexes session_execution_session_idx and session_execution_owner_idx.packages/core/src/session/sql.ts:213 sets SESSION_EXECUTION_LEASE_MS = 30_000.20260914170650_session-recovery creates the original recovery table, cascade foreign keys, composite PK, and unique continuation index.20260914214636_session-execution creates execution ownership, adds non-null execution_id to recovery, and adds execution/session/owner indexes.20260914222526_session-execution-phase.ts:1-11 runs ALTER TABLE \session_execution` ADD `phase` text NOT NULL;`.20260914235657_session-execution-lease.ts runs ALTER TABLE \session_execution` ADD `expires_at` integer NOT NULL;`; this is the identified upgraded-database migration trap.migration.gen.ts with only 38 old imports and omitted September migrations. The immutable patch is authoritative; generated registry consistency must be judged from it, not transient working-tree snapshots.packages/core/src/database/migration.ts:11-106: serialized via Semaphore.makeUnsafe(1); empty DB installs generated schema and journals all migrations atomically; upgraded DB applies missing migrations transactionally one at a time; legacy Drizzle journals are mapped by name or timestamp, with unmatched timestamps defecting as Legacy migration timestamp ${entry.created_at} does not match any known migration.packages/core/test/database-migration.test.ts checks the migration generator with a 30,000 ms Linux timeout and expects "No schema changes, nothing to migrate"; fresh-DB tests inspect key tables, removed transitional columns, migration count, and expected indexes.Lease acquisition, takeover, renewal, and interruption
packages/core/src/session/execution/local.ts creates one process ownerID via crypto.randomUUID() and computes lease duration from SESSION_EXECUTION_LEASE_MS.executionID and attempts to insert phase "ready" with no assistant, creation time, and expiry.session_id replaces a claim only when:
ownerID and existing phase is "ready" or "safe", orexpires_at < Date.now().input.run, preventing a second live owner.renew(executionID) updates expiry only where id and owner_id match; no returned row dies with Session execution claim lost: ${executionID}.input.run(sessionID, force, executionID) against renewal repeated every 10 seconds using Effect.raceFirst; Effect v4 source at Effect.ts:4847-4901 confirms raceFirst returns first completion, success or failure, and interrupts the loser.Failed to drain Session.interrupt(sessionID) interrupts the coordinator and then deletes claims matching Session plus current process owner.Session not found: ${sessionID} if absent, resolves location, and invokes runner.run({ sessionID, force, executionID }).SessionExecutionLocal.node uses dependencies [Database.node, SessionStore.node, LocationServiceMap.node].expires_at >= now or a monotonically changing fencing epoch, contrary to cluster requirements.Run coordinator
packages/core/src/session/run-coordinator.ts:5-22 provides keyed active, run, wake, and interrupt; entries track done, optional owner, pendingWake, and stopping.:37-79 starts fibers through a FiberSet, joins existing explicit runs, retries after stopping entries, and starts a forced drain when idle.:51-65 coalesces one successful follow-up and may install a successor before completing the old done.:81-92 lets wake() set pendingWake = true on any existing entry without checking stopping.:94-101 has interrupt() set stopping = true, clear pendingWake, and interrupt the owner. A concurrent later wake can restore pendingWake, creating a shutdown race.Recovery
packages/core/src/session/recovery.ts scans only claims with expires_at < Date.now()."safe" claims and claims whose owned assistant has been superseded are deleted without recovery; deletion rechecks expiration.recoveryMessageID when present, otherwise generate a new message ID; continuation always gets a fresh ID.SessionEvent.Step.Recovered contains Session, timestamp, execution ID, recovery message ID, optional assistant ID, continuation ID, and phase.Recovery execution claim changed: ${claim.id}.SessionRecoveryTable already contains matching (session_id, execution_id); other defects are rethrown.execution.wake(claim.session_id) occurs only after a newly published recovery (packages/core/src/session/recovery.ts:102), not after duplicate detection.Failed to recover Sessions, forks scoped, and depends on [Database.node, EventV2.node, SessionProjector.node, SessionExecution.node].Projection and latest-assistant safety
packages/core/src/session/projector.ts:119-157 scopes writes by message and Session IDs and defines current assistant as only the latest assistant row by descending sequence, returned only if incomplete.:159-176 gets an explicitly owned assistant by both message ID and current Session and validates type "assistant".:370-382 projects durable PromptAdmitted into SessionInput.:391-431 requires a durable sequence for Step.Recovered, verifies a referenced assistant is still latest and is an assistant, admits queued Prompt.make({ text: "continue" }), applies normal event projection, and inserts recovery identity.Durable Session event is missing aggregate sequence, Recovery target is not the latest assistant: ${event.data.assistantMessageID}, and Recovery target is not an assistant: ${event.data.assistantMessageID}.packages/core/src/session/projector.ts:486-490 deletes only Session inputs admitted/promoted after the revert boundary.packages/core/src/session/message-updater.ts:95-99 updates only the explicitly owned assistant.message-updater.ts:155-239 creates new assistant messages on step start and scopes ended/failed/interrupted settlement to assistantMessageID.message-updater.ts:237-281 maps recovered "unknown" to Provider Step outcome unknown after server restart, otherwise Session execution interrupted by server restart.finish = "error", appends recovery:${executionID}, and converts pending/running tools to unknown errors. Final inspected text is Tool execution outcome unknown after server restart; an intermediate frozen-patch excerpt used Tool execution outcome unknown after interruption, so final patch/current-line evidence must be quoted precisely.findLastIndex; it never falls back to an older incomplete assistant.Events and replay
packages/core/src/event.ts:316-353 runs durable projectors and optional commit hook, updates aggregate sequence, and inserts event in one immediate transaction.:354-360 emits durable aggregate wake notifications only after commit.:369-395 rejects commit hooks on non-durable events with InvalidDurableEventError and exact message Local commit hooks require a durable event.:398-415 logs non-interruption listener failures as Event listener failed with event ID/type/cause.:441-475 replay supports publish, ownerID, and strictOwner; listeners are notified only when a new commit occurred and publish is true.packages/schema/src/session-event.ts:32-56 uses durable version 1 generally and version 2 for step settlement.:185-219 defines Step.Failed, Step.Interrupted, and Step.Recovered; recovery phase is "ready" | "unknown".:423-504 defines compaction started/delta/ended. Started/Ended are durable; Delta is live-only.Runner and tool behavior
packages/core/src/session/runner/index.ts now requires executionID in run({ sessionID, force, executionID }); it performs one local continuation from recorded history.runner/llm.ts threads execution ID through runTurnAttempt(...), validates claims, and defects with Session execution claim lost: ${executionID}."ready", "safe", and "unknown"; inspected changes set "safe" after committed stream boundaries and "unknown" when outcome is uncertain.runner/llm.ts:121-141 has failInterruptedTools, which scans pending/running tools and emits unknown Tool.Failed events while preserving provider executed and metadata. An inspected current snapshot still used Tool execution interrupted, so candidate-vs-current wording needs exact patch verification.runner/llm.ts:143-144 defines awaitToolFibers = Effect.raceFirst(FiberSet.join(fibers), FiberSet.awaitEmpty(fibers)).PermissionV2.DeclinedError, QuestionV2.RejectedError) stop the loop rather than becoming tool output.publish-llm-event.ts tracks assistant/tool ownership, timestamps, text/reasoning deltas, durable tool definitions, settlement, and assistant failure state. monolith. Implement the unchecked items in small reviewed slices: at runner/llm.ts:49; this is textual/commentary evidence, not itself a legacy call. The invariant is no actual SessionPrompt invocation.Compaction
packages/core/src/session/compaction.ts:155-179 token-splits conversation and creates fresh/update summary prompts.:184-242 validates context/output bounds, publishes Compaction.Started, runs a tool-free summary stream with bounded output, invokes optional beforeStream/afterStream, rejects provider failure/blank summary, and publishes durable Compaction.Ended with summary and recent tail through the supplied commit hook.:244-259 auto-compacts only when configured and estimated system/messages/tools exceed context - max(output, buffer).runAfterOverflowCompaction(...).Session input
packages/core/src/session/input.ts:85-116 admits one row, rejects existing projected messages or failed insertions with LifecycleConflict.:118-168 makes prompted projection idempotent only when stored projection and promoted sequence match exactly; otherwise it defects.packages/core/src/session.ts:360-385 runs prompt admission uninterruptibly, maps lifecycle conflict to PromptConflictError, checks retry equivalence, and wakes unless resume === false.session.ts:346-358 exposes durable filtered streaming and aggregate history.session.ts:387-391 returns OperationUnavailableError for "shell" and "skill".Startup composition
packages/server/src/routes.ts:27-39 includes SessionRecovery.node in application services.packages/server/src/routes.ts:53-55 substitutes SessionExecution.node with SessionExecutionLocal.node.packages/opencode/src/server/routes/instance/httpapi/server.ts:299-304 groups SessionV2.node and SessionRecovery.node and supplies both LocationServiceMap.node and SessionExecution.node substitutions.:307-312 keeps Observability.layer last to avoid TUI logger corruption (#34730).Tests
packages/core/test/session-execution-local.test.ts:42-160 contains six enumerated behaviors despite one observation calling them β5 testsβ:
:81-102 live-lease exclusion:104-133 takeover/stale-owner fencing:135-160 uncertain-live non-reentrypackages/core/test/session-projector.test.ts includes:
never recovers a live execution lease using expires_at: Date.now() + 60_000never recovers an execution superseded by a newer assistant using sequences 0 and 1Working-tree evidence
20260914235657_session-execution-lease.ts, perf.data, perf.data.old).git show at 07:49 produced: fatal: path 'packages/core/src/database/migration/20260914235657_session-execution-lease.ts' exists on disk, but not in 'dc661f30cb2055ad6248fdc59b14998d834497be' and lease-exists=128, proving the lease migration belongs to the frozen delta rather than HEAD.33e64fbe08c166aefbfc3c5f1afd9e432aaa60c06e95d8e273163fc2c38b5142 -f0a743c5c616ed7d48e491828e72226bfa4a2cb3bd0104fb785154bcbc4c5870 -, followed by UUID output 57591e35-6f8f-4cda-932c-6a08e85caae7 [ "9401e0ed-b1e3-4557-bc94-1c9b29e1e09c" ].Fiber.interrupt and Effect.raceFirst behavior verified from effect-smol.ADD expires_at integer NOT NULL.AGENTS.md captured: prompt admission separation, location scoping, no legacy loop, inbox delivery behavior, EventV2 ownership separation, package-local commands.NOT NULL migration trap documented.SessionRunner.Interface.run confirmed to carry executionID.PASS/CONCERN/MUST-FIX report or merge verdict had yet been issued.