DashboardopencodeSession 0E5EeJfngrA9

Session 0E5EeJfngrA9

Full ID: 0E5EeJfngrA9O8uoR
Messages: 85
Distillations: 16
Time range: 2026-09-17 09:05:07 — 2026-09-17 09:20:38

Conversation (85 messages)

Strict READ-ONLY security/pentest review of frozen v21 in /tmp/opencode/session-recovery-v21-review. Do not edit, run tests/builds/services, mutate VCS/index/refs, or use recall. Verify immutable inputs first: base ab9408c81cc9916177641ae8e9f08624fc27b5b9; patch /tmp/opencode/session-recovery-final-v21.patch SHA-256 2ae4eea72024cafe8b69c0461063ee25cbf54608856cd258866b7f3b86620b36; SEA /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server SHA-256 aa98d64abb3bf6ac0ef88a940f9c41c6eb14ffeab3c3a7846921ba01ef46643d; 34 paths. Inspect all changed files and relevant context. Adversarially test by inspection: terminal failed Step crash windows and multi-tool idempotence; concurrent interrupt single-flight and wake preservation; post-finalizer cancellation ordering; stale-owner fencing and exact lease predicates; corrupt identity/cross-Session rows; replay/duplicate wake/starvation; provider/tool/snapshot side effects; schema lineage; generated clients; auth and layering. Explicitly verify a completed Step.Failed can never become synthetic continue, but unresolved tools remain model-visible; completed continue-phase Steps still redrive. Verify snapshot prevIds directly names base snapshot f14a9b18-8207-487e-a3d3-227e629ba9ad. Treat final check-call, process-local routing, bounded clock skew as disclosed residuals. Findings first with MUST-FIX/CONCERN exact file:line evidence; end exactly MERGE or DO-NOT-MERGE.

gateway · 2026-09-17 09:05:07
result
Skill "repo-setup" not found. Available skills: ast-grep, customize-opencode, effect, jj-create-pr, jj-guide, jj-update-pr, jj-workflow, rtl-aware-development
gateway · 2026-09-17 09:05:25
result
2ae4eea72024cafe8b69c0461063ee25cbf54608856cd258866b7f3b86620b36  /tmp/opencode/session-recovery-final-v21.patch
aa98d64abb3bf6ac0ef88a940f9c41c6eb14ffeab3c3a7846921ba01ef46643d  /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server
gateway · 2026-09-17 09:05:31
result
ab9408c81cc9916177641ae8e9f08624fc27b5b9
 M packages/client/src/generated/types.ts
 M packages/core/schema.json
 M packages/core/src/database/migration.gen.ts
 M packages/core/src/database/schema.gen.ts
 M packages/core/src/session.ts
 M packages/core/src/session/compaction.ts
 M packages/core/src/session/context-epoch.ts
 M packages/core/src/session/execution/local.ts
 M packages/core/src/session/input.ts
 M packages/core/src/session/message-updater.ts
 M packages/core/src/session/projector.ts
 M packages/core/src/session/run-coordinator.ts
 M packages/core/src/session/runner/index.ts
 M packages/core/src/session/runner/llm.ts
 M packages/core/src/session/runner/publish-llm-event.ts
 M packages/core/src/session/sql.ts
 M packages/core/test/database-migration.test.ts
 M packages/core/test/session-projector.test.ts
 M packages/core/test/session-prompt.test.ts
 M packages/core/test/session-run-coordinator.test.ts
 M packages/core/test/session-runner-recorded.test.ts
 M ...
