Skip to content

fix(server): release webhook claims when acceptance fails - #18820

Merged
juliusmarminge merged 5 commits into
pingdotgg:mainfrom
saphid:t3code/sweep/webhook-claim-release
Oct 19, 2026
Merged

juliusmarminge merged 5 commits into
pingdotgg:mainfrom
saphid:t3code/sweep/webhook-claim-release

Conversation

@saphid

@saphid saphid commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

A failed webhook acceptance could leave its relay deduplication claim behind. The relay retries the HTTP 500, but the stale claim answers duplicate and the task never starts.

The service now tracks whether this invocation acquired the claim, releases it when acceptance fails before dispatch, and retains it after dispatch. A duplicate request or failed claim insert cannot delete another invocation's claim. Existing rate-limit and queue-full release behavior is preserved.

Credit to @saphid for #18820. Contributor commits are preserved, with current main merged in. An independent implementation pass retained the focused production fix; the maintainer test pass consolidated the two added tests into one recovery flow in the existing suite.

Verification

Reviewed local head: 3f0cc0983d, based on c274a25151.

  • PR-added tests: 2 → 1, in the existing webhook service suite; focused total 41 → 40 across service and route suites (33 + 7), all passing.
  • Before: the retained regression fails on the pinned main implementation because both retries return duplicate. Removing the ownership guard also fails because a non-owner deletes the accepted claim.
  • After: the regression covers a delivery-log failure, concurrent retries yielding one accepted and one duplicate, one launch, and a failed non-owner request preserving the accepted claim. Real migrated in-memory SQLite, no sleeps or polling.
  • Server typecheck, targeted lint and formatting pass.
  • Round 1 found no behavior defects; Opus requested restoration of the existing claim-lifetime rationale, now restored. Fresh full-diff round 2 by Opus and Sol found no actionable issues. Fresh pushed-head CI is required before merging.

Actual Linux loopback HTTP verification used the real webhook route, signed relay JWT verification, service and migrated in-memory SQLite. The external provider launcher was stubbed and observed through a Queue; no provider turn ran. Safe HTTP proof log.

Request HTTP / outcome Observed result
Accepted-log write fails 500 / error No delivery or launch
Two concurrent retries after removing failure 202 / accepted + duplicate One delivery and one launch
Non-owner claim insert fails 500 / error Existing claim retained
Same delivery retried afterward 202 / duplicate No second launch

The HTTP proof and focused checks ran at 061cac9475. The final follow-up only restores four existing comment lines; executable source and tests are unchanged. Targeted lint and formatting also pass after that comment change. The ephemeral HTTP server was closed after verification. Screenshots do not apply to this server behavior. No deployed relay, actual provider completion, macOS, Windows, Electron shell, iOS or Android execution was verified here.

Cleanup remains best effort if SQLite cannot delete the claim. The pre-existing overlap race (a duplicate receives 202 before the first request later fails acceptance) and restart durability in #18810 remain outside this fix. This is the focused obvious-bug contribution exception; it changes no schema, configuration or product defaults.

Implementation: gpt-6.1-sol; tests: gpt-6-astra; reviews: gpt-6-sol and claude-opus-5-5. Harness: Codex / Claude Code through T3 Code.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Oct 12, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 3f0cc09

Macroscope's review found this PR approvable — This is a small, self-contained server bug fix that makes webhook claim cleanup ownership-aware and releases claims when acceptance fails before dispatch. Existing successful paths remain unchanged, and focused tests cover the failure and retry scenarios.

You can add or adjust custom eligibility rules. Learn more.

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 12, 2026
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 71cba453-e7e1-48c6-b1b9-067833204b43
📥 Commits

Reviewing files that changed from the base of the PR and between bdb5604 and 3f0cc09.

📒 Files selected for processing: 2
  • apps/server/src/scheduledTasks/ScheduledTaskService.ts
  • apps/server/src/scheduledTasks/ScheduledTaskService.webhook.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

📝 Walkthrough

Relay claim ownership now follows acquisition and dispatch handoff. The service releases acquired claims when errors occur before dispatch starts. Tests cover delivery-log and claim insertion failures, retry, and concurrent requests using the same relay delivery ID.

Changes: Relay delivery claims

