Skip to content

fix(chat): recover pending inputs after restart - #2129

Merged
yyhhyyyyyy merged 4 commits into
devfrom
codex/issue-2111-pending-input-recovery
Aug 10, 2026
Merged

fix(chat): recover pending inputs after restart#2129
yyhhyyyyyy merged 4 commits into
devfrom
codex/issue-2111-pending-input-recovery

Conversation

@zerob13

@zerob13 zerob13 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • reconcile durable Queue and Steer inputs deterministically during cold startup
  • keep restored Queue items in the existing lane until the user explicitly resumes them
  • terminalize interrupted Steer attempts without recovery-specific failure or retry chrome
  • make pending-input listing a pure read so opening a Session cannot execute historical input
  • prevent a manually resumed Queue head from returning after a provider error

Root cause

Durable rows in deepchat_pending_inputs survived a process restart, but their in-memory scheduling edge and user-visible disposition did not. Queue and Steer were also treated as equivalent pending work even though they represent different user commitments. A later read or lifecycle wake could therefore execute an old input, while a failed manually resumed Queue claim could be released back to pending and reappear on the next Session entry.

Behavior

Before

Restored Session
+--------------------------------------------------+
| You  10:21  Unread / Failed                      |
| Please change the output format   [Retry]        |
|                                                  |
| Queue (2)                                        |
|  1. Add a short example          [Edit] [Delete] |
|  2. Translate it to Chinese      [Edit] [Delete] |
+--------------------------------------------------+

Opening or listing the Session could wake historical input.
Resume queue -> provider error -> row returns to pending.

After

Restored Session
+--------------------------------------------------+
| You  10:21                                       |
| Please change the output format                  |
|                                                  |
| Queue (2)                         [Resume queue]  |
|  1. Add a short example          [Edit] [Delete] |
|  2. Translate it to Chinese      [Edit] [Delete] |
+--------------------------------------------------+

Opening the Session is read-only.
Resume queue -> provider boundary -> consume durable row.
Provider errors remain in the transcript and do not restore the Queue item.

The existing message toolbar remains available for normal retry. No Steer-specific failure receipt or recovery action is added.

Implementation

  • Reconcile active pending inputs before any Session runtime is restored.
  • Keep pending Queue rows durable and add their IDs to a process-local restart hold.
  • Release that hold only through the typed sessions.resumePendingQueue route.
  • Preserve the existing Steer-before-Queue priority, Queue FIFO ordering, instance lease, and durable claim fences.
  • Consume a manually resumed Queue claim immediately before the provider stream starts.
    • Failures before that boundary release the claim, preserving the accepted draft.
    • Returned provider errors after that boundary remain transcript failures and cannot requeue the same item.
  • Convert an unclaimed restart Steer into an internal terminal error transcript message, consume its active row, and hide the receipt in the renderer.
  • Remove the scheduling side effect from pending-input listing.
  • Add focused main-process and renderer regressions for restart reconciliation, explicit resume, duplicate actions, failure boundaries, and Steer presentation.

Impact

  • Historical user intent never executes merely because the app starts or a Session hydrates.
  • Restored Queue items remain visible, editable, reorderable, and deletable until explicit resume.
  • A successful manual resume cannot leave the same Queue item behind after provider failure.
  • Interrupted Steer content stays in transcript history but is excluded from later model context until normal retry.
  • No database schema or migration is introduced.
  • Live Queue FIFO, Steer priority, attachment handling, provider execution, permission behavior, Session summaries, and sidebar behavior are unchanged.

Validation

  • pnpm format
  • pnpm i18n
  • pnpm lint
  • pnpm typecheck
  • focused main-process suites: 515/515 passed
  • focused renderer suites: 34/34 passed
  • full renderer suite: 2056/2056 passed

The full main-process run has 60 pre-existing Windows-environment failures across 27 unchanged files, dominated by POSIX path expectations, symlink permissions, executable-bit checks, and packaging fixtures. All affected main-process suites pass.

Closes #2111