gateway · 2026-09-17 09:05:39
result
<path>/tmp/opencode/session-recovery-final-v21.patch</path>
<type>file</type>
<content>
1: diff --git a/packages/client/src/generated/types.ts b/packages/client/src/generated/types.ts
2: index 3b3188c874..5130fa9496 100644
3: --- a/packages/client/src/generated/types.ts
4: +++ b/packages/client/src/generated/types.ts
5: @@ -775,8 +775,17 @@ export type SessionsHistoryOutput = {
6:              }>
7:            }
8:            readonly delivery: "steer" | "queue"
9: +          readonly requestExecution?: boolean
10:          }
11:        }
12: +    | {
13: +        readonly id: string
14: +        readonly metadata?: { readonly [x: string]: JsonValue }
15: +        readonly type: "session.next.prompt.execution_requested"
16: +        readonly durable?: { readonly aggregateID: string; readonly seq: number; readonly version: number }
17: +        readonly location?: { readonly directory: string; readonly workspaceID?: string }
18: +        readonly data: { readonly timestamp: number; ...
gateway · 2026-09-17 09:05:52
result
patch_paths=34 unique_patch_paths=34 worktree_paths=34 unique_worktree_paths=34
path_sets_equal=True
duplicate_patch_paths=[]
commit
gateway · 2026-09-17 09:05:57
result
/tmp/opencode/session-recovery-v21-review/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/app/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/opencode/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/opencode/src/session/llm/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/app/e2e/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/ui/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/app/e2e/performance/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/opencode/src/server/routes/instance/httpapi/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/desktop/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/opencode/test/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/session-ui/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/opencode/test/server/AGENTS.md
/tmp/opencode/session-recovery-v21-review/packages/codemode/AGENTS.md
/tmp/opencode/session-recovery-v21-revie...
gateway · 2026-09-17 09:06:00
result
/tmp/opencode/session-recovery-v21-review/CONTRIBUTING.md
gateway · 2026-09-17 09:06:06
result
<path>/tmp/opencode/session-recovery-v21-review/AGENTS.md</path>
<type>file</type>
<content>
1: - To regenerate the legacy JavaScript SDK, run `./packages/sdk/js/script/build.ts`.
2: - After changing the public Protocol or Server `HttpApi`, run `bun run generate` from `packages/client`. Do not edit `src/generated` or `src/generated-effect` directly.
3: - Keep runtime dependencies directed from Schema to Core and Protocol, then from Core and Protocol to Server. Client runtime code may depend on Schema and Protocol but never Core or Server; `sdk-next` composes Client, Core, and Server.
4: - The default branch in this repo is `dev`.
5: - Local `main` ref may not exist; use `dev` or `origin/dev` for diffs.
6: 
7: ## Branch Names
8: 
9: Use a short branch name of at most three words, separated by hyphens. Do not use slashes or type prefixes such as `feat/` or `fix/`.
10: 
11: Examples: `session-recovery`, `fix-scroll-state`, `regenerate-sdk`. ...
gateway · 2026-09-17 09:06:09
result
<path>/tmp/opencode/session-recovery-v21-review/packages/opencode/AGENTS.md</path>
<type>file</type>
<content>
1: # opencode database guide
2: 
3: ## Database
4: 
5: - **Schema**: Drizzle schema lives in `packages/core/src/**/*.sql.ts`.
6: - **Migrations**: database migrations live in `packages/core` and are applied by core.
7: 
8: ## Development server
9: 
10: - Running `bun dev` from `packages/opencode` starts the live interactive TUI. Do not run it as a blocking foreground command when you need to inspect the result.
11: - Start it in `tmux` instead: `tmux new-session -d -s opencode-dev 'bun dev'`.
12: - Capture the current TUI output with: `tmux capture-pane -pt opencode-dev`.
13: - Stop the session explicitly when done: `tmux kill-session -t opencode-dev`.
14: 
15: # Module shape
16: 
17: Do not use `export namespace Foo { ... }` for module organization. It is not
18: standard ESM, it prevents tree-shaking, and it breaks Node's native TypeScript
19: runner. ...
gateway · 2026-09-17 09:06:20
result
<path>/tmp/opencode/session-recovery-v21-review/packages/opencode/src/server/routes/instance/httpapi/AGENTS.md</path>
<type>file</type>
<content>
1: # HttpApi Route Patterns
2: 
3: Use `HttpApiBuilder.group(...)` for normal HTTP endpoints, including streaming HTTP responses such as server-sent events. Handlers should yield stable services once while building the handler layer, then close over those services in endpoint implementations.
4: 
5: ```ts
6: export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", (handlers) =>
7:   Effect.gen(function* () {
8:     const session = yield* Session.Service
9: 
10:     return handlers.handle("list", () => session.list())
11:   }),
12: )
13: ```
14: 
15: For SSE endpoints, stay in `HttpApiBuilder.group(...)` and return `HttpServerResponse.stream(...)` from the handler. Annotate the endpoint success schema with `HttpApiSchema.asText({ contentType: "text/event-stream" })` so OpenAPI documents the stream content type. ...
gateway · 2026-09-17 09:06:24
result
<path>/tmp/opencode/session-recovery-v21-review/packages/schema/AGENTS.md</path>
<type>file</type>
<content>
1: # Schema Package Guide
2: 
3: `@opencode-ai/schema` owns browser-safe wire and storage contracts shared by protocol, server, core, and generated SDKs. Keep runtime behavior, service layers, side effects, and host-local implementation details in the domain package that owns them.
4: 
5: ## Package Boundary
6: 
7: - Preserve the dependency direction: `@opencode-ai/schema <- @opencode-ai/protocol <- @opencode-ai/server`.
8: - Schema values should be serializable contract definitions, not service implementations or runtime registries.
9: - A domain may keep a minimal public wire contract here when SDK generation needs it, but do not move the broader runtime model into Schema just because an event is public. `plugin.added` is the current example: Schema may own the minimum browser-safe event payload, while plugin runtime behavior stays outside Schema. ...
gateway · 2026-09-17 09:06:28
result
<path>/tmp/opencode/session-recovery-v21-review/CONTRIBUTING.md</path>
<type>file</type>
<content>
1: # Contributing to OpenCode
2: 
3: We want to make it easy for you to contribute to OpenCode. Here are the most common type of changes that get merged:
4: 
5: - Bug fixes
6: - Additional LSPs / Formatters
7: - Improvements to LLM performance
8: - Support for new providers
9: - Fixes for environment-specific quirks
10: - Missing standard behavior
11: - Documentation improvements
12: 
13: However, any UI or core product feature must go through a design review with the core team before implementation.
14: 
15: If you are unsure if a PR would be accepted, feel free to ask a maintainer or look for issues with any of the following labels:
16: 
17: - [`help wanted`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3Ahelp-wanted)
18: - [`good first ...
gateway · 2026-09-17 09:06:40
result
 packages/client/src/generated/types.ts             |   72 +
 packages/core/schema.json                          |  613 +++-
 packages/core/src/database/migration.gen.ts        |    1 +
 packages/core/src/database/schema.gen.ts           |   53 +-
 packages/core/src/session.ts                       |   10 +-
 packages/core/src/session/compaction.ts            |   47 +-
 packages/core/src/session/context-epoch.ts         |   88 +-
 packages/core/src/session/execution/local.ts       |  232 +-
 packages/core/src/session/input.ts                 |  422 ++-
 packages/core/src/session/message-updater.ts       |   69 +
 packages/core/src/session/projector.ts             |   89 +-
 packages/core/src/session/run-coordinator.ts       |   40 +-
 packages/core/src/session/runner/index.ts          |    4 +
 packages/core/src/session/runner/llm.ts            |  393 ++-
 .../core/src/session/runner/publish-llm-event.ts   |  156 +-
 packages/core/src/session/sql.ts                   |   89 +-
 ...
gateway · 2026-09-17 09:06:51
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/execution/claim.ts</path>
<type>file</type>
<content>
1: export * as SessionExecutionClaim from "./claim"
2: 
3: import { and, eq, gt, notInArray } from "drizzle-orm"
4: import { Clock, Effect } from "effect"
5: import type { Database } from "../../database/database"
6: import type { SessionSchema } from "../schema"
7: import { SESSION_EXECUTION_LEASE_MS, SessionExecutionTable } from "../sql"
8: 
9: type DatabaseService = Database.Interface["db"]
10: 
11: export type Claim = {
12:   readonly sessionID: SessionSchema.ID
13:   readonly executionID: string
14:   readonly ownerID: string
15: }
16: 
17: export type Values = Partial<
18:   Pick<typeof SessionExecutionTable.$inferInsert, "assistant_message_id" | "assistant_seq" | "phase">
19: >
20: 
21: export class Lost extends Error {
22:   constructor(readonly claim: Claim) {
23:     super(`Session execution claim lost: ${claim.executionID}`)
24:   }
25: }
26: 
27: ...
gateway · 2026-09-17 09:06:56
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/recovery-id.ts</path>
<type>file</type>
<content>
1: import { SessionMessage } from "./message"
2: 
3: export const message = (executionID: string, assistantMessageID?: SessionMessage.ID) =>
4:   assistantMessageID ?? SessionMessage.ID.make(`msg_recovery_${executionID}`)
5: 
6: export const continuation = (executionID: string) => SessionMessage.ID.make(`msg_recovery_continue_${executionID}`)

(End of file - total 6 lines)
</content>
gateway · 2026-09-17 09:07:01
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/database/migration/20260914170650_session-recovery.ts</path>
<type>file</type>
<content>
1: import { Effect } from "effect"
2: import type { DatabaseMigration } from "../migration"
3: 
4: export default {
5:   id: "20260914170650_session-recovery",
6:   up(tx) {
7:     return Effect.gen(function* () {
8:       yield* tx.run(`ALTER TABLE \`session_input\` ADD \`wake_pending\` integer DEFAULT false NOT NULL;`)
9:       yield* tx.run(
10:         `ALTER TABLE \`session\` ADD \`wake_attempts\` integer DEFAULT 0 NOT NULL CONSTRAINT \`session_wake_attempts_check\` CHECK(\`wake_attempts\` >= 0 AND \`wake_attempts\` <= 9007199254740991);`,
11:       )
12:       yield* tx.run(`
13:         CREATE TABLE \`session_execution\` (
14:           \`id\` text NOT NULL,
15:           \`session_id\` text NOT NULL,
16:           \`owner_id\` text NOT NULL,
17:           \`assistant_message_id\` text,
18:            \`phase\` text NOT ...
gateway · 2026-09-17 09:07:07
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/sql.ts</path>
<type>file</type>
<content>
1: import { sql } from "drizzle-orm"
2: import { check, sqliteTable, text, integer, index, primaryKey, real, uniqueIndex } from "drizzle-orm/sqlite-core"
3: import * as DatabasePath from "../database/path"
4: import { ProjectTable } from "../project/sql"
5: import type { SessionMessage } from "./message"
6: import type { Prompt } from "./prompt"
7: import type { SessionInput } from "./input"
8: import type { Snapshot } from "../snapshot"
9: import { PermissionV1 } from "../v1/permission"
10: import { ProjectV2 } from "../project"
11: import type { SessionSchema } from "./schema"
12: import type { MessageID, PartID, SessionV1 } from "../v1/session"
13: import { WorkspaceV2 } from "../workspace"
14: import { Timestamps } from "../database/schema.sql"
15: import type { SystemContext } from "../system-context/index"
16: import { AgentV2 } from "../agent"
17: import type { ...
gateway · 2026-09-17 09:07:11
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/recovery.ts</path>
<type>file</type>
<content>
1: export * as SessionRecovery from "./recovery"
2: 
3: import { and, asc, desc, eq, exists, gt, isNull, lte, or, sql } from "drizzle-orm"
4: import { Clock, DateTime, Effect, Layer, Option, Schedule, Schema } from "effect"
5: import { Database } from "../database/database"
6: import { makeGlobalNode } from "../effect/app-node"
7: import { EventV2 } from "../event"
8: import { SessionEvent } from "./event"
9: import { SessionExecution } from "./execution"
10: import { SessionProjector } from "./projector"
11: import { SessionExecutionClaim } from "./execution/claim"
12: import { SessionInput } from "./input"
13: import { SessionMessage } from "./message"
14: import { continuation } from "./recovery-id"
15: import { SessionSchema } from "./schema"
16: import {
17:   MAX_WAKE_ATTEMPTS,
18:   SESSION_EXECUTION_LEASE_MS,
19:   SessionExecutionTable,
20:   ...
gateway · 2026-09-17 09:07:14
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/recovery.ts</path>
<type>file</type>
<content>
351:   const freshRecovery = yield* db
352:       .select({
353:         sessionID: SessionRecoveryTable.session_id,
354:         executionID: SessionRecoveryTable.execution_id,
355:         continuationMessageID: SessionRecoveryTable.continuation_message_id,
356:         wakeAttempts: SessionRecoveryTable.wake_attempts,
357:       })
358:       .from(SessionRecoveryTable)
359:       .where(
360:         and(
361:           eq(SessionRecoveryTable.wake_pending, true),
362:           isNull(SessionRecoveryTable.recovery_error),
363:           eq(SessionRecoveryTable.wake_attempts, 0),
364:         ),
365:       )
366:       .orderBy(asc(SessionRecoveryTable.time_created), asc(SessionRecoveryTable.execution_id))
367:       .limit(BATCH_SIZE - retriedRecovery.length)
368:       .all()
369:       .pipe(Effect.orDie)
370:   const retryRecoveryCapacity = BATCH_SIZE - ...
gateway · 2026-09-17 09:07:21
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/input.ts</path>
<type>file</type>
<content>
1: export * as SessionInput from "./input"
2: 
3: import { and, asc, desc, eq, isNull, lte } from "drizzle-orm"
4: import { DateTime, Effect, Option, Schema } from "effect"
5: import { Admitted, Delivery } from "@opencode-ai/schema/session-input"
6: import type { Database } from "../database/database"
7: import { EventV2 } from "../event"
8: import { SessionEvent } from "./event"
9: import { SessionMessage } from "./message"
10: import { Prompt } from "./prompt"
11: import { continuation, message } from "./recovery-id"
12: import { SessionSchema } from "./schema"
13: import { SessionInputTable, SessionMessageTable, SessionRecoveryTable, SessionTable } from "./sql"
14: 
15: type DatabaseService = Database.Interface["db"]
16: 
17: export { Admitted, Delivery }
18: 
19: const decodePrompt = Schema.decodeUnknownSync(Prompt)
20: const encodePrompt = ...
gateway · 2026-09-17 09:07:28
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/input.ts</path>
<type>file</type>
<content>
501:   rows: ReadonlyArray<typeof SessionInputTable.$inferSelect>,
502:   commit?: (row: typeof SessionInputTable.$inferSelect) => Effect.Effect<void>,
503: ) {
504:   for (const row of rows) {
505:     const id = SessionMessage.ID.make(row.id)
506:     yield* events
507:       .publish(
508:         SessionEvent.Prompted,
509:         {
510:           sessionID,
511:           timestamp: DateTime.makeUnsafe(row.time_created),
512:           messageID: id,
513:           prompt: decodePrompt(row.prompt),
514:           delivery: row.delivery,
515:         },
516:         commit ? { commit: () => commit(row) } : undefined,
517:       )
518:       .pipe(
519:         Effect.catchDefect((defect) =>
520:           defect instanceof LifecycleConflict
521:             ? find(db, id).pipe(
522:                 Effect.flatMap((stored) => (stored?.promotedSeq === undefined ? ...
gateway · 2026-09-17 09:07:34
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/projector.ts</path>
<type>file</type>
<content>
1: export * as SessionProjector from "./projector"
2: 
3: import { and, desc, eq, gt, or, sql } from "drizzle-orm"
4: import { DateTime, Effect, Layer, Schema } from "effect"
5: import { Database } from "../database/database"
6: import { EventV2 } from "../event"
7: import { makeGlobalNode } from "../effect/app-node"
8: import { SessionEvent } from "./event"
9: import { SessionV1 } from "../v1/session"
10: import { WorkspaceTable } from "../control-plane/workspace.sql"
11: import { SessionMessage } from "./message"
12: import { SessionMessageUpdater } from "./message-updater"
13: import { SessionInput } from "./input"
14: import { Prompt } from "./prompt"
15: import { continuation } from "./recovery-id"
16: import { WorkspaceV2 } from "../workspace"
17: import {
18:   MessageTable,
19:   PartTable,
20:   SessionInputTable,
21:   SessionMessageTable,
22:   ...
gateway · 2026-09-17 09:07:40
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/projector.ts</path>
<type>file</type>
<content>
351:           .where(eq(SessionTable.id, event.data.sessionID))
352:           .run()
353:           .pipe(Effect.orDie)
354:         yield* run(db, event)
355:       }),
356:     )
357:     yield* events.project(SessionEvent.Prompted, (event) =>
358:       Effect.gen(function* () {
359:         if (event.durable === undefined) return yield* Effect.die("Durable Session event is missing aggregate sequence")
360:         yield* SessionInput.projectPrompted(db, {
361:           id: event.data.messageID,
362:           sessionID: event.data.sessionID,
363:           prompt: event.data.prompt,
364:           delivery: event.data.delivery,
365:           timeCreated: event.data.timestamp,
366:           promotedSeq: event.durable.seq,
367:         })
368:         yield* run(db, event)
369:       }),
370:     )
371:     yield* events.project(SessionEvent.PromptAdmitted, ...
gateway · 2026-09-17 09:07:51
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/message-updater.ts</path>
<type>file</type>
<content>
1: import { castDraft, produce, type WritableDraft } from "immer"
2: import { Effect } from "effect"
3: import { SessionEvent } from "./event"
4: import { SessionMessage } from "./message"
5: import { message } from "./recovery-id"
6: 
7: export type MemoryState = {
8:   messages: SessionMessage.Message[]
9: }
10: 
11: export interface Adapter {
12:   readonly getCurrentAssistant: () => Effect.Effect<SessionMessage.Assistant | undefined>
13:   readonly getAssistant: (messageID: SessionMessage.ID) => Effect.Effect<SessionMessage.Assistant | undefined>
14:   readonly getCurrentShell: (callID: string) => Effect.Effect<SessionMessage.Shell | undefined>
15:   readonly updateAssistant: (assistant: SessionMessage.Assistant) => Effect.Effect<void>
16:   readonly updateShell: (shell: SessionMessage.Shell) => Effect.Effect<void>
17:   readonly appendMessage: (message: ...
gateway · 2026-09-17 09:08:03
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/execution/local.ts</path>
<type>file</type>
<content>
1: import { and, asc, desc, eq, isNull } from "drizzle-orm"
2: import { Cause, Clock, DateTime, Deferred, Duration, Effect, Exit, Layer, Option, Schedule } from "effect"
3: import { Database } from "../../database/database"
4: import { LocationServiceMap } from "../../location-service-map"
5: import { makeGlobalNode } from "../../effect/app-node"
6: import { SessionRunCoordinator } from "../run-coordinator"
7: import { SessionRunner } from "../runner"
8: import { SessionMessage } from "../message"
9: import { SessionSchema } from "../schema"
10: import { SessionStore } from "../store"
11: import { SessionExecution } from "../execution"
12: import { EventV2 } from "../../event"
13: import { SessionEvent } from "../event"
14: import { SessionExecutionClaim } from "./claim"
15: import {
16:   SESSION_EXECUTION_LEASE_MS,
17:   SessionExecutionTable,
18:   ...
gateway · 2026-09-17 09:08:09
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/run-coordinator.ts</path>
<type>file</type>
<content>
1: export * as SessionRunCoordinator from "./run-coordinator"
2: 
3: import { Deferred, Effect, Exit, Fiber, FiberSet, Scope } from "effect"
4: 
5: /** Serializes execution for each key while allowing different keys to run concurrently. */
6: export interface Coordinator<Key, E> {
7:   /** Snapshots keys with an execution owned by this coordinator. */
8:   readonly active: Effect.Effect<ReadonlySet<Key>>
9:   /** Starts execution while idle or joins the active execution. */
10:   readonly run: (key: Key) => Effect.Effect<void, E>
11:   /** Registers one coalesced follow-up after newly recorded work. */
12:   readonly wake: (key: Key) => Effect.Effect<void>
13:   /** Stops active execution, runs cleanup, then starts work that arrived while stopping. */
14:   readonly interrupt: (key: Key, cleanup?: Effect.Effect<void>) => Effect.Effect<void>
15: }
16: 
17: ...
gateway · 2026-09-17 09:08:20
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/runner/index.ts</path>
<type>file</type>
<content>
1: export * as SessionRunner from "./index"
2: 
3: import type { LLMError } from "@opencode-ai/llm"
4: import { Context, Effect } from "effect"
5: import { SessionSchema } from "../schema"
6: import type { SessionMessage } from "../message"
7: import type { ContextSnapshotDecodeError, MessageDecodeError } from "../error"
8: import { SessionRunnerModel } from "./model"
9: import type { SystemContext } from "../../system-context/index"
10: import type { ToolOutputStore } from "../../tool-output-store"
11: 
12: export type RunError =
13:   | LLMError
14:   | SessionRunnerModel.Error
15:   | MessageDecodeError
16:   | ContextSnapshotDecodeError
17:   | SystemContext.InitializationBlocked
18:   | ToolOutputStore.Error
19: 
20: /** Runs one local continuation from already-recorded Session history. ...
gateway · 2026-09-17 09:08:27
result
Found 5 matches
/tmp/opencode/session-recovery-v21-review/packages/core/src/session/runner/llm.ts:
  Line 33: import { SessionExecutionClaim } from "../execution/claim"

  Line 129:       claim: SessionExecutionClaim.Claim,

  Line 148:             { commit: () => SessionExecutionClaim.update(db, claim) },

  Line 201:       const updateExecution = (values: SessionExecutionClaim.Values = {}) =>

  Line 202:         SessionExecutionClaim.update(db, claim, values)
gateway · 2026-09-17 09:08:33
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/runner/llm.ts</path>
<type>file</type>
<content>
1: import {
2:   LLM,
3:   LLMClient,
4:   LLMError,
5:   LLMEvent,
6:   Message,
7:   SystemPart,
8:   isContextOverflowFailure,
9:   type ProviderErrorEvent,
10: } from "@opencode-ai/llm"
11: import { Cause, DateTime, Effect, Exit, Fiber, Layer, Option, Semaphore, Stream } from "effect"
12: import { and, eq } from "drizzle-orm"
13: import { AgentV2 } from "../../agent"
14: import { Config } from "../../config"
15: import { Database } from "../../database/database"
16: import { EventV2 } from "../../event"
17: import { Location } from "../../location"
18: import { ModelV2 } from "../../model"
19: import { PermissionV2 } from "../../permission"
20: import { ProviderV2 } from "../../provider"
21: import { QuestionV2 } from "../../question"
22: import { SystemContext } from "../../system-context/index"
23: import { SystemContextRegistry } from ...
gateway · 2026-09-17 09:08:38
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/runner/llm.ts</path>
<type>file</type>
<content>
551:                 ownerID,
552:               )
553:             return yield* runTurn(sessionID, executionID, undefined, defect.transition.step, ownerID)
554:           }),
555:         ),
556:       )
557:     })
558: 
559:     const run = Effect.fn("SessionRunner.run")(function* (input: {
560:       readonly sessionID: SessionSchema.ID
561:       readonly force: boolean
562:       readonly executionID: string
563:       readonly ownerID: string
564:       readonly recoveryInputID?: SessionMessage.ID
565:     }) {
566:       const claim = {
567:         sessionID: input.sessionID,
568:         executionID: input.executionID,
569:         ownerID: input.ownerID,
570:       }
571:       const recovering = input.recoveryInputID !== undefined
572:       const hasSteer = recovering ? false : yield* SessionInput.hasPending(db, input.sessionID, "steer")
573:       ...
gateway · 2026-09-17 09:08:50
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/runner/publish-llm-event.ts</path>
<type>file</type>
<content>
1: import { ToolOutput, type LLMEvent, type ProviderMetadata, type ToolResultValue, type Usage } from "@opencode-ai/llm"
2: import { DateTime, Effect } from "effect"
3: import { EventV2 } from "../../event"
4: import { ModelV2 } from "../../model"
5: import { SessionEvent } from "../event"
6: import { SessionMessage } from "../message"
7: import { SessionSchema } from "../schema"
8: 
9: type Input = {
10:   readonly sessionID: SessionSchema.ID
11:   readonly agent: string
12:   readonly model: ModelV2.Ref
13:   readonly snapshot?: string
14:   readonly startCommit: (assistantMessageID: SessionMessage.ID, seq: number) => Effect.Effect<void>
15:   readonly eventCommit: () => Effect.Effect<void>
16: }
17: 
18: const safe = (value: number | undefined) => Math.max(0, Number.isFinite(value) ? (value ?? ...
gateway · 2026-09-17 09:09:00
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/compaction.ts</path>
<type>file</type>
<content>
1: export * as SessionCompaction from "./compaction"
2: 
3: import { LLM, LLMError, LLMEvent, Message, type LLMRequest, type Model } from "@opencode-ai/llm"
4: import { DateTime, Effect, Stream } from "effect"
5: import type { Config } from "../config"
6: import type { EventV2 } from "../event"
7: import { SessionEvent } from "./event"
8: import { SessionMessage } from "./message"
9: import { SessionSchema } from "./schema"
10: import { Token } from "../util/token"
11: 
12: const DEFAULT_BUFFER = 20_000
13: const DEFAULT_KEEP_TOKENS = 8_000
14: const TOOL_OUTPUT_MAX_CHARS = 2_000
15: const SUMMARY_OUTPUT_TOKENS = 4_096
16: const SUMMARY_TEMPLATE = `Output exactly the Markdown structure shown inside <template> and keep the section order unchanged. Do not include the <template> tags in your response. ...
gateway · 2026-09-17 09:09:09
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session/context-epoch.ts</path>
<type>file</type>
<content>
1: export * as SessionContextEpoch from "./context-epoch"
2: 
3: import { eq } from "drizzle-orm"
4: import { DateTime, Effect, Schema } from "effect"
5: import type { Database } from "../database/database"
6: import { EventV2 } from "../event"
7: import { SystemContext } from "../system-context/index"
8: import { ContextSnapshotDecodeError } from "./error"
9: import { SessionEvent } from "./event"
10: import { SessionHistory } from "./history"
11: import { SessionInput } from "./input"
12: import { SessionMessage } from "./message"
13: import { SessionSchema } from "./schema"
14: import { SessionContextEpochTable } from "./sql"
15: import { SessionExecutionClaim } from "./execution/claim"
16: 
17: type DatabaseService = Database.Interface["db"]
18: 
19: interface Prepared {
20:   readonly baseline: string
21:   readonly baselineSeq: number
22: }
23: 
24: ...
gateway · 2026-09-17 09:09:16
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session.ts</path>
<type>file</type>
<content>
1: export * as SessionV2 from "./session"
2: export * from "./session/schema"
3: 
4: import { DateTime, Effect, Layer, Schema, Context, Stream } from "effect"
5: import { ListAnchor } from "@opencode-ai/schema/session"
6: import { and, asc, desc, eq, gt, like, lt, or, type SQL } from "drizzle-orm"
7: import { ProjectV2 } from "./project"
8: import { WorkspaceV2 } from "./workspace"
9: import { ModelV2 } from "./model"
10: import { Location } from "./location"
11: import { SessionMessage } from "./session/message"
12: import { Prompt } from "./session/prompt"
13: import { PromptInput } from "@opencode-ai/schema/prompt-input"
14: import { EventV2 } from "./event"
15: import { Database } from "./database/database"
16: import { SessionProjector } from "./session/projector"
17: import { SessionMessageTable, SessionTable } from "./session/sql"
18: import { SessionSchema } from ...
gateway · 2026-09-17 09:09:26
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/session.ts</path>
<type>file</type>
<content>
301:         )
302:         return (direction === "previous" ? rows.toReversed() : rows).map((row) => fromRow(row))
303:       }),
304:       messages: Effect.fn("V2Session.messages")(function* (input) {
305:         yield* result.get(input.sessionID)
306:         const direction = input.cursor?.direction ?? "next"
307:         const requestedOrder = input.order ?? "desc"
308:         const order = direction === "previous" ? (requestedOrder === "asc" ? "desc" : "asc") : requestedOrder
309:         const anchor = input.cursor
310:           ? yield* db
311:               .select({ seq: SessionMessageTable.seq })
312:               .from(SessionMessageTable)
313:               .where(
314:                 and(eq(SessionMessageTable.session_id, input.sessionID), eq(SessionMessageTable.id, input.cursor.id)),
315:               )
316:               .get()
317:               ...
gateway · 2026-09-17 09:09:35
result
<path>/tmp/opencode/session-recovery-v21-review/packages/opencode/src/server/routes/instance/httpapi/server.ts</path>
<type>file</type>
<content>
1: import { Config as EffectConfig, Context, Effect, Layer } from "effect"
2: import { HttpApiBuilder, OpenApi } from "effect/unstable/httpapi"
3: import { HttpClient, HttpMiddleware, HttpRouter, HttpServer, HttpServerResponse } from "effect/unstable/http"
4: import * as Socket from "effect/unstable/socket/Socket"
5: import { FSUtil } from "@opencode-ai/core/fs-util"
6: import * as Observability from "@opencode-ai/core/observability"
7: import { Account } from "@/account/account"
8: import { Agent } from "@/agent/agent"
9: import { Auth } from "@/auth"
10: import { BackgroundJob } from "@/background/job"
11: import { Command } from "@/command"
12: import { Config } from "@/config/config"
13: import { Workspace } from "@/control-plane/workspace"
14: import { Env } from "@/env"
15: import { EventV2Bridge } from "@/event-v2-bridge"
16: import { ...
gateway · 2026-09-17 09:09:41
result
<path>/tmp/opencode/session-recovery-v21-review/packages/opencode/src/server/routes/instance/httpapi/server.ts</path>
<type>file</type>
<content>
301:         [LocationServiceMap.node, locationServiceMapV2],
302:         [SessionExecution.node, SessionExecutionLocal.node],
303:       ]),
304:     ),
305:     Layer.provide(locationServiceMapV2),
306: 
307:     Layer.provide(AppNodeBuilderV1.build(app)),
308:     // Must stay last: layers provided later in this pipe build beneath earlier ones,
309:     // so Observability must come after every service graph. Otherwise eagerly forked
310:     // fibers (e.g. the ModelsDev background refresh) capture Effect's default stdout
311:     // logger and corrupt the TUI (#34730).
312:     Layer.provideMerge(Observability.layer),
313:   )
314: }
315: 
316: export const routes = createRoutes()
317: 
318: export const webHandler = lazy(() =>
319:   HttpRouter.toWebHandler(routes, {
320:     disableLogger: true,
321:     memoMap,
322:     middleware: ...
gateway · 2026-09-17 09:09:55
result
<path>/tmp/opencode/session-recovery-v21-review/packages/server/src/routes.ts</path>
<type>file</type>
<content>
1: import { Database } from "@opencode-ai/core/database/database"
2: import { LayerNode } from "@opencode-ai/core/effect/layer-node"
3: import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
4: import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
5: import { EventV2 } from "@opencode-ai/core/event"
6: import { Credential } from "@opencode-ai/core/credential"
7: import { PermissionSaved } from "@opencode-ai/core/permission/saved"
8: import { PtyTicket } from "@opencode-ai/core/pty/ticket"
9: import { SessionV2 } from "@opencode-ai/core/session"
10: import { SessionExecution } from "@opencode-ai/core/session/execution"
11: import { LocationServiceMap } from "@opencode-ai/core/location-service-map"
12: import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
13: import { SessionRecovery } from ...
gateway · 2026-09-17 09:10:02
result
<path>/tmp/opencode/session-recovery-v21-review/packages/schema/src/session-event.ts</path>
<type>file</type>
<content>
1: export * as SessionEvent from "./session-event"
2: 
3: import { Schema } from "effect"
4: import { optional } from "./schema"
5: import { Event } from "./event"
6: import { ProviderMetadata, ToolContent } from "./llm"
7: import { Delivery } from "./session-delivery"
8: import { Model } from "./model"
9: import { DateTimeUtcFromMillis, NonNegativeInt, RelativePath } from "./schema"
10: import { FileAttachment, Prompt } from "./prompt"
11: import { SessionID } from "./session-id"
12: import { Location } from "./location"
13: import { SessionMessage } from "./session-message"
14: import { Revert } from "./revert"
15: 
16: export { FileAttachment }
17: 
18: export const Source = Schema.Struct({
19:   start: NonNegativeInt,
20:   end: NonNegativeInt,
21:   text: Schema.String,
22: }).annotate({
23:   identifier: "session.next.event.source",
24: })
25: export interface ...
gateway · 2026-09-17 09:10:08
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/schema.json</path>
<type>file</type>
<content>
1: {
2:   "version": "7",
3:   "dialect": "sqlite",
4:   "id": "3bc49670-06d1-4eba-9a45-8c8128bdcf6f",
5:   "prevIds": [
6:     "f14a9b18-8207-487e-a3d3-227e629ba9ad"
7:   ],
8:   "ddl": [
9:     {
10:       "name": "workspace",
11:       "entityType": "tables"
12:     },
13:     {
14:       "name": "data_migration",
15:       "entityType": "tables"
16:     },
17:     {
18:       "name": "account_state",
19:       "entityType": "tables"
20:     },
21:     {
22:       "name": "account",
23:       "entityType": "tables"
24:     },
25:     {
26:       "name": "control_account",
27:       "entityType": "tables"
28:     },
29:     {
30:       "name": "credential",
31:       "entityType": "tables"
32:     },
33:     {
34:       "name": "event_sequence",
35:       "entityType": "tables"
36:     },
37:     {
38:       "name": "event",
39:       "entityType": "tables"
40:     },
41:     ...
gateway · 2026-09-17 09:10:21
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/database/migration.gen.ts</path>
<type>file</type>
<content>
1: import type { DatabaseMigration } from "./migration"
2: 
3: export const migrations = (
4:   await Promise.all([
5:     import("./migration/20260127222353_familiar_lady_ursula"),
6:     import("./migration/20260211171708_add_project_commands"),
7:     import("./migration/20260213144116_wakeful_the_professor"),
8:     import("./migration/20260225215848_workspace"),
9:     import("./migration/20260227213759_add_session_workspace_id"),
10:     import("./migration/20260228203230_blue_harpoon"),
11:     import("./migration/20260303231226_add_workspace_fields"),
12:     import("./migration/20260309230000_move_org_to_state"),
13:     import("./migration/20260312043431_session_message_cursor"),
14:     import("./migration/20260323234822_events"),
15:     import("./migration/20260410174513_workspace-name"),
16:     ...
gateway · 2026-09-17 09:10:30
result
Found 21 matches
/tmp/opencode/session-recovery-v21-review/packages/core/src/database/schema.gen.ts:
  Line 158:         CREATE TABLE \`session_execution\` (

  Line 168:           CONSTRAINT \`session_execution_pk\` PRIMARY KEY(\`id\`),

  Line 169:           CONSTRAINT \`fk_session_execution_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE,

  Line 170:           CONSTRAINT "session_execution_phase_check" CHECK("phase" IN ('ready', 'safe', 'unknown', 'continue', 'cancelling', 'cancelled'))

  Line 181:           \`wake_pending\` integer DEFAULT false NOT NULL,

  Line 199:         CREATE TABLE \`session_recovery\` (

  Line 205:           \`wake_pending\` integer DEFAULT true NOT NULL,

  Line 206:           \`wake_attempts\` integer DEFAULT 0 NOT NULL,

  Line 209:           CONSTRAINT \`session_recovery_pk\` PRIMARY KEY(\`execution_id\`),

  Line 210:           CONSTRAINT \`fk_session_recovery_session_id_session_id_fk\` ...
gateway · 2026-09-17 09:10:40
result
abf93718acd0193fa2ca6cfc205cde8714eff23d7df42a4f093a55e9921fd1a3  -
f14a9b18-8207-487e-a3d3-227e629ba9ad
['169a0f0f-d58f-479f-b024-fa1c7b9a09db']
gateway · 2026-09-17 09:10:56
result
Found 20 matches
/tmp/opencode/session-recovery-v21-review/packages/core/test/session-execution-local.test.ts:
  Line 17: const it = testEffect(Database.layerFromPath(":memory:"))

  Line 82:       expect(yield* Deferred.await(observed)).toBe(7)

  Line 95:       yield* Deferred.await(started)

  Line 110:       yield* Deferred.await(started)

  Line 130:       yield* Deferred.await(firstStarted)

  Line 154:       yield* Deferred.await(firstStarted)

  Line 201:       yield* Deferred.await(started)

  Line 225:       yield* Deferred.await(started)

  Line 255:                   ? Deferred.succeed(finalizerStarted, undefined).pipe(Effect.andThen(Deferred.await(releaseFinalizer)))

  Line 262:       yield* Deferred.await(firstStarted)

  Line 264:       yield* Deferred.await(finalizerStarted)

  Line 271:       yield* Deferred.await(successorStarted)

  Line 293:               Deferred.succeed(finalizerStarted, undefined).pipe(Effect.andThen(Deferred.await(releaseFinalizer))),

  Line ...
gateway · 2026-09-17 09:11:04
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-execution-local.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { Deferred, Effect, Exit, Fiber, Scope } from "effect"
3: import { TestClock } from "effect/testing"
4: import { eq, sql } from "drizzle-orm"
5: import { Database } from "@opencode-ai/core/database/database"
6: import { Project } from "@opencode-ai/core/project"
7: import { ProjectTable } from "@opencode-ai/core/project/sql"
8: import { AbsolutePath } from "@opencode-ai/core/schema"
9: import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
10: import { SessionExecutionClaim } from "@opencode-ai/core/session/execution/claim"
11: import { SessionMessage } from "@opencode-ai/core/session/message"
12: import { SessionSchema } from "@opencode-ai/core/session/schema"
13: import { SessionExecutionTable, SessionTable } from "@opencode-ai/core/session/sql"
14: import { testEffect ...
gateway · 2026-09-17 09:11:11
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-run-coordinator.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
3: import { SessionRunCoordinator } from "@opencode-ai/core/session/run-coordinator"
4: import { testEffect } from "./lib/effect"
5: 
6: const it = testEffect(Layer.empty)
7: 
8: describe("SessionRunCoordinator", () => {
9:   it.effect("joins concurrent resumes for one key", () =>
10:     Effect.scoped(
11:       Effect.gen(function* () {
12:         const gate = yield* Deferred.make<void>()
13:         let runs = 0
14:         const coordinator = yield* SessionRunCoordinator.make({
15:           drain: () => Effect.sync(() => runs++).pipe(Effect.andThen(Deferred.await(gate))),
16:         })
17: 
18:         const first = yield* coordinator.run("session").pipe(Effect.forkChild)
19:         yield* Effect.yieldNow
20:         const ...
gateway · 2026-09-17 09:11:21
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-run-coordinator.test.ts</path>
<type>file</type>
<content>
401:         yield* Deferred.await(cleanupStarted)
402:         const second = yield* coordinator
403:           .interrupt("session", Effect.sync(() => cleanups++))
404:           .pipe(Effect.ensuring(Deferred.succeed(secondDone, undefined)), Effect.forkChild)
405:         yield* coordinator.wake("session")
406:         yield* Effect.yieldNow
407: 
408:         expect(cleanups).toBe(1)
409:         expect(yield* Deferred.isDone(firstDone)).toBe(false)
410:         expect(yield* Deferred.isDone(secondDone)).toBe(false)
411:         expect(runs).toBe(1)
412: 
413:         yield* Deferred.succeed(cleanupGate, undefined)
414:         yield* Effect.all([Fiber.join(first), Fiber.join(second)])
415:         yield* Deferred.await(secondStarted)
416: 
417:         expect(cleanups).toBe(1)
418:         expect(runs).toBe(2)
419:       }),
420:     ),
421:   ...
gateway · 2026-09-17 09:11:30
result
Found 41 matches
/tmp/opencode/session-recovery-v21-review/packages/core/test/session-projector.test.ts:
  Line 68:   it.effect("atomically reconciles one abandoned execution into one continuation", () =>

  Line 222:   it.effect("never continues a Step that durably failed before owner loss", () =>

  Line 325:   it.effect("records a recovery continuation without forging an assistant identity", () =>

  Line 361:   it.effect("recovers each abandoned execution once across repeated startup scans", () =>

  Line 407:   it.effect("never recovers a live execution lease", () =>

  Line 445:   it.effect("never recovers an execution superseded by a newer assistant", () =>

  Line 607:   it.effect("recovers assistant-less continuation at its current assistant boundary", () =>

  Line 658:   it.effect("redrives a durable recovery wake after admission", () =>

  Line 709:   it.effect("quarantines a malformed recovery row without blocking a valid wake", () =>

  Line 763:   it.effect("quarantines ...
gateway · 2026-09-17 09:11:39
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { DateTime, Deferred, Effect, Exit, Fiber, Schema } from "effect"
3: import { TestClock } from "effect/testing"
4: import { asc, eq, sql } from "drizzle-orm"
5: import { Database } from "@opencode-ai/core/database/database"
6: import { LayerNode } from "@opencode-ai/core/effect/layer-node"
7: import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
8: import { EventV2 } from "@opencode-ai/core/event"
9: import { EventTable } from "@opencode-ai/core/event/sql"
10: import { ModelV2 } from "@opencode-ai/core/model"
11: import { Project } from "@opencode-ai/core/project"
12: import { ProjectTable } from "@opencode-ai/core/project/sql"
13: import { ProviderV2 } from "@opencode-ai/core/provider"
14: import { AbsolutePath } from "@opencode-ai/core/schema"
15: import { SessionV2 } from ...
gateway · 2026-09-17 09:11:44
result
Found 8 matches
/tmp/opencode/session-recovery-v21-review/packages/core/test/session-projector.test.ts:
  Line 222:   it.effect("never continues a Step that durably failed before owner loss", () =>

  Line 349:         phase: "continue",

  Line 354:         phase: "continue",

  Line 635:           phase: "continue",

  Line 648:         phase: "continue",

  Line 1661:         phase: "continue",

  Line 1682:         expect.objectContaining({ execution_id: "conflicting-recovery-identity", phase: "continue" }),

  Line 1913:           phase: "continue",
gateway · 2026-09-17 09:11:56
result
Found 51 matches
/tmp/opencode/session-recovery-v21-review/packages/core/test/session-runner.test.ts:
  Line 619:   it.effect("redrives only the synthetic recovery continuation", () =>

  Line 752:   it.effect("never dispatches a provider after ownership changes", () =>

  Line 778:   it.effect("never publishes streamed output after ownership changes", () =>

  Line 805:   it.effect("never starts a local tool after ownership changes", () =>

  Line 845:   it.effect("never fails interrupted tools after ownership changes", () =>

  Line 902:   it.effect("advertises and executes a globally attached application tool", () =>

  Line 1034:   it.effect("interrupts a source Location runner after a Session moves", () =>

  Line 1060:   it.effect("fails gracefully when a stored context snapshot cannot be decoded", () =>

  Line 1542:   it.effect("recovers the continuation committed with Compaction.Ended", () =>

  Line 1686:   it.effect("persists a second context overflow after one recovery", ...
gateway · 2026-09-17 09:12:01
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
580:     responseStream = Stream.concat(
581:       Stream.fromIterable(fixture.partialEvents),
582:       Stream.fromEffect(Deferred.succeed(streamed, undefined)).pipe(Stream.flatMap(() => Stream.never)),
583:     )
584: 
585:     const runner = yield* SessionRunner.Service
586:     yield* insertExecution(sessionID)
587:     const fiber = yield* runner.run({ sessionID, force: true, executionID, ownerID: "test" }).pipe(Effect.forkChild)
588:     yield* Deferred.await(streamed)
589:     yield* Fiber.interrupt(fiber)
590:     const { db } = yield* Database.Service
591:     expect(
592:       yield* db
593:         .select({ id: SessionExecutionTable.id, phase: SessionExecutionTable.phase })
594:         .from(SessionExecutionTable)
595:         .where(eq(SessionExecutionTable.session_id, sessionID))
596:         .get(),
597:     ).toEqual({ id: executionID, phase: ...
gateway · 2026-09-17 09:12:07
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
1500:       response = fragmentFixture("text", "text-before-compaction", ["Earlier answer"]).completeEvents
1501:       yield* session.prompt({
1502:         sessionID,
1503:         prompt: Prompt.make({ text: "Earlier question ".repeat(180) }),
1504:         resume: false,
1505:       })
1506:       yield* session.resume(sessionID)
1507: 
1508:       currentModel = compactModel
1509:       requests.length = 0
1510:       responseStream = Stream.fromIterable(
1511:         fragmentFixture("text", "text-uncommitted-summary", ["## Objective\n- Interrupted"]).completeEvents,
1512:       ).pipe(
1513:         Stream.ensuring(
1514:           db
1515:             .update(SessionExecutionTable)
1516:             .set({ id: "compaction-successor", owner_id: "successor", expires_at: 60_000 })
1517:             .where(eq(SessionExecutionTable.session_id, ...
gateway · 2026-09-17 09:12:15
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
1880:         {
1881:           type: "assistant",
1882:           finish: "tool-calls",
1883:           tokens: { input: 8, output: 3, reasoning: 1, cache: { read: 2, write: 0 } },
1884:           content: [
1885:             { type: "reasoning", id: "reasoning-1", text: "Think" },
1886:             {
1887:               type: "tool",
1888:               id: "call-error",
1889:               name: "write",
1890:               state: {
1891:                 status: "error",
1892:                 input: { path: "README.md" },
1893:                 error: { type: "unknown", message: "Denied" },
1894:               },
1895:             },
1896:             {
1897:               type: "tool",
1898:               id: "call-provider",
1899:               name: "web_search",
1900:               provider: { executed: true, metadata: { fake: { source: "provider" } } ...
gateway · 2026-09-17 09:12:21
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
3800:           input: Schema.Struct({}),
3801:           output: Schema.Struct({}),
3802:           execute: () =>
3803:             Deferred.succeed(executionStarted, undefined).pipe(
3804:               Effect.andThen(Effect.never),
3805:               Effect.ensuring(
3806:                 Deferred.succeed(finalizerStarted, undefined).pipe(Effect.andThen(Deferred.await(releaseFinalizer))),
3807:               ),
3808:             ),
3809:         }),
3810:         sibling_defect: Tool.make({
3811:           description: "Fail while another tool remains active",
3812:           input: Schema.Struct({}),
3813:           output: Schema.Struct({}),
3814:           execute: () => Deferred.await(executionStarted).pipe(Effect.andThen(Effect.die("sibling defect"))),
3815:         }),
3816:       })
3817:       yield* session.prompt({ sessionID, prompt: Prompt.make({ ...
gateway · 2026-09-17 09:12:36
result
Found 16 matches
/tmp/opencode/session-recovery-v21-review/packages/core/test/session-prompt.test.ts:
  Line 140:   it.effect("exposes the execution registry", () =>

  Line 147:   it.effect("delegates execution continuation through SessionExecution", () =>

  Line 181:   it.effect("durably admits one user message before transcript promotion", () =>

  Line 254:   it.effect("resumes through a recorded message without appending another prompt", () =>

  Line 310:   it.effect("wakes execution when an exact prompt retry recovers a committed message", () =>

  Line 330:   it.effect("never wakes execution when retrying an already promoted prompt", () =>

  Line 374:   it.effect("durably records execution intent before advisory wake", () =>

  Line 408:   it.effect("replays historical prompt admission without execution intent as admit-only", () =>

  Line 440:   it.effect("turns an admit-only exact retry into durable execution intent", () =>

  Line 514:   it.effect("never arms durable wake ...
gateway · 2026-09-17 09:12:51
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/database-migration.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect, test } from "bun:test"
2: import { $ } from "bun"
3: import { fileURLToPath } from "url"
4: import path from "path"
5: import { SqliteClient } from "@effect/sql-sqlite-bun"
6: import { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
7: import { Effect, Exit, Layer } from "effect"
8: import { eq, inArray, sql } from "drizzle-orm"
9: import { DatabaseMigration } from "@opencode-ai/core/database/migration"
10: import { migrations } from "@opencode-ai/core/database/migration.gen"
11: import workspaceNameMigration from "@opencode-ai/core/database/migration/20260410174513_workspace-name"
12: import sessionUsageMigration from "@opencode-ai/core/database/migration/20260510033149_session_usage"
13: import normalizeStoragePathsMigration from "@opencode-ai/core/database/migration/20260601010001_normalize_storage_paths"
14: ...
gateway · 2026-09-17 09:13:11
result
No files found
gateway · 2026-09-17 09:13:22
result
/tmp/opencode/session-recovery-v21-review/packages/core/src/event.ts
gateway · 2026-09-17 09:13:29
result
Found 23 matches
/tmp/opencode/session-recovery-v21-review/packages/core/src/event.ts:
  Line 122:   /** Local operational projection committed atomically with a new durable event. Not replayed or serialized. */

  Line 123:   readonly commit?: (seq: number) => Effect.Effect<void>

  Line 205:       function commitDurableEvent(

  Line 214:         commit?: (seq: number) => Effect.Effect<void>,

  Line 239:                   const committed = yield* db

  Line 316:                           const committed = {

  Line 321:                             yield* projector(committed)

  Line 323:                           if (commit) yield* commit(seq)

  Line 354:                   if (committed) {

  Line 356:                       pubsub.durable.get(committed.aggregateID) ?? [],

  Line 361:                   return committed

  Line 369:       function publishEvent<D extends Definition>(definition: D, event: Payload<D>, commit?: PublishOptions["commit"]) {

  Line 371:           if ...
gateway · 2026-09-17 09:13:34
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/event.ts</path>
<type>file</type>
<content>
190:           return created
191:         })
192: 
193:       yield* Effect.addFinalizer(() =>
194:         Effect.gen(function* () {
195:           yield* PubSub.shutdown(pubsub.all)
196:           yield* Effect.forEach(
197:             pubsub.durable.values(),
198:             (pubsubs) => Effect.forEach(pubsubs, PubSub.shutdown, { discard: true }),
199:             { discard: true },
200:           )
201:           yield* Effect.forEach(pubsub.typed.values(), PubSub.shutdown, { discard: true })
202:         }),
203:       )
204: 
205:       function commitDurableEvent(
206:         definition: Definition,
207:         event: Payload,
208:         input?: {
209:           readonly seq: number
210:           readonly aggregateID: string
211:           readonly ownerID?: string
212:           readonly strictOwner?: boolean
213:         },
214:         commit?: (seq: number) ...
gateway · 2026-09-17 09:13:43
result
Found 1 matches
/tmp/opencode/session-recovery-v21-review/packages/core/test/session-runner.test.ts:
  Line 4200:           LLMEvent.toolCall({ id: "call-terminal", name: "echo", input: { text: "done" } }),
gateway · 2026-09-17 09:13:58
result
Found 4 matches
/tmp/opencode/session-recovery-v21-review/packages/core/test/session-projector.test.ts:
  Line 266:         callID: "call-failed-before-owner-loss",

  Line 273:         callID: "call-failed-before-owner-loss",

  Line 280:         callID: "call-failed-before-owner-loss",

  Line 307:             id: "call-failed-before-owner-loss",
gateway · 2026-09-17 09:14:32
result
<path>/tmp/opencode/session-recovery-v21-review/packages/schema/test/event-manifest.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect, test } from "bun:test"
2: import { FileSystem, Integration, Permission, Project, Reference, Session, Workspace } from "../src"
3: import { EventManifest } from "../src/event-manifest"
4: import { IdeEvent } from "../src/ide-event"
5: import { SessionEvent } from "../src/session-event"
6: import { SessionTodo } from "../src/session-todo"
7: import { SessionV1 } from "../src/session-v1"
8: import { WorkspaceEvent } from "../src/workspace-event"
9: 
10: describe("public event manifest", () => {
11:   test("owns the complete public event surface", () => {
12:     expect(EventManifest.ServerDefinitions.length).toBe(61)
13:     expect(EventManifest.Definitions.length).toBe(91)
14:     expect(SessionV1.Event.Definitions).toEqual([
15:       SessionV1.Event.Created,
16:       SessionV1.Event.Updated,
17:       SessionV1.Event.Deleted,
18: ...
gateway · 2026-09-17 09:14:45
result
Found 11 matches
/tmp/opencode/session-recovery-v21-review/packages/schema/src/durable-event-manifest.ts:
  Line 1: export * as DurableEventManifest from "./durable-event-manifest"

  Line 7: export const SessionDurable = {

  Line 8:   definitions: Event.durable(SessionEvent.DurableDefinitions),

  Line 9:   schema: SessionEvent.Durable,

  Line 12: export const Durable = Event.durable([

  Line 14:   ...SessionEvent.DurableDefinitions,


/tmp/opencode/session-recovery-v21-review/packages/schema/src/event-manifest.ts:
  Line 4: import { Durable } from "./durable-event-manifest"

  Line 34: const sessionV1DurableDefinitions = SessionV1.Event.Definitions.filter((definition) => definition.durable !== undefined)

  Line 37: const coreDefinitions = Event.inventory(...sessionV1DurableDefinitions, ...SessionEvent.Definitions)

  Line 83: export const Latest = Event.latest(Definitions)

  Line 84: export { Durable }
gateway · 2026-09-17 09:14:54
result
<path>/tmp/opencode/session-recovery-v21-review/packages/schema/src/durable-event-manifest.ts</path>
<type>file</type>
<content>
1: export * as DurableEventManifest from "./durable-event-manifest"
2: 
3: import { Event } from "./event"
4: import { SessionEvent } from "./session-event"
5: import { SessionV1 } from "./session-v1"
6: 
7: export const SessionDurable = {
8:   definitions: Event.durable(SessionEvent.DurableDefinitions),
9:   schema: SessionEvent.Durable,
10: } as const
11: 
12: export const Durable = Event.durable([
13:   ...SessionV1.Event.Definitions.filter((definition) => definition.durable !== undefined),
14:   ...SessionEvent.DurableDefinitions,
15: ])

(End of file - total 15 lines)
</content>
gateway · 2026-09-17 09:15:01
result
No files found
gateway · 2026-09-17 09:15:11
result
diff --git a/packages/schema/src/session-event.ts b/packages/schema/src/session-event.ts
index 3a559c3e38..2599bbb78f 100644
--- a/packages/schema/src/session-event.ts
+++ b/packages/schema/src/session-event.ts
@@ -94,10 +94,23 @@ export type Prompted = typeof Prompted.Type
 export const PromptAdmitted = Event.define({
   type: "session.next.prompt.admitted",
   ...options,
-  schema: PromptFields,
+  schema: {
+    ...PromptFields,
+    requestExecution: Schema.Boolean.pipe(optional),
+  },
 })
 export type PromptAdmitted = typeof PromptAdmitted.Type
 
+export const PromptExecutionRequested = Event.define({
+  type: "session.next.prompt.execution_requested",
+  ...options,
+  schema: {
+    ...Base,
+    messageID: SessionMessage.ID,
+  },
+})
+export type PromptExecutionRequested = typeof PromptExecutionRequested.Type
+
 export const ContextUpdated = Event.define({
   type: "session.next.context.updated",
   ...options,
@@ -192,6 +205,29 @@ export namespace Step {
     },
   })
   ...
gateway · 2026-09-17 09:15:30
result
Found 74 matches
/tmp/opencode/session-recovery-v21-review/packages/core/test/session-projector.test.ts:
  Line 95:           phase: "unknown",

  Line 115:           phase: "unknown",

  Line 146:         phase: "unknown",

  Line 215:         phase: "unknown",

  Line 250:           phase: "unknown",

  Line 349:         phase: "continue",

  Line 354:         phase: "continue",

  Line 385:           phase: "ready",

  Line 431:           phase: "unknown",

  Line 478:           phase: "unknown",

  Line 492:   for (const phase of ["ready", "unknown", "continue"] as const) {

  Line 493:     it.effect(`never recovers an assistant-less ${phase} execution superseded by a newer assistant`, () =>

  Line 513:           .values(assistantRow(SessionMessage.ID.make(`msg_recovery_newer_${phase}`), 0, { created, completed: created }))

  Line 518:             id: `assistant-less-${phase}`,

  Line 521:             phase,

  Line 537:   for (const phase of ["ready", "unknown", "continue"] as ...
gateway · 2026-09-17 09:15:41
result
Found 33 matches
/tmp/opencode/session-recovery-v21-review/packages/sdk/js/src/v2/gen/types.gen.ts:
  Line 24:   | EventSessionNextPromptExecutionRequested

  Line 32:   | EventSessionNextStepInterrupted

  Line 33:   | EventSessionNextStepRecovered

  Line 874:           requestExecution?: boolean

  Line 973:         type: "session.next.step.interrupted"

  Line 983:         type: "session.next.step.recovered"

  Line 1650:     | SyncEventSessionNextPromptExecutionRequested

  Line 1658:     | SyncEventSessionNextStepInterrupted

  Line 1659:     | SyncEventSessionNextStepRecovered

  Line 2785:   | SessionNextPromptExecutionRequested

  Line 2793:   | SessionNextStepInterrupted

  Line 2794:   | SessionNextStepRecovered

  Line 2915:   | SessionNextPromptExecutionRequested

  Line 2923:   | SessionNextStepInterrupted

  Line 2924:   | SessionNextStepRecovered

  Line 3430:       requestExecution?: boolean

  Line 3435: export type SyncEventSessionNextPromptExecutionRequested = {

  ...
gateway · 2026-09-17 09:15:46
result
<path>/tmp/opencode/session-recovery-v21-review/packages/sdk/js/src/v2/gen/types.gen.ts</path>
<type>file</type>
<content>
3410:       prompt: Prompt
3411:       delivery: "steer" | "queue"
3412:     }
3413:   }
3414: }
3415: 
3416: export type SyncEventSessionNextPromptAdmitted = {
3417:   type: "sync"
3418:   id: string
3419:   syncEvent: {
3420:     type: "session.next.prompt.admitted.1"
3421:     id: string
3422:     seq: number
3423:     aggregateID: string
3424:     data: {
3425:       timestamp: number
3426:       sessionID: string
3427:       messageID: string
3428:       prompt: Prompt
3429:       delivery: "steer" | "queue"
3430:       requestExecution?: boolean
3431:     }
3432:   }
3433: }
3434: 
3435: export type SyncEventSessionNextPromptExecutionRequested = {
3436:   type: "sync"
3437:   id: string
3438:   syncEvent: {
3439:     type: "session.next.prompt.execution_requested.1"
3440:     id: string
3441:     seq: number
3442:     aggregateID: string
3443:     data: ...
gateway · 2026-09-17 09:16:25
result
openapi_valid=true paths=162 schemas=481
session.next.prompt.execution_requested=4
session.next.step.interrupted=4
session.next.step.recovered=4
requestExecution=4
gateway · 2026-09-17 09:16:55
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1080:             delivery: "steer",
1081:             requestExecution: true,
1082:           }),
1083:         { discard: true, concurrency: 1 },
1084:       )
1085:       yield* db.run(sql`CREATE TABLE ordinary_redrive_input_updates (count integer NOT NULL)`)
1086:       yield* db.run(sql`INSERT INTO ordinary_redrive_input_updates (count) VALUES (0)`)
1087:       yield* db.run(sql`
1088:         CREATE TRIGGER count_ordinary_redrive_input_updates
1089:         AFTER UPDATE ON session_input
1090:         BEGIN
1091:           UPDATE ordinary_redrive_input_updates SET count = count + 1;
1092:         END
1093:       `)
1094:       let wakes = 0
1095: 
1096:       yield* SessionRecovery.recover().pipe(
1097:         Effect.provideService(
1098:           SessionExecution.Service,
1099:           SessionExecution.Service.of({
1100:             ...
gateway · 2026-09-17 09:17:04
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1779:       expect(wakes).toEqual([])
1780:       expect(yield* SessionInput.hasPending(db, sessionID, "queue")).toBe(false)
1781:       expect(yield* SessionInput.promoteNextQueued(db, events, sessionID)).toBe(false)
1782:       yield* SessionInput.admit(db, events, {
1783:         id: ordinaryID,
1784:         sessionID,
1785:         prompt: Prompt.make({ text: "later" }),
1786:         delivery: "queue",
1787:         requestExecution: false,
1788:       })
1789: 
1790:       expect(yield* SessionInput.hasPending(db, sessionID, "queue")).toBe(true)
1791:       expect(yield* SessionInput.promoteNextQueued(db, events, sessionID)).toBe(true)
1792:       expect(yield* db.select().from(SessionInputTable).where(eq(SessionInputTable.id, continuationID)).get()).toMatchObject(
1793:         { promoted_seq: null },
1794:       )
1795:       expect(yield* ...
gateway · 2026-09-17 09:17:25
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/src/database/schema.gen.ts</path>
<type>file</type>
<content>
140:           \`message_id\` text NOT NULL,
141:           \`session_id\` text NOT NULL,
142:           \`time_created\` integer NOT NULL,
143:           \`time_updated\` integer NOT NULL,
144:           \`data\` text NOT NULL,
145:           CONSTRAINT \`fk_part_message_id_message_id_fk\` FOREIGN KEY (\`message_id\`) REFERENCES \`message\`(\`id\`) ON DELETE CASCADE
146:         );
147:       `)
148:       yield* tx.run(`
149:         CREATE TABLE \`session_context_epoch\` (
150:           \`session_id\` text PRIMARY KEY,
151:           \`baseline\` text NOT NULL,
152:           \`snapshot\` text NOT NULL,
153:           \`baseline_seq\` integer NOT NULL,
154:           CONSTRAINT \`fk_session_context_epoch_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE
155:         );
156:       `)
157:       yield* ...
gateway · 2026-09-17 09:17:31
result
diff --git a/packages/core/test/session-runner-recorded.test.ts b/packages/core/test/session-runner-recorded.test.ts
index d45cc8c734..ec91d1b4a4 100644
--- a/packages/core/test/session-runner-recorded.test.ts
+++ b/packages/core/test/session-runner-recorded.test.ts
@@ -19,7 +19,7 @@ import { Snapshot } from "@opencode-ai/core/snapshot"
 import { Prompt } from "@opencode-ai/core/session/prompt"
 import { SessionProjector } from "@opencode-ai/core/session/projector"
 import { SessionExecution } from "@opencode-ai/core/session/execution"
-import { SessionRunCoordinator } from "@opencode-ai/core/session/run-coordinator"
+import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
 import { SessionRunner } from "@opencode-ai/core/session/runner"
 import * as SessionRunnerLLM from "@opencode-ai/core/session/runner/llm"
 import { SessionRunnerModel } from "@opencode-ai/core/session/runner/model"
@@ -88,17 +88,11 @@ const execution = Layer.effect(
   ...
gateway · 2026-09-17 09:17:38
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-prompt.test.ts</path>
<type>file</type>
<content>
120:       type: event.type,
121:       data: event.data,
122:     })),
123:   )
124: })
125: 
126: const recover = () =>
127:   SessionRecovery.recover().pipe(
128:     Effect.provideService(
129:       SessionExecution.Service,
130:       SessionExecution.Service.of({
131:         active: Effect.succeed(new Set()),
132:         resume: () => Effect.void,
133:         interrupt: () => Effect.void,
134:         wake: (id) => Effect.sync(() => wakeCalls.push(id)).pipe(Effect.asVoid),
135:       }),
136:     ),
137:   )
138: 
139: describe("SessionV2.prompt", () => {
140:   it.effect("exposes the execution registry", () =>
141:     Effect.gen(function* () {
142:       activeSessions.add(sessionID)
143:       expect(Array.from(yield* (yield* SessionV2.Service).active)).toEqual([sessionID])
144:     }).pipe(Effect.ensuring(Effect.sync(() => ...
gateway · 2026-09-17 09:18:32
result
<path>/tmp/opencode/session-recovery-v21-review/packages/client/src/generated/types.ts</path>
<type>file</type>
<content>
740:               readonly mime: string
741:               readonly name?: string
742:               readonly description?: string
743:               readonly source?: { readonly start: number; readonly end: number; readonly text: string }
744:             }>
745:             readonly agents?: ReadonlyArray<{
746:               readonly name: string
747:               readonly source?: { readonly start: number; readonly end: number; readonly text: string }
748:             }>
749:           }
750:           readonly delivery: "steer" | "queue"
751:         }
752:       }
753:     | {
754:         readonly id: string
755:         readonly metadata?: { readonly [x: string]: JsonValue }
756:         readonly type: "session.next.prompt.admitted"
757:         readonly durable?: { readonly aggregateID: string; readonly seq: number; readonly version: number }
758:        ...
gateway · 2026-09-17 09:18:44
result
Found 40 matches
/tmp/opencode/session-recovery-v21-review/packages/core/schema.json:
  Line 66:       "name": "session_execution",

  Line 78:       "name": "session_recovery",

  Line 941:       "table": "session_execution"

  Line 951:       "table": "session_execution"

  Line 961:       "table": "session_execution"

  Line 971:       "table": "session_execution"

  Line 981:       "table": "session_execution"

  Line 991:       "table": "session_execution"

  Line 1001:       "table": "session_execution"

  Line 1011:       "table": "session_execution"

  Line 1021:       "table": "session_execution"

  Line 1089:       "name": "wake_pending",

  Line 1181:       "table": "session_recovery"

  Line 1191:       "table": "session_recovery"

  Line 1201:       "table": "session_recovery"

  Line 1211:       "table": "session_recovery"

  Line 1221:       "table": "session_recovery"

  Line 1229:       "name": "wake_pending",

  Line 1231:       "table": "session_recovery"

  Line ...
gateway · 2026-09-17 09:18:56
result
<path>/tmp/opencode/session-recovery-v21-review/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
580:                     assistantMessageID: SessionMessage.ID.make(`msg_recovery_race_${phase}`),
581:                     agent: "build",
582:                     model,
583:                   })
584:                   return yield* events.publish(definition, data, options)
585:                 }),
586:         })
587: 
588:         yield* SessionRecovery.recover().pipe(
589:           Effect.provideService(EventV2.Service, intercepted),
590:           Effect.provideService(SessionExecution.Service, recoveryExecution),
591:         )
592: 
593:         expect(yield* db.select().from(SessionExecutionTable).all()).toEqual([])
594:         expect(yield* db.select().from(SessionRecoveryTable).all()).toEqual([])
595:         expect(yield* db.select().from(SessionInputTable).all()).toEqual([])
596:         expect(
597:           yield* db
598:             ...
gateway · 2026-09-17 09:19:18
result
Found 14 matches
/tmp/opencode/session-recovery-v21-review/packages/core/src/session/execution/claim.ts:
  Line 53:     .update(SessionExecutionTable)

  Line 70:     .update(SessionExecutionTable)

  Line 91:     .update(SessionExecutionTable)

  Line 103:     .delete(SessionExecutionTable)


/tmp/opencode/session-recovery-v21-review/packages/core/src/session/execution/local.ts:
  Line 53:                 .insert(SessionExecutionTable)

  Line 110:               .from(SessionExecutionTable)

  Line 188:                     .from(SessionExecutionTable)


/tmp/opencode/session-recovery-v21-review/packages/core/src/session/recovery.ts:
  Line 74:     .from(SessionExecutionTable)

  Line 86:           .update(SessionExecutionTable)

  Line 106:             .update(SessionExecutionTable)

  Line 129:             .update(SessionExecutionTable)

  Line 295:                           ...
gateway · 2026-09-17 09:19:59
result
2ae4eea72024cafe8b69c0461063ee25cbf54608856cd258866b7f3b86620b36  /tmp/opencode/session-recovery-final-v21.patch
10a3698a5e3b009f811a1b27eefab9e1083b560e24efee5f537f003d7edd7384  /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server
ab9408c81cc9916177641ae8e9f08624fc27b5b9
patch_paths=34 worktree_paths=34 path_sets_equal=True
gateway · 2026-09-17 09:20:14
result
path=/home/byk/Code/opencode/packages/opencode/dist/server/opencode-server size=157879104 mtime=2026-09-17 09:18:02.709852813 +0000 inode=19532879
/home/byk/Code/opencode/packages/opencode/dist/server/opencode-server
gateway · 2026-09-17 09:20:38

MUST-FIX

  • The frozen SEA changed during review. Initial SHA-256 matched the required aa98d64abb3bf6ac0ef88a940f9c41c6eb14ffeab3c3a7846921ba01ef46643d; final verification produced 10a3698a5e3b009f811a1b27eefab9e1083b560e24efee5f537f003d7edd7384 for /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server. The reviewed artifact is no longer immutable, so this review cannot approve the candidate.

Source inspection

No independent source-level MUST-FIX or CONCERN emerged before the artifact changed.

  • Base remained ab9408c81cc9916177641ae8e9f08624fc27b5b9.
  • Patch remained 2ae4eea72024cafe8b69c0461063ee25cbf54608856cd258866b7f3b86620b36.
  • Exactly 34 patch and worktree paths matched; reverse applicability and whitespace checks passed.
  • packages/core/schema.json:4-7 directly names base snapshot f14a9b18-8207-487e-a3d3-227e629ba9ad.
  • Completed failed Steps never enter recovery continuation; unresolved tools are durably failed one at a time before claim removal (packages/core/src/session/recovery.ts:179-218).
  • Continue-phase completed Steps still enter recovery (packages/core/src/session/recovery.ts:179-220).
  • Lease mutations use exact Session, execution, owner, and unexpired predicates (packages/core/src/session/execution/claim.ts:27-33).
  • Interruption waits for runner finalizers before durable settlement, while concurrent callers share one barrier and wakes received during cleanup survive (packages/core/src/session/execution/local.ts:168-210, packages/core/src/session/run-coordinator.ts:100-130).
  • Auth and dependency direction remain intact.

No tests, builds, services, or VCS mutations were performed. The unavailable repo-setup skill was the only setup limitation. The disclosed final check-call, process-local routing, and bounded clock-skew residuals remain accepted.

DO-NOT-MERGE

gpt-5.6-sol · 2026-09-17 09:20:38 · ~486 tokens

Distillations (16)

Gen 0 2026-09-17 10:56:32 · 1376 tokens

Date: Sep 17, 2026 * 🔴 (09:18) User established the invariant/test requirement `"never wakes execution when retrying an already promoted prompt"` in `packages/core/test/session-v2.test.ts`. * 🔴 (09:18) User established the invariant/test requirement `"never arms durable wake for a conflicting execution retry"` in `packages/core/test/session-v2.test.ts`. * 🟡 (09:18) `packages/client/src/generat…

Gen 0 2026-09-17 10:43:25 · 858 tokens

Date: Sep 17, 2026 * 🟡 (09:17) Generated schema in `packages/core/src/database/schema.gen.ts` defines `session_execution` with columns `id`, `session_id`, `owner_id`, nullable `assistant_message_id`, `phase`, `assistant_seq` default `-1`, `time_created`, `expires_at`, and nullable `recovery_error`; `session_execution_phase_check` permits `'ready'`, `'safe'`, `'unknown'`, `'continue'`, `'cancelli…

Gen 0 2026-09-17 10:43:03 · 580 tokens

Date: Sep 17, 2026 * 🟡 (09:16) Validation result: `openapi_valid=true`, with 162 paths and 481 schemas; `session.next.prompt.execution_requested`, `session.next.step.interrupted`, `session.next.step.recovered`, and `requestExecution` each appeared exactly 4 times. * 🔴 (09:17) User asserted the recovery/redrive invariant: “never wakes work settled between selection and redrive CAS”. * 🟡 (09:17)…

Gen 0 2026-09-17 10:14:19 · 489 tokens

Date: Sep 17, 2026 * 🟡 (09:16) In `packages/sdk/js/src/v2/gen/types.gen.ts`, `SyncEventSessionNextPromptAdmitted` is at lines 3416-3433; its sync event version is `"session.next.prompt.admitted.1"` and its data contains `timestamp`, `sessionID`, `messageID`, `prompt`, `delivery: "steer" | "queue"`, and optional `requestExecution?: boolean`. * 🟡 (09:16) In `packages/sdk/js/src/v2/gen/types.gen.t…

Gen 0 2026-09-17 10:14:00 · 559 tokens

Date: Sep 17, 2026 * 🟡 (09:14) Search found exactly 4 occurrences of `call-failed-before-owner-loss` in `packages/core/test/session-projector.test.ts`, at lines 266, 273, 280, and 307. * 🟡 (09:15) `packages/schema/src/session-event.ts` changes add optional `requestExecution: Schema.Boolean.pipe(optional)` to `PromptAdmitted`. * 🟡 (09:15) `packages/schema/src/session-event.ts` adds durable even…

Gen 0 2026-09-17 10:13:33 · 454 tokens

Date: Sep 17, 2026 * 🟡 (09:13) In `packages/core/src/event.ts`, `commitDurableEvent(...)` wraps durable publication in `Effect.uninterruptible` and a database transaction with `{ behavior: "immediate" }`; inside the transaction it runs registered projectors, invokes the optional `commit(seq)` hook, upserts `EventSequenceTable`, and inserts into `EventTable`, in that exact order. * 🟡 (09:13) In …

Gen 0 2026-09-17 10:13:21 · 1075 tokens

Date: Sep 17, 2026 * 🔴 (09:12) User requires continuation to never be committed before unresolved hosted tools are reconciled. * 🔴 (09:12) User requires a Step end to never be committed after the provider stream fails. * 🔴 (09:12) User requires assistant start state to never be recorded when Step start publication defects. * 🔴 (09:12) User requires execution to never be woken when retrying an…

Gen 0 2026-09-17 09:58:05 · 1536 tokens

Date: Sep 17, 2026 * 🔴 (09:11) User requires recovery to never continue a Step that durably failed before owner loss. * 🔴 (09:12) User requires the runner to never dispatch a provider after execution ownership changes. * 🔴 (09:12) User requires the runner to never publish streamed output after execution ownership changes. * 🔴 (09:12) User requires the runner to never start a local tool after …

Gen 0 2026-09-17 09:49:12 · 2373 tokens

Date: Sep 17, 2026 * 🟡 (09:10) `packages/core/src/database/migration.gen.ts` dynamically imports 39 migrations in chronological order, ending with `20260914170650_session-recovery`, and maps each module’s default export to `DatabaseMigration.Migration[]`. * 🟡 (09:10) The 39 migration module names in `packages/core/src/database/migration.gen.ts`, in order, are: 1. `20260127222353_familiar_lady_u…

Gen 0 2026-09-17 09:41:49 · 1670 tokens

Date: Sep 17, 2026 * 🟡 (09:09) `packages/core/src/session/context-epoch.ts` defines `SessionContextEpoch.initialize()` and `SessionContextEpoch.prepare()`. Both accept a `DatabaseService`, `SystemContext.SystemContext` effect, `sessionID`, and `SessionExecutionClaim.Claim`; `prepare()` additionally accepts `EventV2.Interface`. * 🟡 (09:09) `SessionContextEpoch.prepareOnce()` concurrently loads t…

Gen 0 2026-09-17 09:31:52 · 1464 tokens

Date: Sep 17, 2026 * 🔴 (09:08) User directed that local ownership be replaced with durable multi-node ownership when clustered. * 🟡 (09:08) `packages/core/src/session/runner/index.ts` defines `SessionRunner.Interface.run()` as one local continuation from recorded session history. Inputs are `sessionID`, `force`, `executionID`, `ownerID`, and optional `recoveryInputID`; the effect may fail with …

Gen 0 2026-09-17 09:21:42 · 1599 tokens

Date: Sep 17, 2026 * 🟡 (09:07) In `packages/core/src/session/projector.ts`, the `SessionEvent.Step.Recovered` projector requires `event.durable`; absence dies with `"Durable Session event is missing aggregate sequence"`. It derives `continuationMessageID` via `continuation(event.data.executionID)`. * 🟡 (09:07) `SessionEvent.Step.Recovered` projection is idempotent only when an existing `Session…

Gen 0 2026-09-17 09:14:56 · 1124 tokens

Date: Sep 17, 2026 * 🔴 (09:07) User directive: “never resume an older assistant projection”; a newer turn supersedes stale incomplete rows. * 🟡 (09:07) `packages/core/src/session/recovery.ts` exports `BATCH_SIZE = 100`. * 🟡 (09:07) Recovery redrive prioritizes one previously attempted `SessionRecoveryTable` row, then fills capacity with fresh rows where `wake_pending=true`, `recovery_error IS …

Gen 0 2026-09-17 09:08:16 · 674 tokens

Date: Sep 17, 2026 * 🟡 (09:07) Review of `packages/core/src/session/sql.ts:3` found `import * as DatabasePath from "../database/path"`, which violates the user’s stated ban on star imports; the file uses `DatabasePath.directoryColumn()` and `DatabasePath.pathColumn()` for `SessionTable`. * 🟡 (09:07) `packages/core/src/session/sql.ts` defines `MAX_WAKE_ATTEMPTS = Number.MAX_SAFE_INTEGER` and app…

Gen 0 2026-09-17 09:08:00 · 1438 tokens

Date: Sep 17, 2026 * 🟡 (09:05) Immutable-input verification succeeded: `/tmp/opencode/session-recovery-final-v21.patch` SHA-256 was `2ae4eea72024cafe8b69c0461063ee25cbf54608856cd258866b7f3b86620b36`; `/home/byk/Code/opencode/packages/opencode/dist/server/opencode-server` SHA-256 was `aa98d64abb3bf6ac0ef88a940f9c41c6eb14ffeab3c3a7846921ba01ef46643d`; checked-out base commit was `ab9408c81cc991617…

Gen 0 2026-09-17 09:07:25 · 545 tokens

Date: Sep 17, 2026 * 🔴 [requested-review] (09:05) User requested a strict READ-ONLY security/pentest review of frozen v21 in `/tmp/opencode/session-recovery-v21-review`, covering all 34 changed paths and relevant context. * 🔴 [enforced-workflow] (09:05) User directed not to edit files, run tests/builds/services, mutate VCS/index/refs, or use recall during the review. * 🔴 (09:05) User required …