Repository navigation
[split-1066] U3 - feat(tools): onParameterParseFailure teardown boundary #1936
Copy link
Copy link
Open
Description
Unit U3 of the PR #1066 split (4/6).
Split plan: #703
PR: #1931
Content source of record: tag pr1066-source = 46d1d218701f0ce2d675b1b315489bacb6b0f77d (easonLiangWorldedtech/Zoo-Code).
Unit contract
BaseTool.onParameterParseFailure() teardown boundary plus the WriteToFileTool override: when the final block fails to parse, execute() never runs, so this boundary finalizes the open partial ask, restores the diff document, releases the per-task state, and reports the earlier streaming failure instead of the incidental parse error.
Why this unit exists on its own
Single provider group (BaseTool boundary + one tool override) + single gate scope.
Boundary
- base:
4b23b6a270aa(previous unit head, U5) - head:
e3c10401f760 - chain: U5 -> U3 -> U6
- merge order is fixed: U12 -> U4 -> U5 -> U3 -> U6 -> U7/FINAL; the FINAL integration PR (fix(write-to-file): clean partial state on missing-param and rooignore denial + integrate the #1066 split series (6/6 + FINAL) #1928) is the sole merge target.
Files and budget
src/core/tools/BaseTool.ts+36/-3 — byte-identical to sourcesrc/core/tools/WriteToFileTool.ts+22/-0 — content subset of sourcesrc/core/tools/__tests__/writeToFileTool.spec.ts+192/-0 — content subset of source- budget: 253 a+d / 3 files — UNDER-SOFT
- mutation gate: 30 changed executable lines (15 BaseTool + 15 WriteToFileTool) — under the 500 cap; valid mutants for the whole PR are 116 / 400, so no directive was added by this unit.
Verification (must pass by once, binary)
zdt split verify --contract U3.json --worktree <wt> --head e3c10401f760— PASS (every changed file is a content subset of the source of record, or an explicitly sanctionedallowNewfile).- Tests: 243 passed / 5 skipped, exit 0 (narrowest relevant suites:
Task.spec.ts,writeToFileTool.spec.ts,writeToFileTool-partial-state-cleanup.spec.ts,removeClineFromStack-delegation.spec.ts,presentAssistantMessage-custom-tool.spec.ts). - Changed-line coverage: 20 covered / 0 uncovered — PASS.
- ESLint
--prune-suppressions --max-warnings=0: clean on every touched file; suppression counts unchanged. - No
.changesetfile, no CHANGELOG edit (AGENTS.md).
Deviations recorded
- None.
- 1 Stryker directive in the diff (
hasPathStabilizedForTask,// Stryker disable next-line ConditionalExpressionwith a concrete reason: the!== undefinedclause is not distinguishable by any test). It belongs to U4's content and travels with it.
Reproduce
git fetch https://github.com/easonLiangWorldedtech/Zoo-Code p1066/u3-parse-failure-boundary
node zdt.mjs split verify --contract U3.json --worktree <wt> --head e3c10401f760
node zdt.mjs split measure --worktree <wt> --base 4b23b6a270aa --head e3c10401f760
pnpm --dir src exec eslint --prune-suppressions --max-warnings=0 <touched file>
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
easonLiangWorldedtech commentedon Oct 10, 2026
Pending row: cancellation-aware diff open
The review row on PR 1931 asks that
DiffViewProvider.open()andopenDiffEditor()become cancellation-aware. Today a task disposed whileopen()is in flight leaves the pending open and its deferred-scroll timeout running, so a later partial delta can resurrect a diff view for a task that no longer exists.Acceptance:
open()and asserts no diff view survives and no timeout fires afterwards.This unit goes first; the change then ports in merge order 1928, 1931, 1929, 1930, 1932.
easonLiangWorldedtech commentedon Oct 10, 2026
Defect: the rollback guard silently skips the
saveDirectlybranch, andreset()forgets instead of cleaningFound while checking the coupling with U6 (#1932), at U3 head
5ff7bea73. Both halves are U3 code:the guard came in with
5c0f21219and the swallowing caller with2a9bfabfb.1. A guard keyed on a flag only one path sets.
DiffViewProvider.revertChanges()opens withif (!this.relPath || !this.isEditing) return, butisEditing = trueis assigned only insideopen(). ThePREVENT_FOCUS_DISRUPTIONbranch never callsopen(), so in that branchrevertChanges()early-returns and nothing rolls back: the directories handed over byadoptCreatedDirs()stay on disk and the filesaveDirectly()wrote stays written. Worse, thecaller
WriteToFileTool.revertDiffChangesBeforeReset()still returnstrue, so the teardown isreported as complete and
reportRevertFailure()never fires. A swallowed failure is worse than areported one. A guard condition must be proven reachable from every entry point; using a flag
that only one path sets turns the guard off for the other path.
2.
reset()forgets instead of cleaning.reset()setscreatedDirs = []andadoptedCreatedDirs = []without removing anything from disk, so "early return + reset" leavesthe preflight-created directories on disk permanently: after the reset no code path knows them.
Acceptance criteria
experiments: { preventFocusDisruption: true }, a failed or deniedsaveDirectlywriteremoves the directories this call created and unlinks a file it created (modify: content
restored) - the rollback works on the branch that never opened a diff view.
must not be conflated with "silently skipped", and a skipped rollback must reach
reportRevertFailure().reset()may only drop the directory list after the directories are gone, or the caller mustroll back before it resets - proven by a test that fails when
reset()runs first.passes today and proves nothing about this defect.
Ported from the retired fork tracking item 6093538947. Timing: next legitimate push of #1931 (a
review in flight blocks the push, not this item).
easonLiangWorldedtech commentedon Oct 10, 2026
Follow-up on new-file rollback ownership in unit U3 (pull 1931).
adoptCreatedDirs closes the rollback gap for the execute() preflight only: the streaming path still relies on DiffViewProvider.open() recording the directories it creates itself, and nothing asserts both entry points. A converging guard that only has one writer silently fails on the other path.
Acceptance: two tests, one per entry point (the execute() preflight, and open() during a partial stream), each proving that a rolled-back new-file write removes every directory that write created and nothing it did not create.
Owner: unit U3. Scheduled to ride the next legitimate push of that unit.
easonLiangWorldedtech commentedon Oct 10, 2026
Contingency note for unit U3 (pull 1931).
A discarded change is kept on disk rather than deleted: .tmp-cr-audit/p1066-u3-cancellation.patch, 99 additions and 11 deletions, which makes open() and openDiffEditor() cancellation-aware. It was reverted only because the checklist row it answered belonged to an older head, not because the change was wrong.
Acceptance: if a maintainer asks for cancellation-aware diff opening, apply the patch on the current head, re-run the DiffViewProvider spec and its negative controls, and re-measure how many tests each control reddens - do not re-derive it.
Owner: unit U3.