Skip to content

feat(tape): add durable execution journal - #2104

Merged
yyhhyyyyyy merged 27 commits into
devfrom
feat/tape-execution-journal
Aug 8, 2026
Merged

feat(tape): add durable execution journal#2104
yyhhyyyyyy merged 27 commits into
devfrom
feat/tape-execution-journal

Conversation

@yyhhyyyyyy

@yyhhyyyyyy yyhhyyyyyy commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a durable Execution Journal to the existing Tape store so DeepChat can reliably classify tool execution and Run state after process crashes.

Changes

  • Add immutable journal facts for Run start, dispatch, tool outcome, and Run terminal state.
  • Give each physical Run a UUID and each tool operation a structured identity.
  • Enforce strict idempotency: identical facts are idempotent; conflicting facts fail as corruption.
  • Commit dispatch facts after all local refusal gates and immediately before side effects.
  • Commit tool outcomes and Run terminal facts before transcript, context, status, hook, or UI projection.
  • Apply the same lifecycle contract to normal, deferred, MCP, and built-in Agent tool execution.
  • Classify startup recovery as not_dispatched, completed, indeterminate, or corruption.
  • Park indeterminate and corrupt executions without automatically retrying tools.
  • Keep journal facts out of Context Tape views, search, recall, and fork merge paths.
  • Preserve Context Tape compatibility while making message revision and derived tool ordering explicit.
  • Add bounded recovery scanning, fail-closed cleanup, and connection-reopen handling.

Failure Semantics

This does not claim exactly-once execution for arbitrary external systems. A crash after remote acceptance but before outcome persistence can still be indeterminate.

The journal instead guarantees that uncertainty has a durable, classifiable boundary and is never silently converted into success or automatic replay.

Summary by CodeRabbit

  • 新功能
    • 增强长任务执行记录与恢复能力,异常中断后可安全识别并暂停处理。
    • 工具调用支持更严格的执行顺序与结果确认,降低重复操作风险。
    • 浏览器、文件、记忆、技能及自动化任务等操作增加执行前校验。
  • 错误修复
    • 修复暂停任务、取消操作和终止状态处理不一致的问题。
    • 改进会话清理、消息恢复及工具结果展示的一致性。
  • 文档
    • 新增持久化执行记录、恢复流程与故障处理规范。

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The pull request adds a durable Execution Journal for DeepChat runs and side-effecting tools. It introduces strict event persistence, UUID run identities, recovery classification, fail-closed dispatch ordering, terminal-state validation, tape reconciliation, and mutation-boundary callbacks across tools and services.

Changes

Execution Journal and runtime lifecycle