Summary by CodeRabbit

  • New Features

    • Added a Resume queue action for queued messages retained after restarting the app.
    • Queued messages now wait for explicit confirmation instead of running automatically.
    • Added localized labels and failure notifications for queue resumption.
  • Bug Fixes

    • Improved recovery of interrupted Steer messages after restart.
    • Failed resumed messages are no longer duplicated or returned to the queue.
    • Pending-input views no longer trigger unexpected execution during session restoration.
    • Restart-failed Steer messages now support the standard retry flow without showing misleading receipt controls.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b7354dac-a891-41db-ac8f-b362ef48e702

📥 Commits

Reviewing files that changed from the base of the PR and between e41c08e and 10e8e0c.

📒 Files selected for processing (2)
  • test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts
  • test/main/routes/dispatcher.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/main/routes/dispatcher.test.ts

📝 Walkthrough

Walkthrough

Cold-start recovery now holds durable Queue inputs for explicit Resume queue, terminalizes unclaimed Steer inputs as retryable errors, and consumes resumed Queue claims before provider execution. The change adds runtime, session, route, renderer, localization, documentation, and test coverage.

Changes

Pending input restart recovery

Layer / File(s) Summary
Restart recovery contracts and behavior
docs/architecture/..., docs/features/..., docs/issues/...
The specifications define Queue holds, Steer terminalization, explicit resume, claim consumption, and recovery criteria.
Structured startup reconciliation
src/main/session/data/..., src/main/agent/deepchat/harness/createDeepChatAgentHarness.ts
Startup recovery returns affected sessions and retained Queue IDs. It creates or fails Steer transcript records and applies recovery atomically.
Queue holds and claim boundaries
src/main/agent/deepchat/runtime/...
The pump excludes held Queue inputs from automatic drains, supports manual release, preserves wake priorities, and consumes manual claims before provider streaming.
Explicit Queue resume API
src/main/agent/manager/..., src/main/session/..., src/shared/contracts/routes/..., src/renderer/api/SessionClient.ts
DeepChat exposes Queue availability and resumption through the runtime, session gate, route contracts, and renderer client. Steer retries can coexist with restart-held Queue inputs.
Queue resume UI and validation
src/renderer/src/components/..., src/renderer/src/features/..., src/renderer/src/stores/..., src/renderer/src/i18n/..., test/...
The UI adds guarded Queue resume controls and hides receipts for restart-failed Steers. Tests cover recovery, holds, claims, retries, gating, atomicity, and state.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: yyhhyyyyyy

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% 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 summarizes the primary change: recovering pending inputs after application restart.
Linked Issues check ✅ Passed The changes implement restart reconciliation, hydration-safe recovery, explicit Queue resume, Steer recovery, safety boundaries, and regression coverage for issue #2111.
Out of Scope Changes check ✅ Passed The code, documentation, UI, localization, and tests directly support pending-input restart recovery and explicit Queue resumption.
✨ 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 codex/issue-2111-pending-input-recovery

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.

@zerob13
zerob13 marked this pull request as ready for review August 10, 2026 04:59

@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: 3