Layer / File(s) Summary
Track claim ownership through dispatch
apps/server/src/scheduledTasks/ScheduledTaskService.ts
The service records when an invocation acquires a relay claim. It releases the claim on errors only while that invocation owns it, and retains the claim after background dispatch starts.
Test retry and concurrent delivery handling
apps/server/src/scheduledTasks/ScheduledTaskService.webhook.test.ts
The test setup provides a SQL client to test callbacks. Tests verify retry and concurrent request outcomes after delivery-log or relay-claim insertion failures.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to 3f0cc

The claim-release change is ready to merge after normal checks. No new blocking issue was identified.

Security architecture risk: 🔵 Low · up to 3f0cc

The change limits claim deletion to the request that acquired it and preserves deduplication after dispatch. No expanded access or weakened authentication was identified. Recovery remains best-effort when storage writes fail, and restart recovery remains outside this fix.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — The affected state is the server's persistent relay-delivery claim table and scheduled webhook dispatch. Claims are keyed by relay delivery ID and associated with a task. This change does not grant a caller broader task-execution authority.

Security Findings and Attack Paths

  • observed — The change closes a cross-request cleanup hazard: a duplicate request never records ownership, so its error handling cannot delete the original request's claim. After fork handoff, parent cleanup no longer has claim-release authority, preserving deduplication for dispatched work.

Trust Boundaries and Controls

  • observed — The verifier validates a typed EdDSA JWT with issuer, environment audience, age, and schema checks, then matches environment, delivery ID, received timestamp, and hook ID. Missing or invalid proof follows the existing direct-webhook path without forwarding relay identity; it does not bypass the URL-token check.

Resilience and Maintainability Implications

  • inferred — The PR improves recovery from pre-dispatch errors but does not establish durable dispatch recovery or eliminate the existing window in which a concurrent retry observes a claim before acceptance finishes. Cancellation protection is not process-crash protection. These are unchanged lifecycle limitations, not new PR concerns.
Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title is concise, specific, and accurately describes the main fix: releasing webhook claims when acceptance fails.
Description check Passed The description clearly covers the problem, change, scope exception, verification results, limitations, and agent attribution. It does not use the template headings for Problem, Change, and Scope and …
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.
Full details: Description check

Explanation

The description clearly covers the problem, change, scope exception, verification results, limitations, and agent attribution. It does not use the template headings for Problem, Change, and Scope and approval, but the required information is present and the description is otherwise complete.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

…s when acceptance fails

Preserve the scoped contribution against upstream 70d60e0.
Focused checks and read-only integration review recorded in the PR.

GPT-6.1 Sol (high), Codex harness through T3 Code.
@macroscopeapp
macroscopeapp Bot dismissed their stale review October 17, 2026 02:57

Dismissing prior approval to re-evaluate bdb5604

@github-actions github-actions Bot added size:S 10-29 changed lines (additions + deletions). and removed size:XS 0-9 changed lines (additions + deletions). labels Oct 17, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 17, 2026
@juliusmarminge

Copy link
Copy Markdown
Member

Taking over this one as maintainer for batch scheduler-tasks-01. I will preserve the original commits, integrate current main, rebuild the focused claim-release fix, and verify it with fresh tests and independent reviews. This takeover will remain unmerged.

@macroscopeapp
macroscopeapp Bot dismissed their stale review October 19, 2026 16:57

Dismissing prior approval to re-evaluate 3f0cc09

@github-actions github-actions Bot added size:XS 0-9 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Oct 19, 2026
@juliusmarminge
juliusmarminge merged commit 02cd3f5 into pingdotgg:main Oct 19, 2026
29 of 30 checks passed
Pipyakas pushed a commit to Pipyakas/t3code that referenced this pull request Oct 19, 2026
…18820)

