Skip to content

Abandon a parked approval only on its own timeout - #997

Merged
TheGreatAxios merged 3 commits into
mainfrom
cl-7793-a-parked-approval-is-abandoned-when-a-different-parallel
Sep 14, 2026
Merged

Abandon a parked approval only on its own timeout#997
TheGreatAxios merged 3 commits into
mainfrom
cl-7793-a-parked-approval-is-abandoned-when-a-different-parallel

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

Summary

  • Match the approval-timeout scan to the parked call identity so one parallel call timing out no longer discards a sibling's still-valid decision
  • Resolve the parked call id from the pending-operation lookup when wired, otherwise derive it from history, keeping the text-only scan as fallback
  • Warn about a late approval decision only when the timeout answers the same call

Verification

  • bun run check passes: lint, typecheck, build, and the full suite (7300 pass, 0 fail across 501 files)
  • New src/session/approval-resume.test.ts fails without the fix (sibling decision dropped) and passes with it

Fixes CL-7793

@linear-code

linear-code Bot commented Sep 13, 2026

Copy link
Copy Markdown

CL-7793

@TheGreatAxios

Copy link
Copy Markdown
Collaborator Author

Critic review · Approve (non-blocking follow-ups)

Fixes the sibling cross-talk: the timeout scan now requires the result to answer the parked call itself, via the optional lookup or the exact-one history derivation. Common case verified: all 3 new tests pass in the branch worktree; the red shape (old text-only scan drops on any sibling timeout) fails tests 1 and 3 by construction.

Findings (all non-blocking)

  • src/session/approval-resume.ts (parkedCallIdFromHistory) — identical name+args duplicates defeat the exact-one rule. Proven with a throwaway probe (removed after): two parked run_shell / echo same calls where the resumed call's own timeout fired and the twin sits unanswered → derivation returns the twin's id, the settled check misses, and the genuinely-late decision is delivered as an uncorrelated turn. Mirror case (sibling timed out, identical args) still delivers correctly because the answered sibling drops out of candidates — also probed. Recommend a keeper test for the duplicate-args shape; the real fix needs the call-id source below.
  • src/exec/runner.ts:979, src/tui/runner/session.ts:498 — neither caller wires resolveParkedCallId, and the vendored reactor exposes no correlationId-to-call lookup (src/permission/decline-markers.ts:8-12), so the lookup seam is dead in production and the heuristic is the live path. No change requested — just do not assume the strong identity path is active.
  • Fallback warn attribution: when parkedCallId is undefined, a sibling timeout both drops A's valid decision (legacy cross-talk persists for duplicate/compacted-history shapes) and logs a late-decision warning against A's correlation. Consider logging the matched call id alongside the correlation.

Notes

  • Hygiene clean: two files, red-then-green commits (e730cda test-only, 7e87d6d fix), co-located test per AGENTS.md, no mock.module, comments explain why. One overstrong comment: "the only unanswered match is this suspension's own call" — false for identical duplicates per the probe above.
  • The history-fetch-to-deliver race (timeout landing between the two) predates this diff; unchanged.
  • DO NOT MERGE per direction; Linear stays In Progress.

@TheGreatAxios

Copy link
Copy Markdown
Collaborator Author

Follow-ups addressed in a8ee35b (not merged; Linear stays In Progress):

  • Duplicates covered/documented: two keeper tests for identical name+args twins — sibling-timeout still delivers (correct), and own-timeout-with-unanswered-twin delivers (known exact-one limitation, locked with a comment so a future lookup fix can flip it to a drop). The overstrong "only unanswered match" comment is softened and the limitation is documented on parkedCallIdFromHistory.
  • Seam justified, not wired: resolveParkedCallId stays unwired at both callers by intent — the vendored reactor surface ({ start, deliver, abort }) exposes no correlationId-to-call lookup and the suspension snapshot carries no call id, so there is nothing to wire without inventing a vendored API. Documented on the seam plus one-line notes at src/exec/runner.ts and src/tui/runner/session.ts call sites.
  • Warn + comment fixed: the settled scan now returns the matched timeout call id and the late-decision warning logs correlation + timeoutCall + outcome, so fallback drops stay attributable.

Verification: bun test src/session/approval-resume.test.ts — 5 pass, 0 fail. bun run check — exit 0 (lint, typecheck, build, 7302 tests / 0 fail across 501 files).

@TheGreatAxios

Copy link
Copy Markdown
Collaborator Author

Critic confirmation · a8ee35b resolves the follow-ups

Re-reviewed the fix commit against the three non-blocking notes; all three are addressed.

Verified

  • src/session/approval-resume.test.ts — both duplicate-args keeper tests present and passing: sibling-timeout delivers, own-timeout-with-unanswered-twin delivers (known exact-one limitation, locked with a comment). bun test src/session/approval-resume.test.ts — 5 pass, 0 fail.
  • src/session/approval-resume.ts (resolveParkedCallId seam) — documented as heuristic-only in production with the reason (vendored reactor exposes no correlationId-to-call lookup; snapshot carries no call id), plus one-line notes at both call sites (src/exec/runner.ts, src/tui/runner/session.ts). Unwired by intent, not by omission.
  • Warn attribution — the settled scan now returns the matched timeout call id and the late-decision warning logs correlation + timeoutCall + outcome, so fallback drops stay attributable. The overstrong "only unanswered match" comment is softened and the twin limitation is documented on parkedCallIdFromHistory.

No new findings. Still DO NOT MERGE per direction; Linear stays In Progress.

@TheGreatAxios
TheGreatAxios merged commit 3eff6f9 into main Sep 14, 2026
9 checks passed
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