🤖 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/agent/deepchat/runtime/pendingInputPump.ts`:
- Around line 583-588: Reformat the deferred wakeup assignment in the pending
wakeup handling code around deferredWakeups.set so it complies with the
configured 100-column width, using Oxfmt or an equivalent multiline call layout
without changing its logic.

In `@test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts`:
- Around line 2632-2681: Extend the test around createDeepChatAgentHarness to
assert that the provider execution path is not called when recovering the
unclaimed Steer input. Keep the existing consumption and recoverPendingMessages
expectations, and use the harness’s existing provider stream/mock symbol to
verify it remains unused.
- Around line 8267-8289: Strengthen the test around
restartedAgent.resumePendingQueue by asserting queued.id is absent from
sqlitePresenter.deepchatPendingInputsTable before provider.coreStream begins
execution. Add the assertion inside the provider mock or otherwise verify the
call order, while preserving the existing assertions for successful resumption
and eventual processStream invocation.
🪄 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: 50f6b4d8-6e0d-4c44-a5dc-46cf4a4d9db8

📥 Commits

Reviewing files that changed from the base of the PR and between 3873374 and 831b820.

📒 Files selected for processing (58)
  • docs/architecture/deepchat-agent-harness-boundaries/spec.md
  • docs/architecture/session-management.md
  • docs/features/im-style-steer-messages/spec.md
  • docs/issues/pending-input-restart-recovery/spec.md
  • src/main/agent/deepchat/harness/createDeepChatAgentHarness.ts
  • src/main/agent/deepchat/harness/deepChatAgentHarness.ts
  • src/main/agent/deepchat/runtime/pendingInputAdmissionCoordinator.ts
  • src/main/agent/deepchat/runtime/pendingInputPump.ts
  • src/main/agent/deepchat/runtime/runLifecycleCoordinator.ts
  • src/main/agent/deepchat/runtime/transcriptMutationCoordinator.ts
  • src/main/agent/deepchat/runtime/turnCoordinator.ts
  • src/main/agent/manager/deepChatAgentBackend.ts
  • src/main/agent/manager/sessionHandles.ts
  • src/main/app/composition.ts
  • src/main/session/contracts.ts
  • src/main/session/data/pendingInputs.ts
  • src/main/session/routes.ts
  • src/main/session/transcriptMutations.ts
  • src/main/session/turn.ts
  • src/renderer/api/SessionClient.ts
  • src/renderer/src/components/chat/PendingInputLane.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/features/chat-page/ChatPage.vue
  • src/renderer/src/features/chat-page/composables/usePendingInputActions.ts
  • src/renderer/src/i18n/da-DK/chat.json
  • src/renderer/src/i18n/de-DE/chat.json
  • src/renderer/src/i18n/en-US/chat.json
  • src/renderer/src/i18n/es-ES/chat.json
  • src/renderer/src/i18n/fa-IR/chat.json
  • src/renderer/src/i18n/fr-FR/chat.json
  • src/renderer/src/i18n/he-IL/chat.json
  • src/renderer/src/i18n/id-ID/chat.json
  • src/renderer/src/i18n/it-IT/chat.json
  • src/renderer/src/i18n/ja-JP/chat.json
  • src/renderer/src/i18n/ko-KR/chat.json
  • src/renderer/src/i18n/ms-MY/chat.json
  • src/renderer/src/i18n/pl-PL/chat.json
  • src/renderer/src/i18n/pt-BR/chat.json
  • src/renderer/src/i18n/ru-RU/chat.json
  • src/renderer/src/i18n/tr-TR/chat.json
  • src/renderer/src/i18n/vi-VN/chat.json
  • src/renderer/src/i18n/zh-CN/chat.json
  • src/renderer/src/i18n/zh-HK/chat.json
  • src/renderer/src/i18n/zh-TW/chat.json
  • src/renderer/src/stores/ui/pendingInput.ts
  • src/shared/contracts/routes.ts
  • src/shared/contracts/routes/sessions.routes.ts
  • test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts
  • test/main/agent/deepchat/runtime/pendingInputAdmissionCoordinator.test.ts
  • test/main/agent/deepchat/runtime/pendingInputPump.test.ts
  • test/main/agent/deepchat/runtime/transcriptMutationCoordinator.test.ts
  • test/main/session/data/pendingInputs.test.ts
  • test/main/session/transcriptMutations.test.ts
  • test/main/session/turn.test.ts
  • test/renderer/components/PendingInputLane.test.ts
  • test/renderer/components/message/MessageItemUser.test.ts
  • test/renderer/features/chat-page/composables/usePendingInputActions.test.ts
  • test/renderer/stores/pendingInputStore.test.ts

Comment thread src/main/agent/deepchat/runtime/pendingInputPump.ts Outdated
Comment thread test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts Outdated
Comment thread test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts Outdated
@zerob13
zerob13 requested a review from yyhhyyyyyy August 10, 2026 06:03

@yyhhyyyyyy yyhhyyyyyy 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.

I agree with the overall direction: pending-input listing should be a pure read, historical Queue items should require an explicit resume after restart, and an unclaimed Steer should become a terminal transcript fact rather than being executed by a later hydration/listing edge.

I found three restart-safety issues that I think should block the merge:

  1. A claimed Queue does not durably record that its user message was materialized.

    Startup recovery decides whether to consume or release a claimed Queue from input.messageIds.length, but the normal appendUserFact path in TurnCoordinator creates/adopts the user message without linking it back to the claimed pending-input row. linkClaimedQueueMessage() appears to be used only by the pre-stream Steer handoff path.

    If the process exits after the user message is persisted (or even after provider dispatch) but before the Queue claim settles, the next startup sees messageIds: [], releases and holds the row, and also recovers the existing transcript attempt as an error. Resuming or retrying can then execute the same input again.

    This may predate the PR, but it directly invalidates the new claimed-Queue recovery contract. Please make user-message materialization/adoption and the claimed-row association durable in the same transaction, or establish another authoritative recovery marker. A follow-up link in a second write would retain the same crash window.

  2. Pending Steer terminalization is not crash-atomic.

    recoverInputsAfterRestart() consumes the Steer row in one transaction and returns its linked message IDs through an in-memory forceRecoverMessagesBySession map. The harness calls recoverPendingMessages() only afterwards.

    If the process exits or recovery throws after the Steer row is consumed but before every linked user message is changed to error, the next startup cannot repair the state: the row is no longer active, while an unforced pending user message with Steer receipt metadata is intentionally kept pending. This leaves a permanent Unread message with no pending row behind it.

    Please terminalize all linked Steer user messages and consume the Steer row in the same database transaction. A fault-injection test should restart again after the first commit / after the first message of a merged Steer and verify that every message is error and no active row remains.

  3. Manual Resume semantics are lost when attachment preparation blocks.

    consumeClaimBeforeProviderStream is derived only from the current wake reason. A manually resumed item that returns needs_user_action becomes blocked; resolving it schedules an ordinary enqueue wake, so the next launch no longer has consume-before-provider enabled. If that provider attempt returns an error, the item is rolled back and released to pending, even though it is still the same explicitly resumed Queue head.

    Please preserve the manual-resume disposition by item ID across blocked -> pending -> claimed, and clear it only when the item is consumed, deleted, or promoted. Please add coverage for both attachment Retry and “send without image content,” followed by a provider error.

One non-blocking scope issue: the renderer shows Resume for any idle pending Queue, and the backend ignores whether releaseRestartHoldForSession() actually released a hold. This applies the new manual semantics to ordinary live Queue rows as well. At minimum, the route should return started: false when no restart hold was released; ideally the renderer should receive an authoritative resumeAvailable signal.

The existing CI is green, but the current tests do not cover these crash boundaries or the blocked-attachment resume sequence.

@zerob13
zerob13 requested a review from yyhhyyyyyy August 10, 2026 08:42

@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.

🧹 Nitpick comments (3)
test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts (1)

8292-8297: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Record the observed state instead of asserting inside the provider mock.

The expect call runs inside coreStream. If it fails, the error propagates into the processStream mock and is rejected there, not reported by the test runner. The later assertions still pass, because processStream was called and the item is consumed by then. A regression that consumes the claim after the provider starts can therefore go undetected.

Capture the state in a variable and assert it after the wait.

💚 Proposed fix
-        const provider = llmProvider.getProviderInstance('openai')
-        provider.coreStream.mockImplementationOnce(() => {
-          expect(sqlitePresenter.deepchatPendingInputsTable.get(queued.id)).toBeUndefined()
-          return (async function* () {
-            yield { type: 'stop', stop_reason: 'provider_error' }
-          })()
-        })
+        const provider = llmProvider.getProviderInstance('openai')
+        let pendingRowAtProviderStart: unknown = 'not-observed'
+        provider.coreStream.mockImplementationOnce(() => {
+          pendingRowAtProviderStart = sqlitePresenter.deepchatPendingInputsTable.get(queued.id)
+          return (async function* () {
+            yield { type: 'stop', stop_reason: 'provider_error' }
+          })()
+        })

Then assert after await vi.waitFor(() => expect(processStream).toHaveBeenCalledOnce()):

expect(pendingRowAtProviderStart).toBeUndefined()

As per coding guidelines, "Add the smallest regression test for user-visible behavior or a documented contract."

🤖 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/harness/deepChatAgentHarness.test.ts` around lines
8292 - 8297, Replace the in-provider expect in the coreStream mock with a
variable capturing sqlitePresenter.deepchatPendingInputsTable.get(queued.id)
when the provider starts. After awaiting processStream with vi.waitFor, assert
that the captured pending row is undefined, ensuring failures are reported by
the test runner.