Co-authored-by: SAPHID <saphid@users.noreply.github.com>
Co-authored-by: GPT-6.1 Sol <noreply@openai.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
(cherry picked from commit 02cd3f5)
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Oct 19, 2026
## What's Changed
* fix(mobile): settings no longer tell you to update when you're up to date by @shivamhwp in pingdotgg/t3code#21688
* test(web): fix the workflow script test that times out on busy CI runners by @shivamhwp in pingdotgg/t3code#21699
* fix(mobile): a file shared into a new task shows in the composer before you send by @shivamhwp in pingdotgg/t3code#21659
* fix(desktop): a cold WSL distro gets 30 seconds to boot instead of 10 by @SunkenInTime in pingdotgg/t3code#21070
* fix(web): detect software keyboard before handling composer Enter by @Yash-Singh1 in pingdotgg/t3code#21763
* fix(mobile): the Git sheet uses the standard list rows by @juliusmarminge in pingdotgg/t3code#21785
* fix(server): changed files keep their real paths for renames and non-ASCII names by @Atharvsinh-codez in pingdotgg/t3code#20175
* fix(server): a message promoted into a stopping run stays queued by @lbgos in pingdotgg/t3code#16926
* perf(mobile): streaming re-renders less on the open thread screen by @juliusmarminge in pingdotgg/t3code#20963
* feat(usage): show even-pace marks on Limits bars by @flamboh in pingdotgg/t3code#14477
* fix(web): Usage hourly labels follow the Time format setting by @mInrOz in pingdotgg/t3code#15575
* fix(web): stop repeating the subagent name in the waiting banner by @saphid in pingdotgg/t3code#16022
* fix(web): Cmd+O no longer opens the editor more than once by @5knnbdwm in pingdotgg/t3code#18983
* fix(web): hoist favorited legacy models to the top of the model picker by @TonybynMp4 in pingdotgg/t3code#11933
* fix(server): a rollback blocked by Git's index lock says so instead of a generic error by @shivamhwp in pingdotgg/t3code#11340
* fix(mobile): expanded tool-call groups keep following new calls by @nekohasekai in pingdotgg/t3code#15747
* fix(web): going back in the command palette keeps the search that led there by @saphid in pingdotgg/t3code#15940
* fix(web): changing a project's model no longer keeps the old model's options by @yaacovcorcos in pingdotgg/t3code#16581
* fix(web): preserve snapshot thumbnail context and detail by @maria-rcks in pingdotgg/t3code#18440
* fix(web): keep expanded tool actions usable from the keyboard by @saphid in pingdotgg/t3code#18831
* fix(usage): Claude usage no longer lists a `<synthetic>` model by @tris203 in pingdotgg/t3code#14672
* fix(server): release webhook claims when acceptance fails by @saphid in pingdotgg/t3code#18820
* fix(desktop): make the annotation editor border and shadow actually render by @PollyGlot in pingdotgg/t3code#9406
* fix(server): Claude follow-ups no longer fail in Auto on models without Auto by @Gigioxx in pingdotgg/t3code#15687
* fix(web): reopening Connections picks up new network addresses by @lnieuwenhuis in pingdotgg/t3code#15840
* fix(client): MCP apps can no longer trap you in full screen; it opens only after a tap by @shivamhwp in pingdotgg/t3code#18548
* fix(web,mobile): disabled provider instances no longer badge their siblings by @tris203 in pingdotgg/t3code#14545
* fix(web): threads open at the newest message, not thousands of pixels above it by @t3dotgg in pingdotgg/t3code#19663
* fix(mobile): report rejected shared settings writes by @juliusmarminge in pingdotgg/t3code#9356
* fix(claude): show automatic compaction while it runs by @maria-rcks in pingdotgg/t3code#15631
* fix(web): keep the parent thread highlighted while viewing its subagent by @saphid in pingdotgg/t3code#15163
* fix(web): show pull request checkout error detail by @saphid in pingdotgg/t3code#15007
* fix(server): mark unvisited thread completions unread by @maria-rcks in pingdotgg/t3code#15607
* fix(web): started threads no longer offer a machine picker that does nothing by @tris203 in pingdotgg/t3code#19900
* fix(web): provider model names no longer get cut off by their slug by @ilyaliao in pingdotgg/t3code#16522
* fix(claude): mid-sentence skill chips keep the full request by @ScottN-PV in pingdotgg/t3code#15253
* fix(web): preserve unsaved keybinding edits when saving another binding by @pnupu in pingdotgg/t3code#11109
* fix(connections): retry unsupported saved direct connections by @none23 in pingdotgg/t3code#15107
* fix(web): show readable messages for structured thread errors by @juliusmarminge in pingdotgg/t3code#21483
* fix(web): custom shortcuts work when Local environment is off by @Mnigos in pingdotgg/t3code#15825
* fix(web): keep thread notification tags within the Windows toast limit by @satyalyadav in pingdotgg/t3code#12289
* fix(web): pinned thread marker stays put when hovering the row by @flamboh in pingdotgg/t3code#11122
* fix(web): keep a typed question answer when you open a new thread by @Gigioxx in pingdotgg/t3code#13865
* fix(web): renumber following items when continuing a plain-Markdown numbered list by @saphid in pingdotgg/t3code#14332
* fix(web): clicking a logged request route no longer opens it in the editor by @lnieuwenhuis in pingdotgg/t3code#15838
* fix(desktop): reject offscreen annotation screenshot crops by @maria-rcks in pingdotgg/t3code#18441
* fix(web): NVDA browse mode reaches the new-thread project picker again by @akj in pingdotgg/t3code#17877
* fix(web): stop composer banner glass overlap by @t3-code[bot] in pingdotgg/t3code#8034
* fix(web): keep pasted decorators as text by @Gigioxx in pingdotgg/t3code#8415
* fix(shell): avoid interactive job control in environment probes by @LouisDeconinck in pingdotgg/t3code#11275
* fix(web): a closed proactive diff stays closed when you return to a thread by @ilyaliao in pingdotgg/t3code#14705
* fix(web): render powerline separators at cell edges by @SadriG91 in pingdotgg/t3code#5607
* fix(server): provider failures say why a turn could not start by @saphid in pingdotgg/t3code#16303

