Skip to content

fix(task): guard saveClineMessages against abandoned tasks (fixes #1021) - #1496

Open
easonLiangWorldedtech wants to merge 6 commits into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:fix/abandoned-subtask-save-race-1021
Open

fix(task): guard saveClineMessages against abandoned tasks (fixes #1021)#1496
easonLiangWorldedtech wants to merge 6 commits into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:fix/abandoned-subtask-save-race-1021

Conversation

@easonLiangWorldedtech

Copy link
Copy Markdown
Contributor

Tracking issue: #1387

Supersedes #1382 (same branch). #1382 was opened on 2026-08-27, before the org's .coderabbit.yaml (introduced in #1433, 2026-08-29) existed on main; its CodeRabbit review session therefore started on the default configuration and cannot submit the formal APPROVED review the review gate requires on a PR head. This PR re-opens the identical change under a fresh review session (head already synced with the org config file).

Summary

Fixes #1021 (part of epic #1375).

Fire-and-forget saveClineMessages() calls could execute updateTaskHistory() after abandonSubtask's atomicUpdatePair() had already cleared parentTaskId/'rootTaskId', silently reattaching the severed parent-child link.

Changes

  • src/core/task/Task.tssaveClineMessages() now checks this.abandoned before updateTaskHistory() and returns false when the task was abandoned. This catches both the explicit abort save and any in-flight fire-and-forget saves (the two un-awaited saveClineMessages().catch(...) call sites).
  • Per-task message persistence is unaffected: saveTaskMessages() still runs before the guard; only the (stale) history-item update is skipped, which is exactly the value that would reattach the severed link.
  • .coderabbit.yaml — synced from upstream main so the review session picks up the org's CodeRabbit configuration (reviews.request_changes_workflow).

Provenance

This is the minimal upstream-main form of the fix developed on the feature/local-usage-stats branch (commit 1d1eb915e, "fix(task): guard saveClineMessages against abandoned tasks to prevent race in abandonSubtask"). That commit also carried formatting changes for usage-stats code that is not in main (the dashboard feature ships separately in #1225), so those hunks are deliberately excluded here — the behavioral fix is the guard itself.

Test

  • Regression test in Task.spec.ts (saveClineMessages abandoned guard (#1021)): an abandoned task's saveClineMessages() persists messages (saveTaskMessages called once) but never calls updateTaskHistory.
  • Non-abandoned control and in-flight deferred-save cases covered; all 9 guard lines covered per lcov.
  • pnpm --dir src exec vitest run core/task/__tests__/Task.spec.ts → 101/101 passing.
  • ESLint clean; no suppression count changes.

…-Code-Org#1021)

Fire-and-forget saveClineMessages() calls could execute updateTaskHistory() after abandonSubtask's atomicUpdatePair() had already cleared parentTaskId/rootTaskId, silently reattaching the severed parent-child link.

Check this.abandoned before updateTaskHistory() to catch both the explicit abort save and any in-flight fire-and-forget saves. Per-task message persistence is unaffected: saveTaskMessages still runs, only the (stale) history-item update is skipped.

This is the minimal upstream-main form of the fix developed on the local-usage-stats branch (commit 1d1eb91); that commit's surrounding usage-stats changes are not part of main and are excluded. Regression test in Task.spec.ts: an abandoned task's saveClineMessages() persists messages but never calls updateTaskHistory().
Per CodeRabbit review: document why the provider test double uses the as unknown as MockedClineProvider double assertion (Task receives a full ClineProvider at runtime; this focused unit test only exercises a few methods) — same pattern and rationale as the existing Subtask Rate Limiting block.
Per CodeRabbit review on PR Zoo-Code-Org#1382, the focused task-history tests used a provider double without taskHistoryStore, so provider?.taskHistoryStore.get() threw before the guard was evaluated and the catch returned false - the assertions passed without ever exercising updateTaskHistory.

Stub taskHistoryStore.get() on the provider double (shared makeMockProvider helper) so execution reaches updateTaskHistory; add a non-abandoned control asserting updateTaskHistory() runs and the item is written as-is (covers the guard false branch); add an in-flight save test where saveTaskMessages() is deferred, the task is abandoned mid-save, and the guard must still skip the history update when the save resolves. All PR-changed lines in Task.ts (guard at 1138-1140) are now 100% covered on lines and branches: true branch hit twice (abandoned + in-flight), false branch once (control).
Branch base 78c712a predates Zoo-Code-Org#1433 (efc30cf, 2026-08-29), which added the CodeRabbit config to main. Without it, CodeRabbit reviews this head with defaults (request-changes workflow disabled) and can only submit COMMENTED reviews; it never submits the APPROVED review that the PR review gate requires. Sync the config (incl. Zoo-Code-Org#1490) so reviews on this head use the org adversarial review profile and the formal review workflow, letting the gate advance.
@coderabbitai

coderabbitai Bot commented Sep 3, 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Team

Run ID: 9c775915-d56b-4c03-9906-0dc283592350

📥 Commits

Reviewing files that changed from the base of the PR and between 0d937c0 and d48f46d.

📒 Files selected for processing (2)
  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.spec.ts

Included review availability: Your plan provides up to 4 included reviews per hour; 1 remains after this review.

📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (5)
Check persistence and lifecycle invariants: awaited atomic writes, rollback or explicit partial-failure behavior, cross-window state consistency, stale listeners/watchers, cancellation, idempotency, and safe restart/resume without lost or d...

⚙️ CodeRabbit configuration file

Files:

  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.spec.ts
Require regression coverage at the lowest valid harness with behavior-focused assertions, including relevant negative, error, false/unset, and boundary cases.

⚙️ CodeRabbit configuration file

Files:

  • src/core/task/__tests__/Task.spec.ts
Check strict typing and exhaustive behavior across normal, boundary, error, cancellation, retry, and compatibility paths.

⚙️ CodeRabbit configuration file

Files:

  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.spec.ts
Verify extension/webview contracts, cancellation and error propagation, VS Code lifecycle correctness, and behavior under retries and partial failure.

⚙️ CodeRabbit configuration file

Files:

  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.spec.ts
Act as an adversarial second-opinion reviewer.

⚙️ CodeRabbit configuration file

Files:

  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.spec.ts
🔇 Additional comments (2)
src/core/task/Task.ts (1)

1247-1255: LGTM!

src/core/task/__tests__/Task.spec.ts (1)

16-16: LGTM!

Also applies to: 31-33, 4304-4449


📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Prevented abandoned tasks from saving outdated task history identifiers.
    • Abandoned tasks can still save messages without updating their task history.
    • Active tasks continue to update task history as expected.

Walkthrough

saveClineMessages now skips task history updates for abandoned tasks while still saving messages. Tests cover abandonment before saving, abandonment during an in-flight save, and successful history updates for active tasks.

Changes

Abandoned task save guard

Layer / File(s) Summary
Guard history updates during abandoned task saves
src/core/task/Task.ts, src/core/task/__tests__/Task.spec.ts
saveClineMessages returns false and skips updateTaskHistory when the task is abandoned. Tests verify this behavior before and during message persistence, and verify history updates for non-abandoned tasks.

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

Merge Risk: ⚪ Minimal · up to d48f4

Abandoned subtasks continue to save messages but no longer restore stale parent or root task links in history. The timing-sensitive cases and normal active-task behavior are covered, with no remaining merge-blocking risk identified.

🚥 Pre-merge checks | ✅ 6 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #1021 by checking the abandoned state before updateTaskHistory while preserving saveTaskMessages. Tests cover explicit abort saves, in-flight saves, and non-abandoned tasks.
Out of Scope Changes check ✅ Passed The summarized code and test changes are focused on the abandoned-task history race described in issue #1021. No unrelated code changes are identified.
Regression Evidence ✅ Passed Focused unit coverage exists in src/core/task/__tests__/Task.spec.ts for the changed saveClineMessages() behavior. It verifies that an abandoned task still calls saveTaskMessages(), returns `fal…
Trust And Persistence Invariants ✅ Passed PASS. The changed runtime path only adds an this.abandoned check in Task.saveClineMessages() after the awaited saveTaskMessages() and metadata work, and before updateTaskHistory(). When `aband…
Title check ✅ Passed The title clearly and concisely identifies the main change: guarding saveClineMessages against abandoned tasks. It matches the implementation and linked issue.
Description check ✅ Passed The description explains the issue, implementation, affected behavior, test coverage, and validation results. It does not reproduce the template headings or completed pre-submission checklist, but it …
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Review status

Thanks for contributing. This comment tracks the review sequence and the next action.

Current step: Awaiting fresh human maintainer or CODEOWNER approval.

Automated review is complete for the latest commit but does not replace human approval.

Review-state labels are managed by this workflow; do not edit them manually.

@easonLiangWorldedtech

Copy link
Copy Markdown
Contributor Author

@coderabbitai approve

coderabbitai[bot]
coderabbitai Bot previously approved these changes Sep 3, 2026
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Comments resolved and changes approved.

@github-actions github-actions Bot added awaiting-maintainer CodeRabbit approved; waiting for a human maintainer has-conflicts PR has merge conflicts with the base branch and removed awaiting-maintainer CodeRabbit approved; waiting for a human maintainer has-conflicts PR has merge conflicts with the base branch labels Sep 3, 2026
…sk-save-race-1021

# Conflicts:
#	.coderabbit.yaml
@github-actions github-actions Bot removed the has-conflicts PR has merge conflicts with the base branch label Sep 4, 2026
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@easonLiangWorldedtech

Copy link
Copy Markdown
Contributor Author

@coderabbitai approve

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

CodeRabbit chat interactions are restricted to organization members for this repository. Ask an organization member to interact with CodeRabbit, or set chat.allow_non_org_members: true in your configuration.

@github-actions github-actions Bot added coderabbit-review-active Required CI passed; CodeRabbit review is active awaiting-coderabbit Waiting for CodeRabbit to approve the latest commit labels Sep 4, 2026
@github-actions github-actions Bot removed the coderabbit-review-active Required CI passed; CodeRabbit review is active label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-maintainer CodeRabbit approved; waiting for a human maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(task): guard saveClineMessages against abandoned tasks to prevent race in abandonSubtask

2 participants