Source: Coding guidelines

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

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

Consider resolving the blocked record through the production API.

Lines 303-308 mutate the fake store record directly to clear the blocked state. The production path resets a blocked Queue input through the resolve-blocked flow. The direct mutation couples the test to the record shape rather than to the observable reset contract.

If the pump port exposes no reset entry point, keep the current approach. Otherwise, drive the reset through that entry point.

As per coding guidelines, "Keep committed tests lean and focused on project reliability, stability, and observable contracts; remove temporary checks that only test implementation internals before handoff."

🤖 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/pendingInputPump.test.ts` around lines 279 -
314, Update the test around the blocked queue record to use the production
resolve-blocked/reset API exposed by the pending-input pump instead of mutating
pendingInputs.records directly. Preserve the existing assertions for the second
drain and consumption semantics, and only retain direct mutation if no suitable
reset entry point exists.

Source: Coding guidelines

test/main/routes/dispatcher.test.ts (1)

4393-4400: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add dispatcher coverage for sessions.resumePendingQueue.

sessions.listPendingInputs is covered, but the Queue resume route defined by sessionsResumePendingQueueRoute calls deps.turn.resumePendingQueue(sessionId) and has no dispatcher test. Add a small Vitest case that dispatches sessions.resumePendingQueue and asserts sessionTurnPort.resumePendingQueue is called for the input 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 `@test/main/routes/dispatcher.test.ts` around lines 4393 - 4400, Add a focused
Vitest case alongside the existing dispatcher coverage that calls
dispatchDeepchatRoute with sessions.resumePendingQueue and a sessionId, then
assert sessionTurnPort.resumePendingQueue was called with that same ID. Use the
existing runtime and route-context setup patterns without changing the
sessions.listPendingInputs test.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts`:
- Around line 8292-8297: Replace the in-provider expect in the coreStream mock
with a variable capturing
sqlitePresenter.deepchatPendingInputsTable.get(queued.id) when the provider
starts. After awaiting processStream with vi.waitFor, assert that the captured
pending row is undefined, ensuring failures are reported by the test runner.

