Skip to content

feat(checkpoints): wire change journal into write/edit/apply-patch tools (B2 v2-4, epic #1375) - #48

Open
easonLiangWorldedtech wants to merge 1 commit into
feat/fws-v2-3-journal-corefrom
feat/fws-v2-4-journal-wiring
Open

feat(checkpoints): wire change journal into write/edit/apply-patch tools (B2 v2-4, epic #1375)#48
easonLiangWorldedtech wants to merge 1 commit into
feat/fws-v2-3-journal-corefrom
feat/fws-v2-4-journal-wiring

Conversation

@easonLiangWorldedtech

Copy link
Copy Markdown
Owner

What

v2-4 of the B2 change-journal rebuild (epic #1375): wires the change journal (v2-3) into the three write-family toolswrite_to_file, edit_file, apply_patch. This is the second part of the split of the reviewed B2 content (legacy #1406, 1924 lines standalone → v2-3 core, PR #47 + v2-4 tool wiring).

  • src/core/tools/WriteToFileTool.ts — the approval-diff stats (computeDiffStats on the sanitized unified diff) are hoisted into approvalDiffStats, shared by both the approval message and the new journal entry; the existing awaited checkpointSave now passes { path: relPath, operation: fileExists ? "update" : "create", diffStats }.
  • src/core/tools/EditFileTool.ts — the existing per-write checkpointSave now passes { path: relPath, operation: isNewFile ? "create" : "update", diffStats }.
  • src/core/tools/ApplyPatchTool.ts (the bulk):
    • The file handlers (handleAddFile / handleDeleteFile / handleUpdateFile) return ApplyPatchFileOpResult { succeeded, wrote } instead of a boolean — a no-op update succeeds with wrote: false, so nothing is journaled that was never written.
    • The patch loop collects the changes that actually wrote and passes one journal entry per written file (all referencing the single whole-patch checkpoint) to checkpointSave; a move-type change uses its final location (movePath ?? path).
    • Behavioral fix 1 — partial patch flush: a rooignore failure inside the loop now breaks (failing the patch) instead of returning — files already written by earlier hunks of the same patch still receive the checkpoint, journal entry, and change card, and the consecutive-mistake counter is no longer wrongly reset.
    • Behavioral fix 2 — mistake counter: task.consecutiveMistakeCount = 0 now only happens after a fully successful patch (previously it was reset unconditionally), so the auto-approval safety net still engages across consecutive partially-failed patches.
    • Behavioral fix 3 — failed move source deletion: when the source unlink after a move copy fails, the tool now reports the failure (error say + tool result + mistake counter + recordToolError) and returns { succeeded: false, wrote: true } — the destination file that was written is still checkpointed and journaled (previously the error was only console.errored and the move reported success).
  • SpecsapplyPatchTool.execute.spec.ts, editFileTool.spec.ts, writeToFileTool.spec.ts updated: the per-write suites assert the journal entry shape (path / operation / diffStats) and the new partial-flush + move-failure behaviors. New mutation-killing assertions: a fully successful add or delete resets the mistake counter (1→0), a first-hunk access denial records no checkpoint, the failed-move path increments the counter (1→2) and reports the exact error message, and both WriteToFileTool approval branches thread the exact diffStats object into the approval message (asserted by parsing the askApproval JSON payload).

Gates (local, pre-push)

  • vitest: applyPatchTool.execute / applyPatchTool.partial / editFileTool / writeToFileTool / index.checkpointJournal → 109 passed | 5 skipped (5 files).
  • eslint: --max-warnings=0 on all six changed files (full zoo-code lint via pre-commit); eslint-suppressions.json counts unchanged (346 entries).
  • pnpm check-types: clean.
  • Stryker (scripts/stryker-diff.mjs ci, base 4e95e380e = v2-3 head, head 6c2ac075c): 0 surviving / 0 uncovered of 99 changed-code mutants (109 total, 10 excluded by directive — see below).

Equivalent mutants (10 directives)

The ten return { succeeded: false, wrote: false } failure sentinels in ApplyPatchTool.ts are each excluded with a scoped // Stryker disable next-line ObjectLiteral directive carrying the concrete reason. They are equivalent mutants: succeeded is consumed only inside the logical && that propagates failure and wrote only inside if (result.wrote), so undefined && xfalse && x and the emptied object {} is behaviourally identical at every consumption site. The remaining changed-code mutants (16) are pinned by the new spec assertions above and killed by the Stryker run.

Line budget

Standalone diff vs the PR base (4e95e380e): 567 lines (512+/55-, 6 files) — over the 400-line soft design target. Rationale: the three tools are one logical unit (the same journal-wiring contract at each write call site), and the ApplyPatchTool change is dominated by the handler return-type refactor (boolean{ succeeded, wrote }) that touches every return site of the three handlers; per-tool PRs would fragment one design decision across three stacked reviews. The spec additions are the mutation-killing assertions documented above; the remaining additions are the ten equivalent-mutant directive lines.

Stacking / merge order

Base: feat/fws-v2-3-journal-core (PR #47). After Zoo-Code-Org#1404 (B1), #47 (v2-3), and this PR land on main, the base switches to main — the diff is identical either way.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

Review status

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

Current step: Required CI passed. Waiting for automated review of the latest commit.

If automated review does not start, a maintainer must restart it.

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

@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 5, 2026
easonLiangWorldedtech pushed a commit that referenced this pull request Sep 6, 2026
…on hook, changeCardDetail setting (B3a v2-7, epic Zoo-Code-Org#1375)

Change-card pipeline on the extension host for each completed tool-write step:

- change_card ClineSay + ChangeCardData/ChangeCardFile/ChangeCardDetail schemas (packages/types)
- changeCardDetail user setting (default 'summary') + ExtensionState + ClineProvider getState/getStateToPostToWebview round trip
- buildChangeCardPayload(): reuses the approval diff stats already computed by the tools; auto-approved steps are always downgraded to 'summary'
- checkpointSave emits task.say('change_card', ...) only when a real commit and write info exist; a card failure is logged and never disables checkpoints

Split of the reviewed B3a content (legacy Zoo-Code-Org#1411) - unit 1 of 4 (v2-7). Stacks on v2-4 (PR #48).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-coderabbit Waiting for CodeRabbit to approve the latest commit coderabbit-review-active Required CI passed; CodeRabbit review is active

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants