Repository navigation
ADFA-6835 | Show edit_file's closest lines and report a change that was never made - #157
Conversation
A model that guesses old_string and is told only "not found" (or "identical to new_string") guesses again. The rejection now lists up to five lines of the file that share the most words with the guess, exact text with spaces visible. An identical-strings rejection is decided after the file is read, so it can carry the lines too. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAaJxvRXKRYkgiDqwGQ
…one" When a run answers while its last file change failed (not user-denied) and none has succeeded since, it is told once that nothing was changed and to read and retry or say so. Answering again ends the run ABANDONED, not COMPLETED. The wording is in agent_loop.yml. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAaJxvRXKRYkgiDqwGQ
After being told its edit failed, a model re-read the file and the repeat-after-success rule then ended the run COMPLETED with its false "has been changed" reply standing. Now a run that ends with a failed change outstanding, by answering twice or by repeating a look, is ABANDONED and shows a notice that the change was not made. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAaJxvRXKRYkgiDqwGQ
Daniel-ADFA
left a comment
There was a problem hiding this comment.
IMPORTANT
- AgentLoop.kt:251 - one run-wide flag; the last result in a batch wins
- AgentLoop.kt:252 - the unapplied-write warning is never re-armed
- AgentLoop.kt:311 - prose answers skip the unapplied-write guard
- AgentLoop.kt:352 - any mutating tool's failure is reported as a failed file edit
- AgentLoop.kt:353 - a denied retry leaves the flag set
Checked by reading the code at f4e3196; not compiled or run. This repo has no written approve/request-changes rule, so the default applied.
Review of #157 found six ways the run-wide unapplied-write flag gave a false result: - A success on one file cleared a failure on another in the same batch. - The warning was never re-armed, so a second failure got none. - A prose answer skipped the check; only "respond" was guarded. - Any project-changing tool set the flag, so a failed shell command or add_dependency was reported as a failed file edit. - The same signal cleared it, so a shell `cat` hid a failed edit. - A user denial left it set, sending the model back to the change the user had refused. Failures are now kept per path, and only from the tools that write a file's content (edit_file, create_file, update_file; new ToolHandler.writesFiles). A success or a denial clears that path; a call that names no path is cleared by any later successful write. The warning re-arms once nothing is outstanding, and prose answers get the same check as "respond". The prompt and the user notice no longer say that nothing at all was changed. Each new AgentLoopTest case fails against the previous AgentLoop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VKUthHVokuWKgP3ACLBii7
…r the run ends An independent review of #157 at aaecc13 found that the per-path tracking could still report a change that was made as not made, or let a half-made one pass: - A failure was keyed by the path as typed, so a retry under the path edit_file corrected it to never cleared it. Writes are now keyed by the file (PathGuard.writeKeyOf): its canonical path, or its bare name when the path named no file. - A correction or an approval timeout counted as a failed change, so the run was sent back to a change the user had steered away from. These now return ToolResult.notApproved, settled like a denial. - A success cleared every failure on its file, even one beside it in the same batch. A success now settles only failures from earlier batches; the same call twice in one batch is not counted as failed. A success in a later batch is still taken for the redo, since which change a retry redoes cannot be read off its text. - After the warning, prose such as "I will now redo it" ended the run; it now gets the unfinished-turn nudge first. - A repeated look ended the run without the warning, and ignored a null unappliedWriteTurn. It now warns first, and does nothing when the check is off. - Runs that stopped as UNPARSABLE, CYCLING, REPEATED or MAX_ITERATIONS never told the user. One UnappliedWrites.warn/stop pair now serves every ending. The closest-lines hint now scores whole lines and marks one cut at 200 characters, shows a tab as \t, matches words in any script, and scores at most 32 words of old_string. 17 of the 18 new tests fail with the old behaviour restored; the other guards against matching two files that share a name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAaJxvRXKRYkgiDqwGQ
From a second independent review, of 6a93052: - writeKeyOf corrected a missing path to the one project file of that name for every write tool, but only edit_file does that. A failed create_file on build/Main.kt was keyed to app/src/Main.kt, so a retry that created lib/Main.kt left it outstanding: a made change reported as not made. New ToolHandler.correctsPaths, true only for edit_file; the other tools fall back to the bare name, and skip the project walk the correction costs. - A path with no file name ("app/") got the empty key that marks a call naming no file, which any later write settles. It now keeps the path. - NearMatchLines could cut a line between the two halves of a surrogate pair; it now stops one character short. - The unapplied-write trace and its event's KDoc said "answered", though a repeated look now triggers it too. Each of the four new tests fails with the old behaviour restored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAaJxvRXKRYkgiDqwGQ
… by its path From a third independent review, of b869b92: - The warning asks the model to read the file again, but a read it had just taken counted as a repeated look and ended the run before it could redo the change. After the warning, the guard lets the last batch run once more; a second repeat still ends the run. - An approval timeout is a plain failure again. Nobody decided against the call, so a failed change it was redoing stays outstanding. A correction is still settled like a denial. - A write that already worked, issued again in a later batch, fails because it made the change. It is no longer counted as not made. - create_file and update_file key a failure by the path they were given even when the file does not exist yet, so a write to another strings.xml no longer settles a failed create of values-es/strings.xml. - The empty bare name of a key like app/ no longer settles the failure of a call that named no file. - File keys are looked up only while a failure is outstanding. - The warning says only the failed change was not made, not to redo other changes to that file, and gives each write tool its recovery. The notice says "a file change failed". The README lists the unapplied_write turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAaJxvRXKRYkgiDqwGQ
…d its file, match whole words A write that already worked and fails again was taken for the change already made, even when a different write to the same file came between and may have undone it. It now counts as a failed change then. The files are looked up only for such a call. Recording writes does nothing when the unapplied-write check is off, so no file is keyed. The closest-lines hint matched substrings, so "val" scored a line holding "evaluate". It now matches whole words, as its description says. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAaJxvRXKRYkgiDqwGQ
Fourth independent review (
|
| ID | Finding | Conclusion |
|---|---|---|
| F01 | A later success on a file settles an earlier failed edit on it, even a different change | True and already an accepted limitation. Moved to ADFA-6847 |
| F02 | A repeated call that already worked is never counted as failed, even after another write to its file | True as stated, but the fix misfired and is reverted in 82ed8fa: a write that undid the change would let the repeat succeed, so the rule caught only unrelated edits (fifth review) |
| F03 | The second terminal-tool answer ends the run without calling onFinalAnswer |
True, but it only drops one ANSWER trace line. No change |
| F04 | Recording writes keys files even when the check is off | True, but production always sets the check. Fixed in c1a9810: record returns early |
| F05 | writeKeyOf can walk the project up to twice per failed edit |
True and low. Not measured. No change |
| F06 | Bare-name keys settle across files | True. Moved to ADFA-6847 |
| F07 | The closest-lines hint matched substrings (val scored evaluate) |
True. Fixed in c1a9810: whole words only |
| F08 | The identical-strings check now runs after the read | Deliberate, and the closest lines help exactly there. No change |
| F09 | notApproved duplicates denied |
True and latent: nothing calls copy(denied = ...). Moved to ADFA-6847 |
| F10 | generate_from_template and contributed tools are not tracked |
A scope choice: only edit_file, create_file and update_file are tracked. No change |
c1a9810 adds 4 tests; 3 fail on the old code. Unit-tested only, not run on a device.
Posted by Claude Code for David Schachter.
Plugin review of AI-Core (
|
| ID | Where | Finding | Conclusion |
|---|---|---|---|
| F17 | settings.gradle.kts:31 |
jitpack.io is a dependency repository, but no AI-Core dependency comes from it. All eight are androidx, Material, Kotlin, coroutines, Markwon and Gson, from Google or Maven Central |
Optional one-line removal. It adds a repository to the supply chain for nothing |
| F18 | build.gradle.kts:32 |
The release build is signed with the debug signing config | Not a leaked key. Fine if that is the repo's norm |
| F19 | BuiltInToolHandlers.kt:63-80 |
Class.forName probes of public plugin-API service classes, as a guard for an older host |
Not reflection into IDE internals. A strict reading of 6.5 could still call it Partial |
| F20 | AiCorePlugin.kt:832,853,859 |
Three tooltip buttons link to i/ai-top.html, i/ai-local.html and i/ai-online.html, which are not in this plugin's assets/docs |
Tracked in ADFA-6863. On a phone the buttons could not be reached, and the documentation database shipped with that build lacks all three pages |
Rubric: 6.1 Compatibility, 6.2 Resource discipline, 6.3 Build reproducibility, 6.4 Native binaries, 6.6 HTML documentation, 6.7 Tooltips and in-app help, 6.8 Icons and imagery, and Manifest declarations all Pass. 6.7 has one open item, F20. 6.5 No reflection is Partial (F19). Template thumbnails are N/A.
Not verified: the i/ai-*.html pages (F20), whether getSettingsEntries() needs a manifest key, tooltip wiring on dialogs and fragments, and behaviour on a device.
Posted by Claude Code for David Schachter.
… parts of identifiers and unspaced scripts A repeated write that already worked was counted as failed when another write to its file came between. No write tool deletes a file, so a write that undid the change would have let the repeat succeed. The rule fired only after unrelated edits to the file, and it compared bare file names, so values/strings.xml and values-es/strings.xml counted as one file. It is removed. The closest-lines hint matched only whole words, so `name` missed `app_name` and part of a Chinese phrase missed its line. A word now also matches a part of an identifier, split at `_` and camelCase, and a word in a script written without spaces matches anywhere in the line. `val` still misses `evaluate`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAYjFcUx64N8PMRknzL
Fifth independent review (
|
| ID | Finding | Change in 82ed8fa |
|---|---|---|
| F01 | The new "another write to its file came between" check compared bare file names. So values/strings.xml and values-es/strings.xml counted as one file, and repeating an edit to the first after editing the second ended the run ABANDONED, though both changes were made. This brought back the collision b0a09c4 fixed. |
Gone with F02's rule. A new test covers two strings.xml files in different directories. |
| F02 | The rule itself fired in the wrong cases. No write tool deletes a file, so a write that undid an edit would let the repeat succeed, and the repeat would never reach the rule. It fired only after unrelated edits to the same file, and reported a change that was made as not made. After a repeated create_file, its warning pointed the model at update_file, which would overwrite the model's own later edit. |
The rule is removed. A repeated write that already worked counts as made, as in b0a09c4. The test that asserted the old rule now asserts this. |
| F03 | With whole-word matching, the closest-lines hint missed app_name for a guess of name, and part of a Chinese phrase (我的应用 in 我的应用程序). |
A word now also matches a part of an identifier, split at _ and camelCase. In a script written without spaces, it matches a part of a phrase. val still misses evaluate. There are two new tests. |
The other part of c1a9810 stays: recording writes does nothing when the check is off.
Verified:
- AI-Core
testDebugUnitTest: 1,313 tests, 0 failures. - With
c1a9810's code put back, all 4 new tests fail. addons checkexits 0, andassemblePluginpasses.- Not run on a device: the phone was in use.
@hal-eisen-adfa, you approved before these changes. Could you take another look at 82ed8fa?
Posted by Claude Code for David Schachter.
…file since it worked 82ed8fa counted any failed repeat of a write that had worked as made. A later write to the file can undo the change in a form the repeat cannot find (a whole-file update from a stale read re-indents the old text back), and the run then ended COMPLETED with the model saying "Done" over a change that is not in the file. Three ways of reading the answer off the file's text were each fooled by some edit, one way or the other, so nothing is read off the text now. - edit_file marks an old_string-not-found failure ToolResult.madeIfUnchanged: what its repeat gives once made, if nothing has written the file since. create_file marks an existing file ToolResult.alreadyMade: no write tool deletes one, so a create that worked stays made. - AgentLoop excuses a failed write only when it repeats a change that worked this run, the same change (ToolRouter.changeOf: the tool and its declared changeArgs, read through its argument aliases) to the same file (ToolResult.file, the canonical path the tool resolved), and either alreadyMade, or madeIfUnchanged with no successful write to that file since and no write naming no file or other project change, such as a shell command, since. Anything else counts, and the run is told to look. The cost: a repeat after the model itself changed the same file again is reported as not made. - The file-writing tools report ToolResult.file on success. A change is keyed once, when it worked, so a failure no longer walks the project for each earlier success. - The closest-lines hint gains tests for whole-identifier ranking, an acronym split from the word after it, and katakana. Tests: a stale rewrite between, another write to the file between, a shell command between, a write naming no file between, a create's certain case, a repeat failing for another reason, a first attempt, the same change to another file, a respelled path, each change keyed once; the handlers' flags and resolved files (disk and editor paths); ToolRouter.changeOf with aliases and ignored arguments; create_file's change key. Each of 9 mutants of the rule fails the test named for it. Probes from four independent reviews, driving the loop with the real handlers, all pass but three: a repeated insert applying twice (ADFA-6879), the repeat after the model's own later edit (by design), and a repeat retyped with other indentation, which keys as another change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAYjFcUx64N8PMRknzL
a8790c5 to
ddbd07e
Compare
… two costs A review of ddbd07e found the rule sound for every write the loop sees, and its tests short of it: - AgentLoopFileToolsTest drives the loop with the real edit, update and create tools through a ToolRouter, as ChatViewModel wires it: a stale rewrite through another spelling of the path, in the same batch, and to a file open in the editor each leave the repeat reported not made; a repeat in the same batch, or after an update to another file, is taken for made; the same create to another existing file counts. Six mutants the suite missed (update_file's file, canonical paths in the flags, the key's file half, the latest success of a redone change) now fail a test. - The stale-rewrite loop test uses the flag edit_file now returns; the handler flag tests spell their paths with ./, so a non-canonical file fails them; a redone change is keyed at its latest success. - AgentLoop's KDoc states both costs: any project change that names no file, even a read-only shell command or MCP tool, makes a later made repeat count; and a create's repeat is excused whatever was written to the file since. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh2DAYjFcUx64N8PMRknzL
What changed since
|
| Case | Taken for made when |
|---|---|
edit_file "old_string not found" (madeIfUnchanged) |
The same change to the same file worked earlier this run, and nothing has written that file since. A shell command, an MCP tool, or a write naming no file counts as a write to every file. |
create_file on an existing file (alreadyMade) |
The same create worked earlier this run, whatever came since. No write tool deletes a file. |
| Anything else | Never. It counts as a change not made, and the run is told to look. |
"Same change" is ToolRouter.changeOf: the tool and its declared changeArgs, read through its aliases, so replace_all or an extra key doesn't matter. "Same file" is the canonical path the tool reports in the new ToolResult.file.
Accepted costs. Both errors point toward telling the user to check, never toward a false "done":
- A repeat after the model changed the same file again, or after any shell command or MCP tool, is reported as not made. That includes a command that only reads, like
cat. - A repeated create is taken for made even if the file was rewritten since.
88230c5: tests. AgentLoopFileToolsTest drives the loop with the real edit, update and create tools through a ToolRouter, as ChatViewModel wires it. It covers a stale rewrite through another spelling of the path, in the same batch, and to a file open in the editor; a repeat in the same batch; an update to another file; and the same create to another existing file.
Verified: 1,339 AI-Core tests pass. Every mutant of the rule, its flags and its key fails a test. assemblePlugin and addons check pass. Probes from the reviews, which drive the loop with the real tools, all pass except the three tracked or accepted cases below. Not run on a device yet. The phone has been in use.
Tracked separately:
- ADFA-6878: gaps in the closest-lines hint for CJK text and digit boundaries.
- ADFA-6879: a repeated insert edit writes its line twice. This predates
82ed8fa. - ADFA-6880: MCP tools that declare
readOnlyHintshouldn't count as writes.
Posted by Claude Code for David Schachter.
|
Review of
|
|
Thanks, @hal-eisen-adfa. I checked each finding against the head ( F01 (Med), fix in this PR. F03 (Low), fix in this PR. A failed call from a tool that changes the project counts as a possible write. This errs toward telling the run, the safe direction. F02, F04, F05 (Low), documented, not fixed. A still-running shell command, edits the user makes outside tool calls, and a contributed tool that mis-declares itself Tests will pin F01 and F03. |
Summary
Decision (2026-10-29): for the 1.5B on-device model, an honest "the change was not made" is the accepted outcome; ADFA-6835 closes when this merges. Whether a larger model (3B) does the edit is measured separately in ADFA-6839.
ADFA-6835. This does not make the on-device model complete the edit (see "Measured"); it makes the failure show the model what to copy, and stops the run reporting a change that never happened. Eight commits, one per behaviour, the last five from review:
4ababd1). Whenedit_filerejects an edit as "old_string not found" or "identical to new_string", the message now lists up to five lines of the file that share the most words with the guess: line number and exact text between quotes, trailing spaces included. The identical-strings check moved to after the file is read so it can carry the lines too (a missing or protected path is now reported before it). NewNearMatchLines; it works by shared words, never regex. Model-independent, so every backend gets it.0ea705d). If a run answers while a file change it attempted failed and has not been redone, it is told once, inagent_loop.yml, that the change was not made, to read and retry or say so plainly.f4e3196). A run that still ends with a failed change outstanding, by answering again or by the repeat-after-success rule, is nowABANDONEDinstead ofCOMPLETED, and a notice says the change was not made.aaecc13, from Daniel's review). The run-wide flag became a set of paths. Onlyedit_file,create_fileandupdate_fileadd to it (newToolHandler.writesFiles), so a shell command oradd_dependencyneither sets nor clears it. A success or a user denial clears its own path. The warning re-arms once nothing is outstanding. A prose answer gets the same check asrespond. The notice now starts "A change was not made: a file edit failed and …".6a93052, from an independent review ofaaecc13). A failure is keyed by the file, not the path as typed (PathGuard.writeKeyOf), so a retry under the pathedit_filecorrected a bare name to now counts as the redo. A correction or an approval timeout returns the newToolResult.notApprovedand is settled like a denial. A success settles only failures from earlier batches, so a failed edit beside a successful one on the same file stays outstanding. After the warning, prose gets the unfinished-turn nudge before the run is ended. A repeated look warns first instead of ending at once, and does nothing when the check is off. Runs that stop asUNPARSABLE,CYCLING,REPEATEDorMAX_ITERATIONSnow show the notice too. The closest-lines hint scores whole lines and marks a line cut at 200 characters, shows a tab as\t, matches words in any script, and scores at most 32 words.b869b92, from a second independent review, of6a93052). Onlyedit_filecorrects a missing path to the one project file of that name (newToolHandler.correctsPaths), so a failedcreate_fileorupdate_fileis no longer keyed to another file of the same name; it falls back to the bare name, and skips that project walk. A path with no file name (app/) keeps its own key instead of the empty one that any later write settles. A line cut at 200 characters no longer splits a surrogate pair.b0a09c4, from a third independent review, ofb869b92). After the warning, the run may repeat its last batch once, so a model that obeys by reading again the file it just read gets a turn to make the edit; a second repeat still ends the run with the notice. An approval timeout is a plain failure again: nobody decided against the call, so a failed change it was redoing stays outstanding (a correction is still settled like a denial). A write that already worked, issued again in a later batch, fails because it made the change and is no longer counted as not made.create_fileandupdate_filekey a failure by the path they were given even when the file does not exist yet, so a write to anotherstrings.xmlno longer settles a failed create ofvalues-es/strings.xml; only a path outside the project falls back to the bare name. The empty bare name ofapp/no longer settles the failure of a call that named no file. Keys are looked up only while a failure is outstanding. The warning now says only the failed change was not made, says not to redo other changes to that file, and gives each write tool its recovery; the notice says "a file change failed". The README lists theunapplied_writeturn.c1a9810, from a fourth independent review, ofb0a09c4). A write that already worked and fails again is no longer taken for the change already made when a different write to the same file worked in between, which may have undone it; the file lookup runs only for such a call. Recording writes does nothing when the check is off. The closest-lines hint matches whole words, sovalno longer scores a line holdingevaluate.82ed8fa, from a fifth independent review, ofc1a9810). The repeat rule fromc1a9810is removed: it compared bare file names, sovalues/strings.xmlandvalues-es/strings.xmlcounted as one file. (Its stated reason, that a write undoing a change would let the repeat succeed, was wrong:ddbd07ebelow.) The closest-lines hint also matches a part of an identifier (namefindsapp_nameandappName) and, in a script written without spaces, a part of a phrase.valstill missesevaluate.ddbd07e, from a sixth independent review, of82ed8fa, and three more of the fixes in between, squashed).82ed8fatook any failed repeat of a write that had worked as made. A later write can undo the change in a form the repeat cannot find: a whole-fileupdate_filefrom a stale read re-indents the old text back, and the run endedCOMPLETEDwith "Done" over a title that still said Hello. Three ways of reading the answer off the file's text were each fooled by some edit, so nothing is read off it now.ToolRouter.changeOf: the tool and its declaredchangeArgs, read through its aliases) to the same file (ToolResult.file, the canonical path the tool resolved).edit_file"old_string not found" (madeIfUnchanged) is excused only when no successful write to that file, and no project change naming no file, came since.create_fileon an existing file (alreadyMade) is excused whatever came since.88230c5, from a seventh independent review, ofddbd07e).AgentLoopFileToolsTestdrives the loop with the real edit, update and create tools through aToolRouter, asChatViewModelwires it.Measured on a Pixel 6 Pro (Android 17)
qwen2.5-coder-1.5b-instruct-q4_k_m, "Build Apps Anywhere" test project, a fresh chat, "Change the app name in strings.xml to Block Stacker", every write declined, three runs per build. Builds:
mainplus this branch; AI-Agent-Local from #155's branch (596cb7cfor theb0a09c4runs).edit_file×3 with the same identical guess, rejected each time;REPEATED;read_filenever calledold_stringrejected again); thenread_file; thenrespond"has been changed" (false)COMPLETEDwith the false answer standingf4e3196)ABANDONEDafter 5 turns, and the chat shows "The change was not made: the file edit failed and …"b0a09c4)ABANDONEDafter 5 turns. 1 of 3: one rejected edit, then "already set to 'Block Stacker'" (false), then after the warning "was not made. Please try again.";ABANDONEDafter 3 turns. All 3 show the noticef4e3196orb0a09c4. The model answers instead of callingedit_fileagain, so this PR does not meet ADFA-6835's "done when". The remaining gap is the model, not the handler.b0a09c4the model says itself that the change was not made (3 of 3), where onf4e3196it re-read the file. So the one repeat allowed after the warning was never used on the phone; it is unit-tested only.main's rule (AgentReplyRenderer, from ADFA-6339 | Let the agent run, read and stop shell commands in the Terminal #125) for an answer that follows a failed call; it hides the model's own "was not made" too.88230c5(2026-10-31): qwen2.5-0.5b-instruct-q4_k_m, because the 1.5B file was no longer on the phone. JitpackDemoTest project, a fresh chat per run, writes approved.REPEATED, with both notices ("kept requesting the same action", "A change was not made"). The file was unchanged.edit_filenamed a wrong path (app/src/main/strings.xml). The tool corrected it, and the edit applied once approved. The model then sent it twice more with the corrected full path. Both failed because the change was already there. The run stoppedREPEATEDwith no "change not made" notice, andstrings.xmlheld the change. This is a repeat under another spelling of the path, which82ed8fawould have reported as not made.Review
Daniel reviewed
f4e3196and found six IMPORTANT defects in the flag.aaecc13fixes all six, each with a test that fails onf4e3196. The loop change is still the part to read:AgentLoop.kt(UnappliedWrites, the prose and terminal-tool branches, and theASSUME_COMPLETEverdict). One notable choice: the terminal-tool block is no longer insideterminalTool?.let, with the same behaviour when no terminal tool is set.An independent review of
aaecc13(thecode-reviewskill, given only the PR) raised 15 findings.6a93052fixes 12, see above; 17 of its 18 new tests fail with the old behaviour put back, and the 18th guards against matching two files that share a name. A second independent review, of6a93052(a Sonnet 5.5 agent given the code and the earlier findings), raised four real low-severity findings, fixed inb869b92; each of its four new tests fails with the old behaviour put back.A third independent review, of
b869b92(thecode-reviewskill, given only the PR), raised 15 findings; I checked each against the code (13 confirmed, 2 plausible).b0a09c4fixes seven of them, plus the warning wording, which David approved; each of its eight new tests fails with the old behaviour put back. Two of its findings go to ADFA-6847: keying a failed write from the file the handler resolved instead of re-deriving it (correctsPaths,writeKeyOf), and one approval-outcome value instead of thedenied/notApprovedflags.Not changed:
old_stringa model could copy one line and leave the rest behind. Not seen; to watch for on the phone.\t, which looks the same as a literal backslash-t in source.Accepted limitations: an edit redone through the shell (
sed -i) does not count as redone, so that run gets one warning it does not need. A success on a file in a later batch is taken for the redo of any earlier failure on that file, even if it was a different change: which change a retry redoes cannot be read off its text, and guessing wrong the other way would tell the user a change that was made was not.Not verified
f4e3196andb0a09c4;c1a9810,82ed8faandddbd07eare unit-tested only.88230c5was run on the phone (above) with the 0.5B model, so its runs don't compare directly with the 1.5B ones.aaecc13,6a93052andb869b92were not run on the phone by themselves;b0a09c4includes them.Test plan
testDebugUnitTeston88230c5(1,339 tests, 0 failures); every mutant of the repeat rule, its flags and its key, from the reviews and my own, fails a testassemblePluginon88230c5addons checkexits 0f4e3196); fixes inaaecc13await his re-reviewcode-reviewskill,aaecc13); fixes in6a930526a93052); fixes inb869b92code-reviewskill,b869b92); fixes inb0a09c4, follow-up ADFA-6847code-reviewskill,b0a09c4); fixes inc1a9810, the rest to ADFA-6847code-reviewskill,c1a9810); fixes in82ed8fa82ed8faand of three fixes after it; the fixes are squashed intoddbd07e; closest-lines hint gaps to ADFA-6878, older repeat defects to ADFA-6879ddbd07e); tests in88230c5, MCP read-only tools to ADFA-688088230c5(3 runs, above)b0a09c4(3 runs, allABANDONEDwith the notice; none reached the approval dialog)🤖 Generated with Claude Code
https://claude.ai/code/session_01Vh2DAaJxvRXKRYkgiDqwGQ
https://claude.ai/code/session_01VKUthHVokuWKgP3ACLBii7