In `@test/main/agent/deepchat/runtime/pendingInputPump.test.ts`:
- Around line 279-314: Update the test around the blocked queue record to use
the production resolve-blocked/reset API exposed by the pending-input pump
instead of mutating pendingInputs.records directly. Preserve the existing
assertions for the second drain and consumption semantics, and only retain
direct mutation if no suitable reset entry point exists.

In `@test/main/routes/dispatcher.test.ts`:
- Around line 4393-4400: Add a focused Vitest case alongside the existing
dispatcher coverage that calls dispatchDeepchatRoute with
sessions.resumePendingQueue and a sessionId, then assert
sessionTurnPort.resumePendingQueue was called with that same ID. Use the
existing runtime and route-context setup patterns without changing the
sessions.listPendingInputs test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ddb94204-ca22-4ead-9e8e-a7c4961e5e5a

📥 Commits

Reviewing files that changed from the base of the PR and between 924af6e and e41c08e.

📒 Files selected for processing (31)
  • docs/architecture/deepchat-agent-harness-boundaries/spec.md
  • docs/architecture/session-management.md
  • docs/features/im-style-steer-messages/spec.md
  • docs/issues/pending-input-restart-recovery/spec.md
  • src/main/agent/deepchat/harness/createDeepChatAgentHarness.ts
  • src/main/agent/deepchat/harness/deepChatAgentHarness.ts
  • src/main/agent/deepchat/runtime/pendingInputAdmissionCoordinator.ts
  • src/main/agent/deepchat/runtime/pendingInputPump.ts
  • src/main/agent/deepchat/runtime/turnCoordinator.ts
  • src/main/agent/manager/deepChatAgentBackend.ts
  • src/main/agent/manager/sessionHandles.ts
  • src/main/app/composition.ts
  • src/main/session/contracts.ts
  • src/main/session/data/pendingInputStore.ts
  • src/main/session/data/pendingInputs.ts
  • src/main/session/data/transcript.ts
  • src/main/session/routes.ts
  • src/main/session/turn.ts
  • src/renderer/api/SessionClient.ts
  • src/renderer/src/features/chat-page/ChatPage.vue
  • src/renderer/src/stores/ui/pendingInput.ts
  • src/shared/contracts/routes/sessions.routes.ts
  • test/main/agent/deepchat/harness/deepChatAgentHarness.test.ts
  • test/main/agent/deepchat/runtime/pendingInputAdmissionCoordinator.test.ts
  • test/main/agent/deepchat/runtime/pendingInputPump.test.ts
  • test/main/agent/manager/deepChatAgentBackend.test.ts
  • test/main/routes/dispatcher.test.ts
  • test/main/session/data/pendingInputs.test.ts
  • test/main/session/data/tables/deepchatPendingInputsTable.test.ts
  • test/main/session/turn.test.ts
  • test/renderer/stores/pendingInputStore.test.ts
