Skip to content

Fix delegation link loss across interrupt/resume; type NewTaskTool provider call - #18

Merged
easonLiangWorldedtech merged 1 commit into
main-task-treefrom
pr-9-delegation-link-resume
Aug 16, 2026
Merged

Fix delegation link loss across interrupt/resume; type NewTaskTool provider call#18
easonLiangWorldedtech merged 1 commit into
main-task-treefrom
pr-9-delegation-link-resume

Conversation

@easonLiangWorldedtech

Copy link
Copy Markdown
Owner

Fix delegation link loss across interrupt/resume + type NewTaskTool provider call

Fixes the remaining PR-6 problems A, C and D (Problem B was already fixed by #16).

Problem A/C — resumed subtask's result never routes back to its parent

When a delegated child is interrupted (cancelTask / evictCurrentTask), the parent's awaitingChildId link is preserved only while the parent is still delegated. After a crash or resume cycle the parent can be left active with no awaitingChildId, so when the user resumes the child, AttemptCompletionTool refuses to route its completion back (it requires parent.awaitingChildId === this child). The result: a resumed subtask's result is silently stranded and never reported to the parent.

Fix: re-establish the link in createTaskWithHistoryItem — the common funnel for every resume path (showTaskWithId, cancel-rehydrate, reopen) — when resuming an interrupted child. New private helper reestablishDelegationLinkOnResume transitions a demoted active parent back to delegated, gated so it:

  • skips children whose delegation was intentionally severed (cancelledDelegationChildIds),
  • never clobbers a live delegation to a different child,
  • only performs the legal active → delegated transition (the sole valid path in VALID_TRANSITIONS).

Non-fatal: any failure is logged and the resume proceeds without the link. Because AttemptCompletionTool already accepts an active parent whose awaitingChildId matches, routing (Problem C) works automatically once the link is restored — no approval-stranding change needed.

Problem D — remove as any in NewTaskTool

task.providerRef is a WeakRef<ClineProvider>, so after the null-check provider is already typed ClineProvider. The (provider as any).delegateParentAndOpenChild(...) cast was unnecessary; it is now a typed method call. This removes the last as any in NewTaskTool.ts, so its stale no-explicit-any suppression entry is dropped from eslint-suppressions.json (suppression counts never increase).

Tests

4 focused regression tests for reestablishDelegationLinkOnResume:

  • link restored on resume of an interrupted child with a demoted parent,
  • no-op when already delegated to the same child,
  • never clobbers a live delegation to another child,
  • no reattach for intentionally-severed children.

Verification

  • pnpm run check-types — 11/11 tasks successful
  • Related suites (flicker-free-cancel, taskHistory, TaskHistoryStore.reconciliation, attemptCompletionTool, newTaskTool, newTaskInlineFlatten) — all pass
  • Per-file eslint on touched files — clean; eslint-suppressions.json diff is a single 5-line deletion of the now-stale entry

…ovider call

## Problem A/C — delegation link lost across interrupt/resume

When a delegated child is interrupted (cancelTask / evictCurrentTask), the parent's
`awaitingChildId` link is preserved only while the parent is still `delegated`. After a
crash or resume cycle the parent can be left `active` with no `awaitingChildId`, so when
the user resumes the child, AttemptCompletionTool refuses to route its completion back
(it requires `parent.awaitingChildId === this child`). The result: a resumed subtask's
result is silently stranded and never reported to the parent.

Fix: re-establish the link in `createTaskWithHistoryItem` (the common funnel for every
resume path) when resuming an *interrupted* child. New private helper
`reestablishDelegationLinkOnResume` transitions a demoted `active` parent back to
`delegated`, gated so it:
  - skips children whose delegation was intentionally severed (`cancelledDelegationChildIds`),
  - never clobbers a live delegation to a different child,
  - only performs the legal `active -> delegated` transition.
Non-fatal: any failure is logged and the resume proceeds without the link. Because
AttemptCompletionTool already accepts an `active` parent whose `awaitingChildId` matches,
routing (Problem C) works automatically once the link is restored.

## Problem D — remove `as any` in NewTaskTool

`task.providerRef` is a `WeakRef<ClineProvider>`, so after the null-check `provider` is
already typed `ClineProvider`. The `(provider as any).delegateParentAndOpenChild(...)`
cast was unnecessary; it is now a typed method call. This removes the last `as any` in
NewTaskTool.ts, so its stale `no-explicit-any` suppression entry is dropped from
eslint-suppressions.json (count never increases).

## Tests

Added 4 focused regression tests for `reestablishDelegationLinkOnResume` covering: link
restored on resume of an interrupted child with a demoted parent; no-op when already
delegated to the same child; never clobbers a live delegation to another child; and no
reattach for intentionally-severed children.
@easonLiangWorldedtech
easonLiangWorldedtech merged commit 6c69041 into main-task-tree Aug 16, 2026
12 checks passed
@easonLiangWorldedtech
easonLiangWorldedtech deleted the pr-9-delegation-link-resume branch August 16, 2026 13:58
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