## New Contributors
* @Atharvsinh-codez made their first contribution in pingdotgg/t3code#20175
* @lbgos made their first contribution in pingdotgg/t3code#16926
* @yaacovcorcos made their first contribution in pingdotgg/t3code#16581
* @pnupu made their first contribution in pingdotgg/t3code#11109
* @LouisDeconinck made their first contribution in pingdotgg/t3code#11275
* @SadriG91 made their first contribution in pingdotgg/t3code#5607

**Full Changelog**: pingdotgg/t3code@v0.1.1-nightly.20261019.3360...v0.1.1-nightly.20261019.3373

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.1.1-nightly.20261019.3373
github-actions Bot added a commit to davidvanderklay/t3code-flake that referenced this pull request Oct 19, 2026
## What's Changed
* fix(mobile): settings no longer tell you to update when you're up to date by @shivamhwp in pingdotgg/t3code#21688
* test(web): fix the workflow script test that times out on busy CI runners by @shivamhwp in pingdotgg/t3code#21699
* fix(mobile): a file shared into a new task shows in the composer before you send by @shivamhwp in pingdotgg/t3code#21659
* fix(desktop): a cold WSL distro gets 30 seconds to boot instead of 10 by @SunkenInTime in pingdotgg/t3code#21070
* fix(web): detect software keyboard before handling composer Enter by @Yash-Singh1 in pingdotgg/t3code#21763
* fix(mobile): the Git sheet uses the standard list rows by @juliusmarminge in pingdotgg/t3code#21785
* fix(server): changed files keep their real paths for renames and non-ASCII names by @Atharvsinh-codez in pingdotgg/t3code#20175
* fix(server): a message promoted into a stopping run stays queued by @lbgos in pingdotgg/t3code#16926
* perf(mobile): streaming re-renders less on the open thread screen by @juliusmarminge in pingdotgg/t3code#20963
* feat(usage): show even-pace marks on Limits bars by @flamboh in pingdotgg/t3code#14477
* fix(web): Usage hourly labels follow the Time format setting by @mInrOz in pingdotgg/t3code#15575
* fix(web): stop repeating the subagent name in the waiting banner by @saphid in pingdotgg/t3code#16022
* fix(web): Cmd+O no longer opens the editor more than once by @5knnbdwm in pingdotgg/t3code#18983
* fix(web): hoist favorited legacy models to the top of the model picker by @TonybynMp4 in pingdotgg/t3code#11933
* fix(server): a rollback blocked by Git's index lock says so instead of a generic error by @shivamhwp in pingdotgg/t3code#11340
* fix(mobile): expanded tool-call groups keep following new calls by @nekohasekai in pingdotgg/t3code#15747
* fix(web): going back in the command palette keeps the search that led there by @saphid in pingdotgg/t3code#15940
* fix(web): changing a project's model no longer keeps the old model's options by @yaacovcorcos in pingdotgg/t3code#16581
* fix(web): preserve snapshot thumbnail context and detail by @maria-rcks in pingdotgg/t3code#18440
* fix(web): keep expanded tool actions usable from the keyboard by @saphid in pingdotgg/t3code#18831
* fix(usage): Claude usage no longer lists a `<synthetic>` model by @tris203 in pingdotgg/t3code#14672
* fix(server): release webhook claims when acceptance fails by @saphid in pingdotgg/t3code#18820
* fix(desktop): make the annotation editor border and shadow actually render by @PollyGlot in pingdotgg/t3code#9406
* fix(server): Claude follow-ups no longer fail in Auto on models without Auto by @Gigioxx in pingdotgg/t3code#15687
* fix(web): reopening Connections picks up new network addresses by @lnieuwenhuis in pingdotgg/t3code#15840
* fix(client): MCP apps can no longer trap you in full screen; it opens only after a tap by @shivamhwp in pingdotgg/t3code#18548
* fix(web,mobile): disabled provider instances no longer badge their siblings by @tris203 in pingdotgg/t3code#14545
* fix(web): threads open at the newest message, not thousands of pixels above it by @t3dotgg in pingdotgg/t3code#19663
* fix(mobile): report rejected shared settings writes by @juliusmarminge in pingdotgg/t3code#9356
* fix(claude): show automatic compaction while it runs by @maria-rcks in pingdotgg/t3code#15631
* fix(web): keep the parent thread highlighted while viewing its subagent by @saphid in pingdotgg/t3code#15163
* fix(web): show pull request checkout error detail by @saphid in pingdotgg/t3code#15007
* fix(server): mark unvisited thread completions unread by @maria-rcks in pingdotgg/t3code#15607
* fix(web): started threads no longer offer a machine picker that does nothing by @tris203 in pingdotgg/t3code#19900
* fix(web): provider model names no longer get cut off by their slug by @ilyaliao in pingdotgg/t3code#16522
* fix(claude): mid-sentence skill chips keep the full request by @ScottN-PV in pingdotgg/t3code#15253
* fix(web): preserve unsaved keybinding edits when saving another binding by @pnupu in pingdotgg/t3code#11109
* fix(connections): retry unsupported saved direct connections by @none23 in pingdotgg/t3code#15107
* fix(web): show readable messages for structured thread errors by @juliusmarminge in pingdotgg/t3code#21483
* fix(web): custom shortcuts work when Local environment is off by @Mnigos in pingdotgg/t3code#15825
* fix(web): keep thread notification tags within the Windows toast limit by @satyalyadav in pingdotgg/t3code#12289
* fix(web): pinned thread marker stays put when hovering the row by @flamboh in pingdotgg/t3code#11122
* fix(web): keep a typed question answer when you open a new thread by @Gigioxx in pingdotgg/t3code#13865
* fix(web): renumber following items when continuing a plain-Markdown numbered list by @saphid in pingdotgg/t3code#14332
* fix(web): clicking a logged request route no longer opens it in the editor by @lnieuwenhuis in pingdotgg/t3code#15838
* fix(desktop): reject offscreen annotation screenshot crops by @maria-rcks in pingdotgg/t3code#18441
* fix(web): NVDA browse mode reaches the new-thread project picker again by @akj in pingdotgg/t3code#17877
* fix(web): stop composer banner glass overlap by @t3-code[bot] in pingdotgg/t3code#8034
* fix(web): keep pasted decorators as text by @Gigioxx in pingdotgg/t3code#8415
* fix(shell): avoid interactive job control in environment probes by @LouisDeconinck in pingdotgg/t3code#11275
* fix(web): a closed proactive diff stays closed when you return to a thread by @ilyaliao in pingdotgg/t3code#14705
* fix(web): render powerline separators at cell edges by @SadriG91 in pingdotgg/t3code#5607
* fix(server): provider failures say why a turn could not start by @saphid in pingdotgg/t3code#16303

## New Contributors
* @Atharvsinh-codez made their first contribution in pingdotgg/t3code#20175
* @lbgos made their first contribution in pingdotgg/t3code#16926
* @yaacovcorcos made their first contribution in pingdotgg/t3code#16581
* @pnupu made their first contribution in pingdotgg/t3code#11109
* @LouisDeconinck made their first contribution in pingdotgg/t3code#11275
* @SadriG91 made their first contribution in pingdotgg/t3code#5607

**Full Changelog**: pingdotgg/t3code@v0.1.1-nightly.20261019.3360...v0.1.1-nightly.20261019.3373

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.1.1-nightly.20261019.3373
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants