| name | deterministic-file-edits |
| description | Recover when the `patch` tool silently fails or reports success without applying — especially on regex literals, backslashes, escaped characters, or generated code. Use a deterministic node `.cjs` script run via `terminal` instead of fuzzy replace. Also covers the isolate-verify-merge workflow for risky/credential-gated features. |
Deterministic File Edits (when fuzzy patch lies)
When to use this skill
patch returns "success" / "file modified" but a follow-up read_file shows the old content still there (classic on \\s, \\[, regex literals, YAML with backslashes, minified/generated strings).
- Fuzzy matching on special characters silently no-ops — no error, no change.
- You need a byte-exact edit and cannot trust fuzzy replace.
The trap (cost this session ~8 wasted turns)
The patch tool uses 9 fuzzy-matching strategies. On backslash/regex/generated content it can report success while applying nothing. Symptoms:
- Repeated "success" then
read_file still shows old text.
- Eventually a real error like
no_unresolved or idempotent_no_progress_warning.
Never trust a "success" from patch on special-char content — always read_file immediately after.
The fix: deterministic node script via terminal
Author a tiny .cjs that does an exact String.split(from).join(to). To avoid the agent's OWN backslash-escaping problem while writing the script, pass the exact from/to strings through a JSON file (JSON \\ reliably means one backslash).
Reusable script: see scripts/exact-replace.cjs. Usage: see references/usage.md.
Minimal inline version
const fs=require('fs');
const p='src/lib/script-parser.ts';
let s=fs.readFileSync(p,'utf8');
const from=JSON.parse('"'+process.argv[2]+'"');
const to=JSON.parse('"'+process.argv[3]+'"');
if(!s.includes(from)){console.log('NOT FOUND');process.exit(2);}
s=s.split(from).join(to);
fs.writeFileSync(p,s);
console.log('OK');
Run: node fix.cjs "\"\\\\s\"" "\"\\s\"" — note argv is itself JSON, so \\ on CLI = one backslash in the arg.
Pitfalls
execute_code is often BLOCKED ("BLOCKED: execute_code runs arbitrary local Python..."). Use terminal + a .cjs file on disk, not execute_code.
- **
String.raw\\s`is NOT the file's bytes** —String.rawof\sis\s(one backslash). If unsure what's actually in the file, dump char codes (seereferences/usage.md`).
sed in MSYS mangles backslashes — prefer node.
- A
split().join() that finds 0 occurrences means your from string doesn't match the real bytes — inspect with char codes before guessing.
- After recovery:
read_file to confirm, then run the project's typecheck/test/lint for regressions. Never claim done without fresh pass evidence.
Inspect actual bytes (when escaping is confusing)
const fs=require('fs');
const line=fs.readFileSync('src/lib/script-parser.ts','utf8').split('\n')[70];
for(let i=0;i<line.length;i++){ if(line[i]==='\\') console.log(i,'BACKSLASH'); }
console.log(JSON.stringify(line));
JSON.stringify doubles each backslash, so \\\\s in output = two backslashes in the file; \\s = one.
Isolate-verify-merge (user-endorsed workflow)
For features needing credentials/network (OAuth upload, live API calls):
- Build in a separate subfolder with its own
package.json + tsconfig.json.
- Keep external SDKs lazy-imported (
await import('googleapis')) so dry-run/sandbox paths need zero deps and run fully offline.
- Write offline tests (no network/credentials) and verify them.
- Only then merge into main behind an env flag (e.g.
YOUTUBE_ENABLED), reusing existing stores.
This keeps the main branch green and lets you prove logic before touching auth.
Verification checklist (always run after a recovery edit)
read_file the changed lines — confirm bytes actually changed.
npm run typecheck (or tsc -p tsconfig.json --noEmit)
npm run test / npm run test:unit
npx eslint <files> — confirm 0 errors (warnings may be intentional)
- Report exact pass/fail counts. Do not say "verified" without running.
Support files in this skill
scripts/exact-replace.cjs — runnable exact-string replacer (pass a replace.json).
references/usage.md — step-by-step + byte-inspect snippet + escaping rules.
references/patch-quirks.md — the real script-parser.ts case that motivated this skill.