🚧 Files skipped from review as they are similar to previous changes (15)
  • test/main/session/turn.test.ts
  • src/main/agent/deepchat/harness/createDeepChatAgentHarness.ts
  • docs/architecture/deepchat-agent-harness-boundaries/spec.md
  • src/renderer/src/features/chat-page/ChatPage.vue
  • src/renderer/api/SessionClient.ts
  • src/main/app/composition.ts
  • src/main/agent/deepchat/harness/deepChatAgentHarness.ts
  • docs/architecture/session-management.md
  • test/main/agent/deepchat/runtime/pendingInputAdmissionCoordinator.test.ts
  • src/main/session/turn.ts
  • src/main/agent/deepchat/runtime/pendingInputAdmissionCoordinator.ts
  • test/main/session/data/pendingInputs.test.ts
  • docs/issues/pending-input-restart-recovery/spec.md
  • src/main/session/contracts.ts
  • src/main/agent/deepchat/runtime/pendingInputPump.ts

@zerob13

zerob13 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the two applicable CodeRabbit nitpicks in 10e8e0ce9:

  • Moved the provider-start pending-row assertion out of the coreStream mock so a failure cannot be absorbed by the stream error path.
  • Added focused dispatcher coverage for sessions.resumePendingQueue.

No change was made to the direct fake-store reset in pendingInputPump.test.ts. PendingInputPumpStorePort intentionally does not expose a blocked-input reset/resolve operation; that transition is owned by PendingInputAdmissionCoordinator.resolveBlockedPendingInput. Adding a reset method to the pump solely for this unit test would widen the production port and couple the pump to an admission-layer responsibility. The test therefore retains the local state transition, matching the review's condition to keep it when no suitable pump reset entry point exists.

@yyhhyyyyyy yyhhyyyyyy 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.

LGTM

@yyhhyyyyyy
yyhhyyyyyy merged commit 81d48af into dev Aug 10, 2026
12 checks passed
@yyhhyyyyyy
yyhhyyyyyy deleted the codex/issue-2111-pending-input-recovery branch August 10, 2026 09:39
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.

[bug] Wake durable pending inputs after restart and session hydration

2 participants