Bug
script_apply_edits with anchor_replace produced a duplicated method when the replacement text contained more lines than the anchor matched. The tool returned success: true with editsApplied: 1 despite the file being broken afterward.
This is distinct from #790 (retry duplication during domain reload) — no domain reload was involved here. The duplication happened on a single, non-retried edit call.
Reproduction
Full tool call:
{
"name": "ProgressionManager",
"path": "Assets/_Project/Scripts/Characters/Components",
"edits": [
{
"op": "anchor_replace",
"anchor": "\\[System\\.Obsolete.*\\]\\s*\n\\s*/// <summary>\\s*\n\\s*/// Restore level and XP from saved data without triggering events or rewards\\.\\.",
"text": " /// <summary>\n /// Restore level and XP from saved data without triggering events or rewards.\n /// </summary>\n [System.Obsolete(\"Use RestoreFromSave(level, xp, statPoints, talentPoints) to ensure _points dictionary is restored.\")]\n public void RestoreFromSave(int savedLevel, int savedXP)\n {\n _level = savedLevel;\n _currentXP = savedXP;\n }\n\n /// <summary>\n /// Restore level, XP, and points from saved data without triggering events."
}
],
"options": {"validate": "relaxed", "refresh": "immediate"}
}
Note: validate: "relaxed" was used. I did not test whether validate: "standard" would have caught the duplicate method.
File before edit (exact region):
[System.Obsolete("Use RestoreFromSave(level, xp, statPoints, talentPoints) to ensure _points dictionary is restored.")]
/// <summary>
/// Restore level and XP from saved data without triggering events or rewards..
/// Called during save game loading after Character serialized fields are set.
/// </summary>
public void RestoreFromSave(int savedLevel, int savedXP)
{
_level = savedLevel;
_currentXP = savedXP;
}
/// <summary>
/// Restore level, XP, and points from saved data without triggering events..
/// Called during save game loading. Does NOT fire OnPointsChanged to avoid
/// double-counting via Character's event forwarding handler.
/// </summary>
public void RestoreFromSave(int savedLevel, int savedXP, int statPoints, int talentPoints)
Intent: Reorder the [Obsolete] attribute to come after the XML doc comment (C# convention), and fix a double period in the doc comment.
Tool response:
{
"success": true,
"message": "Applied 2 structured edit(s) to 'Assets/_Project/Scripts/Characters/Components/ProgressionManager.cs'.",
"data": {
"path": "Assets/_Project/Scripts/Characters/Components/ProgressionManager.cs",
"editsApplied": 2,
"scheduledRefresh": false,
"sha256": "1ac0ed4ba6044c877dd16b801f8a00708b000bfb559307cc1859986fa8f1030e",
"routing": "structured"
}
}
(Note: 2 edits were in the batch — the second edit was a separate anchor_replace on a different doc comment in the same file. The second edit succeeded correctly. Only the first edit produced corruption.)
File after edit (broken — two copies of the 2-param method):
/// <summary>
/// Restore level and XP from saved data without triggering events or rewards.
/// </summary>
[System.Obsolete("Use RestoreFromSave(level, xp, statPoints, talentPoints) to ensure _points dictionary is restored.")]
public void RestoreFromSave(int savedLevel, int savedXP)
{
_level = savedLevel;
_currentXP = savedXP;
}
/// <summary>
/// Restore level, XP, and points from saved data without triggering events.
/// Called during save game loading after Character serialized fields are set.
/// </summary>
public void RestoreFromSave(int savedLevel, int savedXP)
{
_level = savedLevel;
_currentXP = savedXP;
}
/// <summary>
/// Restore level, XP, and points from saved data without triggering events.
/// Called during save game loading. Does NOT fire OnPointsChanged to avoid
/// double-counting via Character's event forwarding handler.
/// </summary>
public void RestoreFromSave(int savedLevel, int savedXP, int statPoints, int talentPoints)
The anchor matched ~3 lines (attribute + doc comment start). The replacement text included a full method body + start of the next doc comment. The original method body below the anchor match was not consumed — it remained in place, producing the duplicate.
Expected Behavior
Either:
anchor_replace should fail or warn when the replacement text contains significantly more lines than the anchor match (the mismatch is a strong signal of user error or an upcoming corruption), OR
validate: "standard" (or even "relaxed") should catch the resulting duplicate method signature and reject the edit before writing the file
Workaround
- Use
replace_method op instead (safer method-level boundaries)
- Use external editor tools for multi-line replacements near method boundaries
- Always read the file after any
anchor_* operation to verify integrity
Environment
- MCP For Unity v9.5.3-beta.1
- Unity 6000.3.9f1
- Transport: SSE
- Client: Claude Code (claude-opus-4-6)
Bug
script_apply_editswithanchor_replaceproduced a duplicated method when the replacement text contained more lines than the anchor matched. The tool returnedsuccess: truewitheditsApplied: 1despite the file being broken afterward.This is distinct from #790 (retry duplication during domain reload) — no domain reload was involved here. The duplication happened on a single, non-retried edit call.
Reproduction
Full tool call:
{ "name": "ProgressionManager", "path": "Assets/_Project/Scripts/Characters/Components", "edits": [ { "op": "anchor_replace", "anchor": "\\[System\\.Obsolete.*\\]\\s*\n\\s*/// <summary>\\s*\n\\s*/// Restore level and XP from saved data without triggering events or rewards\\.\\.", "text": " /// <summary>\n /// Restore level and XP from saved data without triggering events or rewards.\n /// </summary>\n [System.Obsolete(\"Use RestoreFromSave(level, xp, statPoints, talentPoints) to ensure _points dictionary is restored.\")]\n public void RestoreFromSave(int savedLevel, int savedXP)\n {\n _level = savedLevel;\n _currentXP = savedXP;\n }\n\n /// <summary>\n /// Restore level, XP, and points from saved data without triggering events." } ], "options": {"validate": "relaxed", "refresh": "immediate"} }Note:
validate: "relaxed"was used. I did not test whethervalidate: "standard"would have caught the duplicate method.File before edit (exact region):
Intent: Reorder the
[Obsolete]attribute to come after the XML doc comment (C# convention), and fix a double period in the doc comment.Tool response:
{ "success": true, "message": "Applied 2 structured edit(s) to 'Assets/_Project/Scripts/Characters/Components/ProgressionManager.cs'.", "data": { "path": "Assets/_Project/Scripts/Characters/Components/ProgressionManager.cs", "editsApplied": 2, "scheduledRefresh": false, "sha256": "1ac0ed4ba6044c877dd16b801f8a00708b000bfb559307cc1859986fa8f1030e", "routing": "structured" } }(Note: 2 edits were in the batch — the second edit was a separate
anchor_replaceon a different doc comment in the same file. The second edit succeeded correctly. Only the first edit produced corruption.)File after edit (broken — two copies of the 2-param method):
The anchor matched ~3 lines (attribute + doc comment start). The replacement text included a full method body + start of the next doc comment. The original method body below the anchor match was not consumed — it remained in place, producing the duplicate.
Expected Behavior
Either:
anchor_replaceshould fail or warn when the replacement text contains significantly more lines than the anchor match (the mismatch is a strong signal of user error or an upcoming corruption), ORvalidate: "standard"(or even"relaxed") should catch the resulting duplicate method signature and reject the edit before writing the fileWorkaround
replace_methodop instead (safer method-level boundaries)anchor_*operation to verify integrityEnvironment