Layer / File(s) Summary
Journal contract and persistence
src/main/tape/domain/*, src/main/tape/application/*, src/main/tape/infrastructure/sqlite/*, src/main/tape/ports/*
Defines immutable run, dispatch, outcome, and terminal facts. Adds canonical hashing, strict idempotency, corruption detection, recovery classification, SQLite persistence, reserved event isolation, and effective tool-order projection.
Run lifecycle and recovery
src/main/agent/deepchat/harness/*, src/main/agent/deepchat/runtime/deepChatLoopRunner.ts, src/main/agent/deepchat/runtime/process.ts, src/main/agent/deepchat/runtime/turnCoordinator.ts
Uses UUID run identities, commits terminal facts, handles committed projection failures, classifies incomplete runs at startup, parks affected interactions, and forces matching pending-message recovery.
Tool dispatch and settlement
src/main/agent/deepchat/runtime/dispatch.ts, src/main/agent/deepchat/runtime/deferredToolExecutor.ts, src/main/mcp/*, src/main/tool/*
Commits dispatches before side effects and outcomes before projections. Propagates journal failures through serial, parallel, MCP, deferred, browser, process, memory, skill, scheduler, delegation, filesystem, and settings operations.
Tape reconciliation and process ownership
src/main/session/data/*, src/main/agent/shared/process/backgroundExecSessionManager.ts
Adds revision-aware tape facts, compaction order corrections, forced recovery selection, completed-session retention, ownership validation, and host reconciliation.
Validation and crash coverage
test/main/**
Adds coverage for journal ordering, idempotency, corruption, recovery, terminal invariants, dispatch gating, tape projections, browser behavior, process ownership, and SQLite crash recovery.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: zerob13

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.31% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding a durable execution journal to Tape.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tape-execution-journal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/memory/services/rowMutations.ts (1)

296-301: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Thread beforeMutation through the manual edit provenance path.

updateMemoryContent runs applyManualContentEdit inside the memory transaction at src/main/memory/services/managementService.ts:634, but applyManualContentEdit calls resolveProvenance without that callback. Provenance hits can run rekeyProvenance before the caller’s new commit boundary runs. Add beforeMutation?: () => void to applyManualContentEdit, pass it into resolveProvenance, and update the manual-edit call sites via management.ts/ports.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/memory/services/rowMutations.ts` around lines 296 - 301, Thread the
optional beforeMutation callback through applyManualContentEdit and its
manual-edit ports/call sites, including the managementService
updateMemoryContent path. Pass it to resolveProvenance in the newKey branch
before resolveManualEditFold, preserving the callback through the management.ts
layers so provenance mutations wait for the caller’s commit boundary.
src/main/orchestration/liveDelegationService.ts (1)

719-742: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

interrupt can return success without invoking beforeMutation.

If no active turn exists and the latest persisted turn is already terminal, the method returns the inspected detail at line 741. beforeMutation never runs, so no dispatch fact is committed for a tool call that reports success. This matches the early-return gap in BackgroundExecSessionManager.kill. I consolidate the required change in a separate comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/orchestration/liveDelegationService.ts` around lines 719 - 742,
Update the inactive branch of interrupt to invoke beforeMutation even when no
active persisted turn requires finishing, including when the latest turn is
terminal or absent. Preserve the existing finishTurn path and return inspection
result, ensuring successful tool calls still commit the dispatch fact before
returning.
🧹 Nitpick comments (18)
src/main/agent/deepchat/runtime/deferredToolExecutor.ts (1)

556-576: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

Recording completed for a failed post-dispatch tool call reads as a false positive.

When the tool throws after dispatch, the code commits an error outcome and then a completed / tool_result terminal. The run terminal therefore states success while the outcome fact states failure. The error state is recoverable from the outcome fact, so this is not a data loss, but a distinct stopReason keeps the terminal fact self-describing.

♻️ Proposed adjustment
         if (runStartedCommitted && !terminalCommitAttempted) {
           commitRunTerminal(
             dispatchCommitted
-              ? { outcome: 'completed', stopReason: 'tool_result' }
+              ? { outcome: 'completed', stopReason: 'tool_error', errorMessage: errorText }
               : {
                   outcome: 'error',
                   stopReason: 'pre_dispatch_error',
                   errorMessage: errorText
                 }
           )
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/agent/deepchat/runtime/deferredToolExecutor.ts` around lines 556 -
576, Update the run-terminal commit in the error-handling path around
commitRunTerminal so post-dispatch tool failures no longer use outcome
'completed' with stopReason 'tool_result'. Preserve the existing pre-dispatch
error branch, and assign the appropriate distinct error stop reason for failures
after dispatch while retaining the committed error outcome.
test/main/session/runtimeIntegration.test.ts (1)

82-124: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Make the runtimeIntegration tape append mock idempotent.

DeepChatTapeEntriesTable.appendInternal dedupes idempotent appends using provenance_key, while this fixture appends every input and derives entry_id from tapeEntries.length + 1. If production retries a journal event with the same provenance key, this mock can create duplicate rows with non-matching entry IDs unless append also returns the existing provenance-key match for idempotent inputs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/session/runtimeIntegration.test.ts` around lines 82 - 124, Update
the runtimeIntegration tape append mock’s append implementation to handle
idempotent inputs by checking tapeEntries for an existing row with the same
provenance_key and returning that existing entry without appending. Preserve the
current append-and-entry_id generation behavior for non-idempotent inputs and
new provenance keys.
test/main/agent/deepchat/runtime/dispatch.test.ts (1)

573-578: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Wrap the ExecutionJournalError argument list to the 100-column limit.

Line 575 is about 107 columns. Oxfmt formats this file at 100 columns.

♻️ Proposed fix
       const commitDispatch = vi.fn((input) => {
         if (input.toolName === 'invalid') {
-          throw new ExecutionJournalError('normalizedArguments must be JSON serializable.', 'invalid_fact')
+          throw new ExecutionJournalError(
+            'normalizedArguments must be JSON serializable.',
+            'invalid_fact'
+          )
         }

As per coding guidelines: "Follow Oxfmt formatting: single quotes, no semicolons, and a 100-column width."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/agent/deepchat/runtime/dispatch.test.ts` around lines 573 - 578,
Reformat the ExecutionJournalError constructor call inside commitDispatch so its
arguments wrap within the 100-column limit, while preserving the existing
single-quote style and behavior.

Source: Coding guidelines

test/main/agent/deepchat/runtime/compactionService.test.ts (1)

1071-1075: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the contribution exists before checking the absent property.

find returns undefined when no summary_checkpoint contribution exists. expect(undefined).not.toHaveProperty('sourceEntryIds') then passes. The test would also pass if the checkpoint stops emitting the contribution.

♻️ Proposed fix
-    expect(
-      unrelatedCheckpoint.contributions.find(
-        (contribution) => contribution.reason === 'summary_checkpoint'
-      )
-    ).not.toHaveProperty('sourceEntryIds')
+    const unrelatedContribution = unrelatedCheckpoint.contributions.find(
+      (contribution) => contribution.reason === 'summary_checkpoint'
+    )
+    expect(unrelatedContribution).toBeDefined()
+    expect(unrelatedContribution).not.toHaveProperty('sourceEntryIds')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/agent/deepchat/runtime/compactionService.test.ts` around lines 1071
- 1075, Update the assertion for the summary_checkpoint contribution to first
require that the find result is defined, then assert that the contribution does
not have sourceEntryIds. Preserve the existing lookup on
unrelatedCheckpoint.contributions and ensure the test fails when the
contribution is missing.
test/main/tape/executionJournal.test.ts (1)

612-661: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Close the database in a finally block.

Line 660 calls db.close() only on the success path. If any assertion between Line 618 and Line 659 throws, the connection stays open. The three sibling itIfSqlite tests at Lines 663, 691, and 719 already use try/finally. Apply the same pattern here.

♻️ Proposed change
 itIfSqlite('queries only journal events through the dedicated SQLite index', () => {
   const db = new DatabaseCtor(':memory:')
-  const table = new DeepChatExecutionJournalStore(db)
-  table.createTable()
-  const service = new ExecutionJournalService(() => table)
-
-  table.appendEvent({ sessionId: 'session-1', name: 'context/example', data: { value: 1 } })
-  // ... remaining assertions ...
-  db.close()
+  try {
+    const table = new DeepChatExecutionJournalStore(db)
+    table.createTable()
+    const service = new ExecutionJournalService(() => table)
+
+    table.appendEvent({ sessionId: 'session-1', name: 'context/example', data: { value: 1 } })
+    // ... remaining assertions unchanged ...
+  } finally {
+    db.close()
+  }
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/tape/executionJournal.test.ts` around lines 612 - 661, Wrap the
database setup and assertions in the itIfSqlite test in a try/finally block,
moving db.close() into finally so it runs on both success and assertion failure.
Preserve the existing test behavior and use the db resource created at the start
of the test.
test/main/skill/skillExecutionService.test.ts (1)

267-279: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Set the fs mock state explicitly in the negative cwd test.

This test depends on fs.existsSync returning a falsy value. It does not set that value. The sibling test at Line 294 sets existsSync to true. If mock state leaks between tests, this test stops exercising the working-directory guard and can pass or fail for the wrong reason. Set the mock explicitly so the test is self-contained.

♻️ Proposed change
   it('does not commit dispatch when the resolved spawn cwd is unusable', async () => {
+    vi.mocked(fs.existsSync).mockReturnValue(false)
     const plan = {
       command: 'python',
       args: ['/skills/ocr/scripts/run.py'],
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/skill/skillExecutionService.test.ts` around lines 267 - 279, Update
the test “does not commit dispatch when the resolved spawn cwd is unusable” to
explicitly mock fs.existsSync as falsy before execution, ensuring it
independently exercises the working-directory guard regardless of state from
sibling tests.
test/main/tool/agentTools/agentMemoryTools.test.ts (1)

127-140: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the argument assertion out of the beforeMutation callback.

Lines 129-133 call expect inside beforeMutation. The handler under test treats a throw from beforeMutation as a commit failure and rejects the call. The second half of this test proves that behavior. If the argument assertion fails, the resulting error propagates as a rejected handler call, not as a clear assertion failure, and Line 140 never runs.

Capture the arguments and assert after the call.

💚 Proposed fix to keep assertion failures visible
-    const beforeMutation = vi.fn((args) => {
-      order.push('commit')
-      expect(args).toEqual({
-        content: 'repo uses pnpm',
-        kind: 'semantic',
-        importance: 0.7
-      })
-    })
+    const beforeMutation = vi.fn(() => {
+      order.push('commit')
+    })
 
     await handler.call(MEMORY_TOOL_NAMES.remember, { content: '  repo uses pnpm  ' }, 'conv-1', {
       beforeMutation
     })
 
+    expect(beforeMutation).toHaveBeenCalledWith({
+      content: 'repo uses pnpm',
+      kind: 'semantic',
+      importance: 0.7
+    })
     expect(order).toEqual(['commit', 'target'])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/tool/agentTools/agentMemoryTools.test.ts` around lines 127 - 140,
Update the beforeMutation callback in the remember handler test to capture its
args and record the commit order without asserting there. After handler.call
completes, assert the captured arguments alongside the existing order
expectation, preserving the separate test behavior for callback-thrown commit
failures.
src/main/tape/application/factPersistence.ts (1)

451-453: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

getBySession loads the whole session tape on each record replacement.

When a record replacement carries tool facts, buildTapeToolRevisionIndex reads every entry of the session. Long sessions accumulate thousands of entries, so each user message edit performs a full-session read and a full fingerprint pass.

Consider scoping the read to the message. The revision index is keyed by tool_call:{messageId}:{toolCallId}, so only entries belonging to record.id are ever consulted.

♻️ Sketch of a narrower read
   const toolInputs = options.revisionKind === 'record' ? buildTapeToolFactInputs(record) : []
   const toolRevisionIndex =
-    toolInputs.length > 0 ? buildTapeToolRevisionIndex(table.getBySession(record.sessionId)) : null
+    toolInputs.length > 0
+      ? buildTapeToolRevisionIndex(table.getToolEntriesByMessageId(record.sessionId, record.id))
+      : null

This requires a new store method that filters on json_extract(payload_json, '$.messageId').

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/tape/application/factPersistence.ts` around lines 451 - 453, Replace
the full-session lookup in the tool-fact branch around
buildTapeToolRevisionIndex with a message-scoped store query keyed by record.id.
Add and use a store method that filters entries via json_extract(payload_json,
'$.messageId'), preserving the existing toolInputs and revision-index behavior
while avoiding getBySession for record replacements.
src/main/tape/ports/storage.ts (1)

23-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move listEventsByNames out of TapeEntryStore.

The only production caller passes ExecutionJournalPersistenceStore, and the method is declared on both TapeEntryStore and ExecutionJournalPersistenceStore despite this store port’s note that strict journal persistence is intentionally absent from TapeEntryStore. Keep the method only on the journal port, or on a small local interface, so generic entry-store fakes do not need journal-only behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/tape/ports/storage.ts` at line 23, Remove listEventsByNames from the
TapeEntryStore interface and retain it on ExecutionJournalPersistenceStore or a
focused local interface used by its production caller. Update affected typing
and fakes so generic TapeEntryStore implementations no longer require this
journal-specific method.
src/main/tape/infrastructure/sqlite/tapeEntryStore.ts (1)

1080-1091: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Defer the tool-order projection until after search filtering.

projectedTapePayloadSql runs two nested NOT EXISTS scans for each tool_call / tool_result candidate, and those select-list expressions are not guarded by the ORDER BY ... LIMIT 20 in this query. On large matches, materialize the limited rows first in an inner query, then apply the payload_json project in an outer query.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/tape/infrastructure/sqlite/tapeEntryStore.ts` around lines 1080 -
1091, The query should defer the expensive projectedTapePayloadSql calculation
until after search filtering and the ORDER BY ... LIMIT 20 selection.
Restructure the relevant tape-entry query so an inner query materializes the
limited candidate rows and an outer query computes payload_json via
projectedTapePayloadSql, preserving all returned columns and ordering behavior.
src/main/desktop/browser/YoBrowserToolHandler.ts (1)

43-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the redundant call branches.

Both branches call the same presenter method. runId and beforeDispatch are optional parameters, so passing undefined is equivalent to omitting them. The condition runId || beforeDispatch adds no behavior.

♻️ Suggested simplification
           const beforeDispatch = beforeInvoke ? () => beforeInvoke({ url }) : undefined
           return JSON.stringify(
-            runId || beforeDispatch
-              ? await this.presenter.loadUrl(
-                  sessionId,
-                  url,
-                  undefined,
-                  undefined,
-                  'agent',
-                  runId,
-                  beforeDispatch
-                )
-              : await this.presenter.loadUrl(sessionId, url, undefined, undefined, 'agent')
+            await this.presenter.loadUrl(
+              sessionId,
+              url,
+              undefined,
+              undefined,
+              'agent',
+              runId,
+              beforeDispatch
+            )
           )

Apply the same change to the cdp_send branch at Lines 73-83.

Also applies to: 72-83

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/desktop/browser/YoBrowserToolHandler.ts` around lines 43 - 56,
Remove the conditional loadUrl call branches in the browser navigation handler,
including both the shown branch and the cdp_send branch. Call presenter.loadUrl
once in each case, passing the optional runId and beforeDispatch arguments
directly; preserve the existing sessionId, URL, and agent arguments and JSON
serialization.
src/main/agent/deepchat/runtime/dispatch.ts (2)

1882-1908: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse commitOutcome for the final staged result.

Lines 1882-1908 repeat the logic of commitOutcome at Lines 1621-1635: commit the outcome, record committedOutcome, then release projections. Two copies can diverge when the commit rules change.

♻️ Suggested consolidation
-    const stagedResult = commitDispatchedToolOutcome(
-      {
+    const outcome = commitOutcome({
+      kind: 'staged',
+      stagedResult: {
         toolCallId: completedToolCall.id,

Then build the remaining fields inside the same object and use outcome.stagedResult for the later block updates and the return value.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/agent/deepchat/runtime/dispatch.ts` around lines 1882 - 1908,
Replace the duplicated final staged-result commit block with the existing
commitOutcome helper used earlier in the dispatch flow. Pass the complete
outcome fields through that helper, then use its returned stagedResult for
committedOutcome assignment, projection release, subsequent block updates, and
the function return value.

243-249: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Move the outcome-committed invariant before toolResults.fitBatch.

The check runs after the await at Lines 230-242. fitBatch can offload content and perform I/O for results that the invariant then rejects. Running the check first avoids that work and fails faster on corruption.

♻️ Suggested reordering
   if (stagedResults.length > 0) {
+    for (const stagedResult of stagedResults) {
+      if (stagedResult.operation && !stagedResult.outcomeCommitted) {
+        throw new ExecutionJournalCorruptionError(
+          `Dispatched tool result was not committed for ${stagedResult.toolCallId}.`
+        )
+      }
+    }
     const fittedResults = await toolResults.fitBatch({
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/agent/deepchat/runtime/dispatch.ts` around lines 243 - 249, Move the
outcome-committed validation loop over stagedResults before the
toolResults.fitBatch call and its await in the dispatch flow. Keep the existing
ExecutionJournalCorruptionError condition and message unchanged, so invalid
staged results fail before fitBatch performs offloading or I/O.
src/main/desktop/browser/YoBrowserPresenter.ts (1)

161-178: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

UI events fire before the dispatch commit runs.

beforeDispatch runs inside navigateUntilDomReady at Line 169. ensureSessionBrowserState, updateOwner, ensurePreviewHost, and emitOpenRequested run earlier. If the journal commit throws, the session browser state and the preview host already exist and the renderer already received browser.open.requested for a navigation that never starts. The same pattern applies to sendCdpCommand at Lines 476-495.

The target action still stays behind the commit, so the journal contract holds. If you want the observable state to match the journal, invoke beforeDispatch before emitOpenRequested.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/desktop/browser/YoBrowserPresenter.ts` around lines 161 - 178, Move
the beforeDispatch invocation in the navigation flow so it completes before
emitOpenRequested and other observable setup in the surrounding method, while
preserving the target action’s existing post-commit execution. Apply the same
ordering correction to sendCdpCommand: run its beforeDispatch step before
emitting UI events or creating observable state, without moving the actual
command dispatch ahead of the journal commit.
src/main/agent/shared/process/backgroundExecSessionManager.ts (1)

961-966: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse of the reconciliation constant changes the cleanup meaning.

COMPLETED_SESSION_RECONCILIATION_MS now controls two unrelated policies: the proxy reconciliation period and the local auto-removal age for finished sessions. A later tuning of the reconciliation period silently changes how long finished sessions stay readable. Consider a separate named constant for the local retention age.

♻️ Proposed separate constant
+const COMPLETED_SESSION_RETENTION_MS = 5 * 60 * 1000
         } else if (
           session.status !== 'running' &&
-          now - session.lastAccessedAt > COMPLETED_SESSION_RECONCILIATION_MS
+          now - session.lastAccessedAt > COMPLETED_SESSION_RETENTION_MS
         ) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/agent/shared/process/backgroundExecSessionManager.ts` around lines
961 - 966, Introduce a separate named constant for local retention of finished
sessions and use it in the expired-session condition within the background
session cleanup flow, replacing COMPLETED_SESSION_RECONCILIATION_MS while
leaving the proxy reconciliation policy unchanged.
src/main/mcp/toolManager.ts (1)

823-823: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

State the commit flag directly.

access?.commitDispatch !== undefined re-derives a condition that is already known at this point. Assign true and keep the flag meaning "a dispatch fact was committed".

♻️ Proposed change
-      try {
-        access?.commitDispatch?.({
+      const commitDispatch = access?.commitDispatch
+      try {
+        commitDispatch?.({
           toolName: finalName,
           toolSource: 'mcp',
           normalizedArguments: preparedArgs.args,
           target: {
             serverName: toolServerName,
             originalName,
             ...(ownerPluginId ? { ownerPluginId } : {})
           }
         })
-        dispatchCommitted = access?.commitDispatch !== undefined
+        dispatchCommitted = commitDispatch !== undefined
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/mcp/toolManager.ts` at line 823, Update the assignment to
dispatchCommitted in the surrounding dispatch handling logic to set it directly
to true, preserving its meaning as indicating that a dispatch fact was
committed.
src/main/skill/skillTools.ts (1)

98-100: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Pass options unconditionally to manageDraftSkill.

handleSkillManage() initializes options as {}, and SkillService.manageDraftSkill() also defaults the third parameter to {}, so the default-no-op branch and the explicit-options branch both call the same default. Remove the conditional forwarding unless a test requires the two-argument call form.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/skill/skillTools.ts` around lines 98 - 100, Update
handleSkillManage() to pass the initialized options object unconditionally as
the third argument to SkillService.manageDraftSkill(). Remove the beforeMutation
conditional and preserve the existing manageDraftSkill invocation behavior.
src/main/memory/services/writeCoordinator.ts (1)

1146-1157: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the duplicated tombstone-check block into a helper.

The tombstone check (build the scoped provenance key, then call hasTombstoneForClaim) repeats near-identically at Line 1146 (coordinateWriteAttempt), Line 1675 (tryExplicitRelearn, negated form), and Line 1749 (directAddMemory). Extract a private helper, for example isClaimTombstoned(agentId, kind, content, scope), and call it from all three sites. This keeps the tombstone check consistent if the identity fields change later.

♻️ Proposed helper extraction
+  private isClaimTombstoned(
+    agentId: string,
+    kind: NormalizedMemoryCandidate['kind'],
+    content: string,
+    scope: MemoryScope
+  ): boolean {
+    return this.ports.repository.hasTombstoneForClaim({
+      agentId,
+      kind,
+      content,
+      provenanceKey: buildScopedMemoryProvenanceKey(agentId, kind, content, scope),
+      scope
+    })
+  }

Then replace each inline check, for example at Line 1146:

-    if (
-      !duplicate &&
-      this.ports.repository.hasTombstoneForClaim({
-        agentId,
-        kind: normalized.kind,
-        content,
-        provenanceKey: buildScopedMemoryProvenanceKey(agentId, normalized.kind, content, scope),
-        scope
-      })
-    ) {
+    if (!duplicate && this.isClaimTombstoned(agentId, normalized.kind, content, scope)) {
       return { action: 'noop', reason: 'forgotten' }
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/memory/services/writeCoordinator.ts` around lines 1146 - 1157,
Extract the repeated tombstone lookup into a private isClaimTombstoned helper
that builds the scoped provenance key and calls repository.hasTombstoneForClaim.
Replace the inline checks in coordinateWriteAttempt, tryExplicitRelearn, and
directAddMemory with this helper, preserving each caller’s existing negation and
outcome behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/architecture/tape-system.md`:
- Line 113: Update the execution/tool_outcome row in the architecture
documentation to remove cancel from the listed outcome categories, leaving only
success/error so it matches the isError-based domain model and T1/T2 abort
contract.

In `@src/main/agent/deepchat/runtime/dispatch.ts`:
- Around line 1636-1658: The failPostDispatchPermission recovery path must
reconcile the committed stagedResult before rethrowing invalid_fact. Update the
surrounding settleToolBatch/deferred-interaction handling to project and insert
committedOutcome into the assistant content/transcript when
execution.journalFailure.outcomeCommitted is set, using the committed staged
result and avoiding duplicate insertion.

In `@src/main/agent/shared/process/backgroundExecSessionManager.ts`:
- Around line 1025-1047: The list method’s host-unavailable fallback omits
completed sessions, causing finished records to disappear. Update the fallback
projection in list to include matching entries from completedSessions alongside
active session metadata, while preserving host responses and reconciliation
behavior when hostListSucceeded is true.

In `@src/main/mcp/toolManager.ts`:
- Around line 907-909: Update the abort-handling branch around isAbortError and
dispatchCommitted so post-T1 aborted calls are classified as
indeterminate/parked rather than rethrown. Ensure dispatchCommitFailed
suppresses committed aborts consistently with McpService.callTool, while
preserving rethrow behavior for pre-dispatch failures.

In `@src/main/tape/application/executionJournalService.ts`:
- Around line 163-167: Bound the recovery scan in classifyRecoveryCandidates by
passing an explicit row limit or recent session/time-window constraint to
listEventsByNames, rather than retrieving every matching execution-journal row.
Preserve classification through classifyExecutionJournalRows while ensuring
recovery processing remains limited to the intended recent scope.

In `@src/main/tape/domain/canonicalJson.ts`:
- Around line 3-25: Update normalizeForStableJson and its callers to eliminate
the unused preservePrototypeKeys branch, or make stableJsonStringify
consistently pass and honor it when prototype-preserving behavior is required.
Ensure the chosen behavior is explicit for the accumulator object, including how
parsed keys such as __proto__ are handled, and remove the parameter threading if
the legacy {} behavior remains.

In `@src/main/tape/infrastructure/sqlite/tapeEntryStore.ts`:
- Around line 61-63: Bound recovery journal scans by applying a maximum row or
run-count limit at the recovery reader boundary, preferably in
listEventsByNames() or its call from classifyRecoveryCandidates(), before rows
reach classifyExecutionJournalRows(). Preserve classification behavior for rows
within the bound and prevent unbounded streaming when execution names span
multiple sessions.

In `@src/main/tool/agentTools/agentFileSystemHandler.ts`:
- Around line 845-858: Update writeFile and the corresponding mutation methods
to avoid reusing a validated pathname after beforeMutation. Open the validated
parent directory via a descriptor, perform a no-follow file operation relative
to that descriptor, and ensure the write cannot follow a replaced file or parent
symlink outside the allowed directory.

In `@test/main/agent/deepchat/runtime/process.test.ts`:
- Line 1859: Rename the test case describing the provider AbortError to state
that the abort signal is inactive, not active. Update only the `it` description
in the test around `records a provider AbortError`; preserve its existing
assertions and behavior.

In `@test/main/agent/shared/process/backgroundExecSessionManager.test.ts`:
- Around line 300-313: Update the test covering rejected local session preflight
so its third kill call targets the same missing session, or remove it from this
case. If retaining a successful kill assertion, move it to a separate test using
a running session and assert the intended commit behavior there.

In `@test/main/session/data/tapeFork.test.ts`:
- Around line 401-427: In the test around service.mergeFork, add a positive
precondition after appendExecutionJournalEvent asserting that the
execution/run_started entry exists for fork.forkSessionId via the existing table
query. Keep the subsequent parent-session assertion unchanged so the test
verifies both fork journal creation and non-copying during merge.

---

Outside diff comments:
In `@src/main/memory/services/rowMutations.ts`:
- Around line 296-301: Thread the optional beforeMutation callback through
applyManualContentEdit and its manual-edit ports/call sites, including the
managementService updateMemoryContent path. Pass it to resolveProvenance in the
newKey branch before resolveManualEditFold, preserving the callback through the
management.ts layers so provenance mutations wait for the caller’s commit
boundary.

In `@src/main/orchestration/liveDelegationService.ts`:
- Around line 719-742: Update the inactive branch of interrupt to invoke
beforeMutation even when no active persisted turn requires finishing, including
when the latest turn is terminal or absent. Preserve the existing finishTurn
path and return inspection result, ensuring successful tool calls still commit
the dispatch fact before returning.

---

Nitpick comments:
In `@src/main/agent/deepchat/runtime/deferredToolExecutor.ts`:
- Around line 556-576: Update the run-terminal commit in the error-handling path
around commitRunTerminal so post-dispatch tool failures no longer use outcome
'completed' with stopReason 'tool_result'. Preserve the existing pre-dispatch
error branch, and assign the appropriate distinct error stop reason for failures
after dispatch while retaining the committed error outcome.

In `@src/main/agent/deepchat/runtime/dispatch.ts`:
- Around line 1882-1908: Replace the duplicated final staged-result commit block
with the existing commitOutcome helper used earlier in the dispatch flow. Pass
the complete outcome fields through that helper, then use its returned
stagedResult for committedOutcome assignment, projection release, subsequent
block updates, and the function return value.
- Around line 243-249: Move the outcome-committed validation loop over
stagedResults before the toolResults.fitBatch call and its await in the dispatch
flow. Keep the existing ExecutionJournalCorruptionError condition and message
unchanged, so invalid staged results fail before fitBatch performs offloading or
I/O.

In `@src/main/agent/shared/process/backgroundExecSessionManager.ts`:
- Around line 961-966: Introduce a separate named constant for local retention
of finished sessions and use it in the expired-session condition within the
background session cleanup flow, replacing COMPLETED_SESSION_RECONCILIATION_MS
while leaving the proxy reconciliation policy unchanged.

In `@src/main/desktop/browser/YoBrowserPresenter.ts`:
- Around line 161-178: Move the beforeDispatch invocation in the navigation flow
so it completes before emitOpenRequested and other observable setup in the
surrounding method, while preserving the target action’s existing post-commit
execution. Apply the same ordering correction to sendCdpCommand: run its
beforeDispatch step before emitting UI events or creating observable state,
without moving the actual command dispatch ahead of the journal commit.

In `@src/main/desktop/browser/YoBrowserToolHandler.ts`:
- Around line 43-56: Remove the conditional loadUrl call branches in the browser
navigation handler, including both the shown branch and the cdp_send branch.
Call presenter.loadUrl once in each case, passing the optional runId and
beforeDispatch arguments directly; preserve the existing sessionId, URL, and
agent arguments and JSON serialization.

In `@src/main/mcp/toolManager.ts`:
- Line 823: Update the assignment to dispatchCommitted in the surrounding
dispatch handling logic to set it directly to true, preserving its meaning as
indicating that a dispatch fact was committed.

In `@src/main/memory/services/writeCoordinator.ts`:
- Around line 1146-1157: Extract the repeated tombstone lookup into a private
isClaimTombstoned helper that builds the scoped provenance key and calls
repository.hasTombstoneForClaim. Replace the inline checks in
coordinateWriteAttempt, tryExplicitRelearn, and directAddMemory with this
helper, preserving each caller’s existing negation and outcome behavior.

In `@src/main/skill/skillTools.ts`:
- Around line 98-100: Update handleSkillManage() to pass the initialized options
object unconditionally as the third argument to SkillService.manageDraftSkill().
Remove the beforeMutation conditional and preserve the existing manageDraftSkill
invocation behavior.

In `@src/main/tape/application/factPersistence.ts`:
- Around line 451-453: Replace the full-session lookup in the tool-fact branch
around buildTapeToolRevisionIndex with a message-scoped store query keyed by
record.id. Add and use a store method that filters entries via
json_extract(payload_json, '$.messageId'), preserving the existing toolInputs
and revision-index behavior while avoiding getBySession for record replacements.

In `@src/main/tape/infrastructure/sqlite/tapeEntryStore.ts`:
- Around line 1080-1091: The query should defer the expensive
projectedTapePayloadSql calculation until after search filtering and the ORDER
BY ... LIMIT 20 selection. Restructure the relevant tape-entry query so an inner
query materializes the limited candidate rows and an outer query computes
payload_json via projectedTapePayloadSql, preserving all returned columns and
ordering behavior.

In `@src/main/tape/ports/storage.ts`:
- Line 23: Remove listEventsByNames from the TapeEntryStore interface and retain
it on ExecutionJournalPersistenceStore or a focused local interface used by its
production caller. Update affected typing and fakes so generic TapeEntryStore
implementations no longer require this journal-specific method.

In `@test/main/agent/deepchat/runtime/compactionService.test.ts`:
- Around line 1071-1075: Update the assertion for the summary_checkpoint
contribution to first require that the find result is defined, then assert that
the contribution does not have sourceEntryIds. Preserve the existing lookup on
unrelatedCheckpoint.contributions and ensure the test fails when the
contribution is missing.

In `@test/main/agent/deepchat/runtime/dispatch.test.ts`:
- Around line 573-578: Reformat the ExecutionJournalError constructor call
inside commitDispatch so its arguments wrap within the 100-column limit, while
preserving the existing single-quote style and behavior.

In `@test/main/session/runtimeIntegration.test.ts`:
- Around line 82-124: Update the runtimeIntegration tape append mock’s append
implementation to handle idempotent inputs by checking tapeEntries for an
existing row with the same provenance_key and returning that existing entry
without appending. Preserve the current append-and-entry_id generation behavior
for non-idempotent inputs and new provenance keys.

In `@test/main/skill/skillExecutionService.test.ts`:
- Around line 267-279: Update the test “does not commit dispatch when the
resolved spawn cwd is unusable” to explicitly mock fs.existsSync as falsy before
execution, ensuring it independently exercises the working-directory guard
regardless of state from sibling tests.

In `@test/main/tape/executionJournal.test.ts`:
- Around line 612-661: Wrap the database setup and assertions in the itIfSqlite
test in a try/finally block, moving db.close() into finally so it runs on both
success and assertion failure. Preserve the existing test behavior and use the
db resource created at the start of the test.

In `@test/main/tool/agentTools/agentMemoryTools.test.ts`:
- Around line 127-140: Update the beforeMutation callback in the remember
handler test to capture its args and record the commit order without asserting
there. After handler.call completes, assert the captured arguments alongside the
existing order expectation, preserving the separate test behavior for
callback-thrown commit failures.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9c5feb4f-c8ed-4a38-b00a-a8792de45001

📥 Commits

Reviewing files that changed from the base of the PR and between 7199be4 and eea1924.

📒 Files selected for processing (109)
  • docs/architecture/agent-system.md
  • docs/architecture/durable-execution-journal/plan.md
  • docs/architecture/durable-execution-journal/spec.md
  • docs/architecture/durable-execution-journal/tasks.md
  • docs/architecture/session-management.md
  • docs/architecture/tape-system.md
  • src/main/agent/deepchat/harness/createDeepChatAgentHarness.ts
  • src/main/agent/deepchat/runtime/contextContributions.ts
  • src/main/agent/deepchat/runtime/deepChatLoopRunner.ts
  • src/main/agent/deepchat/runtime/deferredToolExecutor.ts
  • src/main/agent/deepchat/runtime/dispatch.ts
  • src/main/agent/deepchat/runtime/interactionCoordinator.ts
  • src/main/agent/deepchat/runtime/interactionParkingRegistry.ts
  • src/main/agent/deepchat/runtime/process.ts
  • src/main/agent/deepchat/runtime/runTerminalProjectionError.ts
  • src/main/agent/deepchat/runtime/sessionLifecycleCoordinator.ts
  • src/main/agent/deepchat/runtime/toolAdapters.ts
  • src/main/agent/deepchat/runtime/turnCoordinator.ts
  • src/main/agent/deepchat/runtime/types.ts
  • src/main/agent/shared/process/backgroundExecSessionManager.ts
  • src/main/app/composition.ts
  • src/main/desktop/browser/BrowserTab.ts
  • src/main/desktop/browser/YoBrowserPresenter.ts
  • src/main/desktop/browser/YoBrowserToolHandler.ts
  • src/main/mcp/index.ts
  • src/main/mcp/toolManager.ts
  • src/main/memory/data/tables/agentMemory.ts
  • src/main/memory/index.ts
  • src/main/memory/ports.ts
  • src/main/memory/services/managementService.ts
  • src/main/memory/services/rowMutations.ts
  • src/main/memory/services/writeCoordinator.ts
  • src/main/orchestration/liveDelegationRepository.ts
  • src/main/orchestration/liveDelegationService.ts
  • src/main/scheduler/index.ts
  • src/main/session/data/database.ts
  • src/main/session/data/tables/deepchatMessages.ts
  • src/main/session/data/transcript.ts
  • src/main/skill/index.ts
  • src/main/skill/skillExecutionService.ts
  • src/main/skill/skillTools.ts
  • src/main/tape/application/executionJournalService.ts
  • src/main/tape/application/factPersistence.ts
  • src/main/tape/application/factService.ts
  • src/main/tape/application/forkService.ts
  • src/main/tape/application/reconcilerService.ts
  • src/main/tape/application/sessionTape.ts
  • src/main/tape/domain/canonicalJson.ts
  • src/main/tape/domain/effectiveView.ts
  • src/main/tape/domain/executionJournal.ts
  • src/main/tape/domain/facts.ts
  • src/main/tape/domain/viewManifest.ts
  • src/main/tape/infrastructure/sqlite/tapeEntryStore.ts
  • src/main/tape/infrastructure/sqlite/tapeSearchProjectionStore.ts
  • src/main/tape/ports/application.ts
  • src/main/tape/ports/capabilities.ts
  • src/main/tape/ports/storage.ts
  • src/main/tool/agentTools/agentBashHandler.ts
  • src/main/tool/agentTools/agentFileSystemHandler.ts
  • src/main/tool/agentTools/agentImageGenerationTool.ts
  • src/main/tool/agentTools/agentMemoryTools.ts
  • src/main/tool/agentTools/agentToolManager.ts
  • src/main/tool/agentTools/chatSettingsTools.ts
  • src/main/tool/agentTools/cronJobTool.ts
  • src/main/tool/agentTools/liveDelegationTool.ts
  • src/main/tool/index.ts
  • src/main/tool/runtimePorts.ts
  • src/shared/types/core/mcp.ts
  • src/shared/types/mcp.ts
  • src/shared/types/skill.ts
  • src/shared/types/tool.d.ts
  • test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts
  • test/main/agent/deepchat/runtime/compactionService.test.ts
  • test/main/agent/deepchat/runtime/deferredToolExecutor.test.ts
  • test/main/agent/deepchat/runtime/dispatch.test.ts
  • test/main/agent/deepchat/runtime/process.test.ts
  • test/main/agent/deepchat/runtime/sessionLifecycleCoordinator.test.ts
  • test/main/agent/deepchat/runtime/toolAdapters.test.ts
  • test/main/agent/shared/process/backgroundExecSessionManager.test.ts
  • test/main/desktop/browser/BrowserTab.test.ts
  • test/main/desktop/browser/YoBrowserPresenter.test.ts
  • test/main/desktop/browser/YoBrowserToolHandler.test.ts
  • test/main/mcp/mcpService.test.ts
  • test/main/mcp/toolManager.test.ts
  • test/main/memory/support/memoryFakes.ts
  • test/main/memory/writeCoordinator.test.ts
  • test/main/orchestration/liveDelegationRepository.test.ts
  • test/main/orchestration/liveDelegationService.test.ts
  • test/main/session/data/settings.test.ts
  • test/main/session/data/tapeFacts.test.ts
  • test/main/session/data/tapeFork.test.ts
  • test/main/session/data/tapeRecall.test.ts
  • test/main/session/data/tapeReconciler.test.ts
  • test/main/session/data/tapeTestHarness.ts
  • test/main/session/data/tapeViewManifest.test.ts
  • test/main/session/data/transcript.test.ts
  • test/main/session/runtimeIntegration.test.ts
  • test/main/skill/skillExecutionService.test.ts
  • test/main/skill/skillService.test.ts
  • test/main/tape/canonicalJson.test.ts
  • test/main/tape/executionJournal.test.ts
  • test/main/tape/executionJournalCrash.test.ts
  • test/main/tape/fixtures/executionJournalCrashWorker.test.ts
  • test/main/tool/agentTools/agentBashHandler.test.ts
  • test/main/tool/agentTools/agentImageGenerationTool.test.ts
  • test/main/tool/agentTools/agentMemoryTools.test.ts
  • test/main/tool/agentTools/agentToolManagerRead.test.ts
  • test/main/tool/agentTools/chatSettingsTools.test.ts
  • test/main/tool/toolService.test.ts

Comment thread docs/architecture/tape-system.md Outdated
Comment thread src/main/agent/deepchat/runtime/dispatch.ts
Comment thread src/main/agent/shared/process/backgroundExecSessionManager.ts
Comment thread src/main/mcp/toolManager.ts
Comment thread src/main/tape/application/executionJournalService.ts
Comment thread src/main/tape/infrastructure/sqlite/tapeEntryStore.ts
Comment thread src/main/tool/agentTools/agentFileSystemHandler.ts
Comment thread test/main/agent/deepchat/runtime/process.test.ts Outdated
Comment thread test/main/agent/shared/process/backgroundExecSessionManager.test.ts
Comment thread test/main/session/data/tapeFork.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/agent/shared/process/backgroundExecSessionManager.ts (1)

1186-1196: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Update completed-session metadata after a successful clear.

clear resets the host output length and offload state. completedSessions keeps the old values. If a later list call cannot reach the host, it reports cleared output as still available.

Proposed fix
     try {
       await this.request('clear', [conversationId, sessionId])
+      if (completed) {
+        this.completedSessions.set(sessionId, {
+          ...completed,
+          outputLength: 0,
+          offloaded: false,
+          lastAccessedAt: Date.now()
+        })
+      }
     } catch (error) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/agent/shared/process/backgroundExecSessionManager.ts` around lines
1186 - 1196, Update the successful clear path in the method containing
request('clear') to refresh the matching completedSessions metadata after the
request completes. Reset the completed session’s host output length and offload
state to the values representing a cleared session, while preserving the
existing missing-utility-session cleanup and error propagation behavior.
🧹 Nitpick comments (2)
test/main/desktop/browser/YoBrowserPresenter.test.ts (1)

459-460: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Strengthen the CDP suppression assertion.

Line 460 only excludes the exact argument pair ('Page.reload', {}). If the implementation dispatches Page.reload with undefined params, the assertion still passes. Assert on the method name only, or reuse cdpCommandObserver as the other CDP test does.

♻️ Proposed change
     expect(sendToAllWindowsMock).not.toHaveBeenCalled()
-    expect(webContents?.debugger.sendCommand).not.toHaveBeenCalledWith('Page.reload', {})
+    expect(webContents?.debugger.sendCommand).not.toHaveBeenCalledWith(
+      'Page.reload',
+      expect.anything()
+    )
+    expect(webContents?.debugger.sendCommand).not.toHaveBeenCalledWith('Page.reload')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/desktop/browser/YoBrowserPresenter.test.ts` around lines 459 - 460,
Strengthen the CDP suppression assertion in the relevant YoBrowserPresenter test
by verifying that debugger.sendCommand was never called with the method name
Page.reload, regardless of its parameters. Replace the exact argument-pair check
or reuse cdpCommandObserver consistently with the other CDP test.
test/main/evals/nativeAgent/harness.ts (1)

256-266: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Guard the argument parse in the scripted callTool.

Line 261 parses request.function.arguments without a guard. If a scenario produces a truncated or empty argument string, JSON.parse throws inside callTool. The harness then reports a tool error instead of the scripted behavior, and the failure reason is hard to read. The production ToolService uses a tolerant parser for the same input.

♻️ Proposed change
+const parseToolArguments = (raw: string): Record<string, unknown> => {
+  try {
+    const parsed = JSON.parse(raw) as unknown
+    return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
+      ? (parsed as Record<string, unknown>)
+      : {}
+  } catch {
+    return {}
+  }
+}
       options?.commitDispatch?.({
         toolName: request.function.name,
         toolSource: 'agent',
-        normalizedArguments: JSON.parse(request.function.arguments) as Record<string, unknown>,
+        normalizedArguments: parseToolArguments(request.function.arguments),
         target: {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/evals/nativeAgent/harness.ts` around lines 256 - 266, Update the
scripted callTool implementation to parse request.function.arguments through the
same tolerant parsing behavior used by production ToolService, so empty or
truncated JSON does not throw and replace the scripted tool behavior. Preserve
the existing normalizedArguments dispatch contract and fallback behavior for
invalid arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/desktop/browser/YoBrowserPresenter.ts`:
- Around line 155-183: Mark the session as dispatched at the start of the inner
project function in the projectDispatch flow, before emitWindowCreated can
throw. Preserve createdEventPublished as the guard, and ensure emitWindowUpdated
can use the dispatched state to lazily emit the creation event for sessions
whose initial projection failed.

In `@test/main/desktop/browser/YoBrowserPresenter.test.ts`:
- Around line 379-385: Reset sendToAllWindowsMock between tests so the custom
implementation installed in the affected tests does not leak into later tests.
Update the relevant beforeEach setup to use mockReset() for this mock, or
explicitly restore its default implementation after each test that calls
mockImplementation; preserve the existing event-order assertions.

---

Outside diff comments:
In `@src/main/agent/shared/process/backgroundExecSessionManager.ts`:
- Around line 1186-1196: Update the successful clear path in the method
containing request('clear') to refresh the matching completedSessions metadata
after the request completes. Reset the completed session’s host output length
and offload state to the values representing a cleared session, while preserving
the existing missing-utility-session cleanup and error propagation behavior.

---

Nitpick comments:
In `@test/main/desktop/browser/YoBrowserPresenter.test.ts`:
- Around line 459-460: Strengthen the CDP suppression assertion in the relevant
YoBrowserPresenter test by verifying that debugger.sendCommand was never called
with the method name Page.reload, regardless of its parameters. Replace the
exact argument-pair check or reuse cdpCommandObserver consistently with the
other CDP test.

In `@test/main/evals/nativeAgent/harness.ts`:
- Around line 256-266: Update the scripted callTool implementation to parse
request.function.arguments through the same tolerant parsing behavior used by
production ToolService, so empty or truncated JSON does not throw and replace
the scripted tool behavior. Preserve the existing normalizedArguments dispatch
contract and fallback behavior for invalid arguments.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 248f2d94-0ab1-42da-bb47-69ede285ddcc

📥 Commits

Reviewing files that changed from the base of the PR and between eea1924 and 4aaf7a3.

📒 Files selected for processing (19)
  • docs/architecture/tape-system.md
  • src/main/agent/deepchat/runtime/dispatch.ts
  • src/main/agent/shared/process/backgroundExecSessionManager.ts
  • src/main/desktop/browser/BrowserTab.ts
  • src/main/desktop/browser/YoBrowserPresenter.ts
  • src/main/tape/domain/canonicalJson.ts
  • src/main/tape/ports/storage.ts
  • test/main/agent/deepchat/runtime/compactionService.test.ts
  • test/main/agent/deepchat/runtime/dispatch.test.ts
  • test/main/agent/deepchat/runtime/process.test.ts
  • test/main/agent/shared/process/backgroundExecSessionManager.test.ts
  • test/main/desktop/browser/YoBrowserPresenter.test.ts
  • test/main/evals/nativeAgent/harness.ts
  • test/main/evals/nativeAgent/nativeAgentBehavior.eval.test.ts
  • test/main/session/data/tapeFork.test.ts
  • test/main/session/runtimeIntegration.test.ts
  • test/main/skill/skillExecutionService.test.ts
  • test/main/tape/executionJournal.test.ts
  • test/main/tool/agentTools/agentMemoryTools.test.ts
💤 Files with no reviewable changes (1)
  • src/main/tape/ports/storage.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • test/main/session/data/tapeFork.test.ts
  • test/main/tool/agentTools/agentMemoryTools.test.ts
  • src/main/desktop/browser/BrowserTab.ts
  • src/main/tape/domain/canonicalJson.ts
  • test/main/skill/skillExecutionService.test.ts
  • test/main/session/runtimeIntegration.test.ts
  • test/main/agent/deepchat/runtime/compactionService.test.ts
  • test/main/agent/shared/process/backgroundExecSessionManager.test.ts
  • docs/architecture/tape-system.md
  • test/main/tape/executionJournal.test.ts
  • test/main/agent/deepchat/runtime/process.test.ts
  • src/main/agent/deepchat/runtime/dispatch.ts

Comment thread src/main/desktop/browser/YoBrowserPresenter.ts
Comment thread test/main/desktop/browser/YoBrowserPresenter.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/main/agent/shared/process/backgroundExecSessionManager.ts (3)

1410-1411: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve completed metadata across an unexpected utility-process exit.

handleHostExit clears completedSessions after moving active sessions to crashedSessions. Sessions that completed before the exit then disappear from list while the host is unavailable. The local completed-session fallback cannot help after this clear.

Keep completed records across an unexpected exit. Let successful reconciliation or explicit cleanup remove them. shutdown already clears them for intentional shutdown.

Proposed fix
     this.hostReady = null
     this.activeSessions.clear()
-    this.completedSessions.clear()
     this.stopCompletedSessionReconciliation()
     this.rejectPendingRequests(error)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/agent/shared/process/backgroundExecSessionManager.ts` around lines
1410 - 1411, Update handleHostExit to stop clearing completedSessions when
moving active sessions to crashedSessions, preserving completed records while
the utility process is unavailable. Keep their removal under successful
reconciliation or explicit cleanup, and leave shutdown’s existing
completedSessions.clear() behavior unchanged.

1169-1177: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return before dispatching kill for completed sessions.

completed is terminal metadata, but this path still invokes beforeMutation and sends a kill request. This leaves done, error, and killed sessions on the termination path. Return when completed is present, before the callback. Use remove for cleanup. Otherwise, the callback can persist a dispatch for an operation that cannot terminate the session.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/agent/shared/process/backgroundExecSessionManager.ts` around lines
1169 - 1177, Update the session termination flow around getCompletedSession to
return immediately when completed metadata exists, before invoking
beforeMutation or dispatching the kill request. Use the completed-session
cleanup remove operation rather than delete, while preserving the existing
crashed-session early return and active-session kill behavior.

1051-1057: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Protect new completions from stale reconciliation.

At Lines [1051]-[1057], the loop iterates the live completedSessions map after the host-list request resolves. A concurrent poll, log, waitForCompletionOrYield, or getCompletionResult call can add a completed session after the host snapshot was taken. This loop can then delete the new terminal metadata.

Snapshot completedSessions before the await. Delete an entry only when its current value is the same object that was present in the snapshot.

Proposed fix
   async list(conversationId: string): Promise<SessionMeta[]> {
+    const completedAtListStart = new Map(this.completedSessions)
     const active = Array.from(this.activeSessions.values())
       .filter((session) => session.conversationId === conversationId)
       .map((session) => this.toActiveSessionMeta(session))
@@
-      for (const [sessionId, session] of this.completedSessions) {
+      for (const [sessionId, session] of completedAtListStart) {
         if (session.conversationId === conversationId && !hostSessionIds.has(sessionId)) {
-          this.completedSessions.delete(sessionId)
+          if (this.completedSessions.get(sessionId) === session) {
+            this.completedSessions.delete(sessionId)
+          }
         }
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/agent/shared/process/backgroundExecSessionManager.ts` around lines
1051 - 1057, Update the host reconciliation flow around the host-list await and
the completedSessions cleanup loop to snapshot completedSessions before awaiting
the host request. Iterate that snapshot, and delete an entry only if it still
exists with the same session object as the snapshot value, preserving concurrent
completions added or replaced after the snapshot.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/main/evals/nativeAgent/harness.ts`:
- Around line 240-253: Update parseToolArguments to validate both direct
JSON.parse and jsonrepair fallback results, returning {} unless the parsed value
is a non-null plain object; only return validated object values so
normalizedArguments remains compatible with commitDispatch.

---

Outside diff comments:
In `@src/main/agent/shared/process/backgroundExecSessionManager.ts`:
- Around line 1410-1411: Update handleHostExit to stop clearing
completedSessions when moving active sessions to crashedSessions, preserving
completed records while the utility process is unavailable. Keep their removal
under successful reconciliation or explicit cleanup, and leave shutdown’s
existing completedSessions.clear() behavior unchanged.
- Around line 1169-1177: Update the session termination flow around
getCompletedSession to return immediately when completed metadata exists, before
invoking beforeMutation or dispatching the kill request. Use the
completed-session cleanup remove operation rather than delete, while preserving
the existing crashed-session early return and active-session kill behavior.
- Around line 1051-1057: Update the host reconciliation flow around the
host-list await and the completedSessions cleanup loop to snapshot
completedSessions before awaiting the host request. Iterate that snapshot, and
delete an entry only if it still exists with the same session object as the
snapshot value, preserving concurrent completions added or replaced after the
snapshot.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6519ee02-2afe-4388-9e88-959461cb4f53

📥 Commits

Reviewing files that changed from the base of the PR and between 4aaf7a3 and f74e59e.

📒 Files selected for processing (5)
  • src/main/agent/shared/process/backgroundExecSessionManager.ts
  • src/main/desktop/browser/YoBrowserPresenter.ts
  • test/main/agent/shared/process/backgroundExecSessionManager.test.ts
  • test/main/desktop/browser/YoBrowserPresenter.test.ts
  • test/main/evals/nativeAgent/harness.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/main/agent/shared/process/backgroundExecSessionManager.test.ts
  • src/main/desktop/browser/YoBrowserPresenter.ts

Comment thread test/main/evals/nativeAgent/harness.ts
@yyhhyyyyyy
yyhhyyyyyy requested a review from zerob13 August 8, 2026 05:39

@zerob13 zerob13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Complexity and test-value review

I would not merge this PR in its current shape. The crash-boundary direction is useful and the
boundary/real-process tests are valuable, but the implementation is not yet the smallest coherent
change: the PR is 111 files and +11,382/-827, mixes a durable journal with unrelated Context Tape
repairs, and puts an unbounded amount of historical work on application startup.

Findings

  1. [P1] Recovery performs an unbounded full-history scan on the synchronous startup path.

    ExecutionJournalService.classifyRecoveryCandidates() reads every journal event through
    listEventsByNames() (src/main/tape/application/executionJournalService.ts:163), whose SQL has
    no run-state predicate, checkpoint, or limit
    (src/main/tape/infrastructure/sqlite/tapeEntryStore.ts:642). The classifier then materializes
    every Run and reparses every payload; outcome parsing also hashes the persisted response again.
    MAX_STARTUP_RECOVERY_DETAILS only bounds logging, not scanning. With response payloads allowed
    up to 256,000 characters, launch cost grows with total lifetime journal bytes rather than unresolved
    work. This also contradicts the PR description's “bounded recovery scanning” claim.

    The minimal V1 is to query only Runs without a terminal fact and load their related facts. If a
    permanent global corruption audit is required, run it outside synchronous startup or add a durable
    acknowledgement/retention design before landing this path.

  2. [P2] V1 persists outcome data that no production recovery path consumes.

    ExecutionToolOutcomeFact stores responseText and offloadPath
    (src/main/tape/domain/executionJournal.ts:112), but the classifier reduces an outcome to
    { entryId } (:708, :762) and startup recovery only marks the pending message interrupted.
    There is no production reader that replays or projects either field. Normal cleanup can also delete
    the referenced offload file, leaving a durable stale path. This duplicates sensitive tool output,
    increases database size and startup hashing cost, and implements a future recovery format without
    implementing that recovery.

    For V1, persist only the operation identity, isError, and a response hash if idempotency needs it.
    Add durable response recovery in a separate change when there is an actual consumer and retention
    contract.

  3. [P2] Split the Context Tape ordering fixes out of the journal PR.

    Acceptance criteria 18-20 in
    docs/architecture/durable-execution-journal/spec.md:254 cover compaction provenance, message
    replacement semantics, tool ordering, and backfill revisions. Commits f0e045ed3, 58c0189a1,
    and e718512bd account for +989/-149 lines and are independently reviewable Context Tape fixes;
    they are not required to establish T0/T1/T2/T3 journal boundaries. Combining them makes failures
    harder to attribute and forces journal reviewers to validate a second storage model. Move those
    commits and their tests to a separate PR.

  4. [P3] The missing-dispatch gate should be a type contract, not a runtime branch and test.

    ToolExecutionPort.execute() still accepts optional options, so
    createToolExecutionPort() checks options?.commitDispatch at runtime
    (src/main/agent/deepchat/runtime/toolAdapters.ts:61). The only production callers of this port are
    normal dispatch and deferred dispatch, and both always provide the callback. Define the internal
    execution options as ToolCallOptions & { commitDispatch: ToolDispatchCommit }, require them on
    ToolExecutionPort.execute, and delete this guard plus its dedicated test. Lower-level/direct tool
    APIs may keep optional callbacks where non-journal execution is a real use case.

Gate assessment

The T1/T2 prerequisite checks, duplicate-operation checks, local preflight-before-T1 checks, and the
host-transaction prohibition protect different failure windows; they are not mutually redundant.
The redundant gate is the runtime capability-presence check above because the internal port can make
the invalid state unrepresentable. The broader callback plumbing is costly (new beforeMutation /
beforeInvoke variants span 23 source files), but most of it exists because side-effect preflight is
owned deep in each subsystem. Replacing it safely would require one uniform prepare/commit/invoke
contract, not another layer of booleans.

Test assessment

The test total (+6,065/-138) exceeds the production-source addition (+4,455/-676), but the ratio
alone is not the problem. Keep the native crash tests and the dispatch/outcome/terminal ordering tests;
they protect observable durability contracts. The avoidable bulk is mainly implementation proof:

  • deepChatAgentHarness.test.ts:2317-2460 spends about 140 lines on log caps, priority, and string
    sanitization through full harness construction. Build classifier reports directly and collapse this
    to one table-driven diagnostic test.
  • deepChatAgentHarness.test.ts:2928-3006 repeats nearly the same fallback-error scenario for typed,
    corruption, and untyped errors. One table-driven contract test can preserve subtype/cause assertions.
  • The dedicated missing-commitDispatch adapter test disappears when the port type is corrected.
  • Keep the background-process ownership and Context Tape regression tests with the separate PRs that
    own those behaviors; they are useful tests, but they inflate and couple this journal review.

Minimal-cut summary

src/main/tape/application/executionJournalService.ts:L163: scale: replace the lifetime scan with an unresolved-Run recovery query.

src/main/tape/domain/executionJournal.ts:L112: yagni: remove raw response/offload persistence until recovery consumes it.

src/main/agent/deepchat/runtime/toolAdapters.ts:L61: type: require commitDispatch on the internal execution port and delete the runtime gate.

docs/architecture/durable-execution-journal/spec.md:L254: scope: move Context Tape compaction/order repair to its own PR.

docs/architecture/durable-execution-journal/plan.md:L1: artifact: keep the final spec; drop the 375-line plan and 111-line task ledger, moving open follow-ups to an issue.

net(PR scope): at least -1,300 lines possible before parser and test deduplication.

Validation at f9098f6513a317dcd265709d0959935f0c1ec0ff: required GitHub checks are green; focused
Vitest coverage passed 36 tests, with 11 environment-gated native crash cases skipped locally.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/architecture/durable-execution-journal/tasks.md`:
- Line 120: Update the checklist item at the diff’s task entry to replace the
instruction to “push normally” with “do not push,” while preserving the required
validation, diff review, and commit steps.

In `@src/main/tape/infrastructure/sqlite/tapeEntryStore.ts`:
- Around line 67-69: Update the migration around the
idx_deepchat_tape_entries_session_provenance definition in
src/main/tape/infrastructure/sqlite/tapeEntryStore.ts so legacy duplicate Tape
rows cannot cause SQLite startup failure: scope the uniqueness constraint to the
applicable Journal events, or add and verify a migration that resolves duplicate
provenance keys before enabling it. In
docs/architecture/durable-execution-journal/spec.md lines 211-212, revise the
compatibility claim if existing Tape rows are no longer guaranteed to satisfy
this constraint.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 76167ca8-53f6-4a05-9553-c06c2af5699b

📥 Commits

Reviewing files that changed from the base of the PR and between f9098f6 and 2639c2d.

📒 Files selected for processing (18)
  • docs/architecture/durable-execution-journal/plan.md
  • docs/architecture/durable-execution-journal/spec.md
  • docs/architecture/durable-execution-journal/tasks.md
  • src/main/agent/deepchat/loop/ports.ts
  • src/main/agent/deepchat/runtime/deferredToolExecutor.ts
  • src/main/agent/deepchat/runtime/dispatch.ts
  • src/main/tape/application/executionJournalService.ts
  • src/main/tape/domain/executionJournal.ts
  • src/main/tape/infrastructure/sqlite/tapeEntryStore.ts
  • src/main/tape/ports/storage.ts
  • test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts
  • test/main/agent/deepchat/runtime/deferredToolExecutor.test.ts
  • test/main/agent/deepchat/runtime/dispatch.test.ts
  • test/main/agent/deepchat/runtime/toolAdapters.test.ts
  • test/main/session/data/tapeTestHarness.ts
  • test/main/session/runtimeIntegration.test.ts
  • test/main/tape/executionJournal.test.ts
  • test/main/tape/executionJournalCrash.test.ts
💤 Files with no reviewable changes (1)
  • test/main/agent/deepchat/runtime/toolAdapters.test.ts
🚧 Files skipped from review as they are similar to previous changes (11)
  • test/main/session/runtimeIntegration.test.ts
  • test/main/session/data/tapeTestHarness.ts
  • test/main/tape/executionJournal.test.ts
  • test/main/agent/deepchat/runtime/deferredToolExecutor.test.ts
  • test/main/agent/deepchat/runtime/dispatch.test.ts
  • src/main/tape/application/executionJournalService.ts
  • src/main/tape/domain/executionJournal.ts
  • docs/architecture/durable-execution-journal/plan.md
  • src/main/agent/deepchat/runtime/deferredToolExecutor.ts
  • test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts
  • src/main/tape/ports/storage.ts

Comment thread docs/architecture/durable-execution-journal/tasks.md
Comment thread src/main/tape/infrastructure/sqlite/tapeEntryStore.ts
@yyhhyyyyyy
yyhhyyyyyy requested a review from zerob13 August 8, 2026 07:00
@yyhhyyyyyy
yyhhyyyyyy merged commit 2e2b118 into dev Aug 8, 2026
12 checks passed
@zhangmo8
zhangmo8 deleted the feat/tape-execution-journal branch August 10, 2026 02:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants