Skip to content

fix(agent): treat run_terminal mirror stop as cancellation in durable run event sink - #4326

Merged
kwakayama merged 2 commits into
mainfrom
issue/872-durable-mirror-run-terminal
Aug 30, 2026
Merged

fix(agent): treat run_terminal mirror stop as cancellation in durable run event sink#4326
kwakayama merged 2 commits into
mainfrom
issue/872-durable-mirror-run-terminal

Conversation

@kwakayama

Copy link
Copy Markdown
Contributor

When the durable run event mirror is disabled with reason run_terminal (the API declared the run terminal, e.g. a project delete cancelled in-flight runs — a clean stop per veryfront-issue-inbox#743, already treated as such by run-chunk-mirror.ts and hosted-chat-finalization.ts), assertEnabled() in src/agent/hosted/durable-run-event-sink.ts still escalated it to DurableRunEventPersistenceError: Required durable run event mirror is disabled: run_terminal, paging Sentry (VERYFRONT-AGENT-7). The fix special-cases run_terminal in assertEnabled() to reject with DOMException("Durable run event mirror stopped: the run is already terminal", "AbortError") — the runtime's recognized cancellation shape — while every other disable reason (auth_rejected, payload_too_large, ...) keeps failing hard, and the fail-closed contract is preserved: the sink still rejects, so the model call is never dispatched for a terminal run. Because both discovery points (the entry check before append, and the post-append flush) funnel through assertEnabled(), one guard covers both.

Note: the Sentry culprit veryfront.esm.src.agent.hosted:durable-run-event-sink is framework code that veryfront-agent consumes via the prebuilt veryfront npm package, so the fix lands here in veryfront-code rather than veryfront-agent; veryfront-agent will need a veryfront dependency bump after this ships before the Sentry group goes quiet.

Fixes veryfront/veryfront-issue-inbox#872

Red

deno task test:file src/agent/hosted/durable-run-event-sink.test.ts

Before the fix:

agent/hosted/durable-run-event-sink ...
  treats a mirror already stopped by a terminal run as cancellation, not a failure ... FAILED (0ms)
  treats a run turning terminal during persistence as cancellation, not a failure ... FAILED (0ms)

 ERRORS

treats a mirror already stopped by a terminal run as cancellation, not a failure
error: AssertionError: Expected error to be instance of "DOMException", but was "DurableRunEventPersistenceError": a terminal-run stop must refuse the dispatch as a cancellation, not a persistence failure
    at async durable-run-event-sink.test.ts:478

treats a run turning terminal during persistence as cancellation, not a failure
error: AssertionError: Expected error to be instance of "DOMException", but was "DurableRunEventPersistenceError": a run that turns terminal mid-persistence must reject as a cancellation
    at async durable-run-event-sink.test.ts:518

FAILED | 0 passed (19 steps) | 1 failed (2 steps)

The raised error in both cases is DurableRunEventPersistenceError "Required durable run event mirror is disabled: run_terminal" — the exact Sentry VERYFRONT-AGENT-7 signature.

Green

deno task test:file src/agent/hosted/durable-run-event-sink.test.ts
  treats a mirror already stopped by a terminal run as cancellation, not a failure ... ok
  treats a run turning terminal during persistence as cancellation, not a failure ... ok
  reports the concrete disable reason when a required mirror is already disabled ... ok
  ...
agent/hosted/durable-run-event-sink ... ok (426ms)
ok | 1 passed (21 steps) | 0 failed (430ms)

Affected suites:

deno task test:file src/agent/hosted        => ok | 498 passed (419 steps) | 0 failed (11s)
deno task test:file src/agent/conversation  => ok | 21 passed (246 steps) | 0 failed (2s)
deno fmt --check / deno lint / deno check on durable-run-event-sink.ts: all clean

Revert check

With the fix commit reverted (git revert --no-commit a2fddccf, only src/agent/hosted/durable-run-event-sink.ts modified), the regression tests fail again with the original signature:

treats a mirror already stopped by a terminal run as cancellation, not a failure
  => AssertionError: Expected error to be instance of "DOMException", but was "DurableRunEventPersistenceError": a terminal-run stop must refuse the dispatch as a cancellation, not a persistence failure
treats a run turning terminal during persistence as cancellation, not a failure
  => AssertionError: Expected error to be instance of "DOMException", but was "DurableRunEventPersistenceError"
FAILED | 0 passed (19 steps) | 1 failed (2 steps) (401ms)

Restored to the fix (git reset --hard a2fddccf), the suite passes again:

agent/hosted/durable-run-event-sink ... ok (409ms)
ok | 1 passed (21 steps) | 0 failed (413ms)

Acceptance criteria

  • Deterministic regression test reproduces the Sentry signature (DurableRunEventPersistenceError "Required durable run event mirror is disabled: run_terminal" from assertEnabled) using synthetic mirror fixtures only.
  • A run_terminal mirror stop refuses the model dispatch as a clean cancellation (DOMException named AbortError), not DurableRunEventPersistenceError.
  • Both discovery points covered: mirror already disabled before append (nothing appended), and mirror disabled by the post-append flush (context already appended).
  • Every other disable reason (auth_rejected, payload_too_large, ...) keeps failing hard with DurableRunEventPersistenceError; the existing "reports the concrete disable reason" test stays green.
  • Fail-closed contract preserved: the sink still rejects and the model call is never dispatched for a terminal run; no weakened assertions, no Sentry suppression.
  • Lint, typecheck, and targeted tests pass (deno fmt/lint/check clean on the changed files).

Kentaro Wakayama added 2 commits August 30, 2026 22:04
… run event sink (issue-inbox#872)

A mirror disabled with reason run_terminal means the API already declared
the run finished server-side, so the sink now refuses the model dispatch
with a DOMException AbortError, the runtime's recognized abort shape,
instead of raising DurableRunEventPersistenceError. Every other disable
reason still fails closed with the persistence error.
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 29 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ffecdec-a3c7-42da-9714-ba4f8ce85129

📥 Commits

Reviewing files that changed from the base of the PR and between eaaf178 and a2fddcc.

📒 Files selected for processing (2)
  • src/agent/hosted/durable-run-event-sink.test.ts
  • src/agent/hosted/durable-run-event-sink.ts

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.

@github-actions

Copy link
Copy Markdown

📦 Client bundle boundary

Entrypoint Modules Source size Server leaks
src/index.client.ts 288 2232 KiB ✅ 0

A server module in a client graph aborts hydration in the browser. New leaks fail CI; known leaks are tracked in scripts/lint/client-bundle-baseline.json to burn down.

@gitar-bot

gitar-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown

Note

Automatic reviews are paused because your trial's included automatic processing has been used for this period. Upgrade now, or comment "Gitar review" to run a review anytime.
Learn more

Code Review ✅ Approved

Fixes the durable run event sink to treat run_terminal mirror stops as clean cancellations (DOMException with AbortError) rather than hard failures (DurableRunEventPersistenceError), stopping spurious Sentry alerts (VERYFRONT-AGENT-7) when the API declares a run terminal. The fix special-cases run_terminal in assertEnabled() while preserving the fail-closed contract for all other disable reasons and covering both entry and post-append discovery points. Regression tests added and all affected suites passing.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@codecov

codecov Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.50000% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/agent/hosted/durable-run-event-sink.ts 87.50% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@sonarqubecloud

Copy link
Copy Markdown

@kwakayama
kwakayama marked this pull request as ready for review August 30, 2026 21:33

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kwakayama has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-30T22:04:48.920208Z a2fddcc Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a2fddccff9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agent/hosted/durable-run-event-sink.ts
@kwakayama

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: a2fddccff9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@kwakayama
kwakayama added this pull request to the merge queue Aug 30, 2026
Merged via the queue into main with commit 0e2d942 Aug 30, 2026
67 checks passed
@kwakayama
kwakayama deleted the issue/872-durable-mirror-run-terminal branch August 30, 2026 22:47
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.

1 participant