{"record":{"id":"f4d46591c4648fd9","repo":"can1357/oh-my-pi","slug":"rewrite-header-reference-1-must-reference-an-f4d465","errorCode":null,"errorMessage":"${REWRITE_HEADER}${reference[1]} must reference an earlier deletion operation.","messagePattern":"(.+?)(.+?) must reference an earlier deletion operation\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/sloppy.ts","lineNumber":3394,"sourceCode":"\t\tif (normalized.text.slice(matchEnd, matchEnd + overlap) !== rewriteNormalized.slice(-overlap)) continue;\n\t\tlet end = normalized.ends[matchEnd + overlap - 1] ?? candidate.end;\n\t\tconst newline = content.indexOf(\"\\n\", end);\n\t\tconst lineEnd = newline === -1 ? content.length : newline;\n\t\tif (/^[ \\t]*$/u.test(content.slice(end, lineEnd))) end = lineEnd;\n\t\treturn { start: candidate.start, end };\n\t}\n\treturn undefined;\n}\n\nfunction resolveRewriteReferences(rewrite: string, removedByOperation: Array<string | undefined>): string {\n\treturn rewrite\n\t\t.split(\"\\n\")\n\t\t.map(line => {\n\t\t\tconst reference = line.trim().match(/^»([1-9]\\d*)$/u);\n\t\t\tif (!reference) return line;\n\t\t\tconst referenced = removedByOperation[Number(reference[1]) - 1];\n\t\t\tif (referenced === undefined) {\n\t\t\t\tthrow new Error(`${REWRITE_HEADER}${reference[1]} must reference an earlier deletion operation.`);\n\t\t\t}\n\t\t\treturn referenced;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\n/**\n * Locate an operation's candidates; when the authored pattern finds nothing,\n * retry echo-recovery variants (`X⟪X⟫` dedup, echoed anchor lines) and keep\n * the original error when every variant fails too.\n */\n/**\n * Delimiter-garbled punctuation selections (`i[----]{+++}+` for `++`→`--`):\n * the marker glyphs absorb the payload's own `-`/`+` characters, scrambling\n * which side is current. Enumerate run-length/side variants for punct-only\n * selections; the file disambiguates — exactly one variant's old side exists.\n */\nfunction punctuationPairVariants(operation: Operation): Operation[] {","sourceCodeStart":3376,"sourceCodeEnd":3412,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/sloppy.ts#L3376-L3412","documentation":"resolveRewriteReferences lets a REWRITE line of the form »N pull in the text deleted by an earlier operation N. When the referenced operation index does not exist among the operations processed so far (removedByOperation has no entry at index N-1), the library throws this error. It prevents dangling back-references to non-existent or later deletions.","triggerScenarios":"A REWRITE line matching /^»([1-9]\\d*)$/ refers to an operation number greater than the number of earlier deletion operations, or that operation made no deletion (nothing recorded in removedByOperation).","commonSituations":"Author miscounts operation numbers (they are 1-based and only deletions register); payload reorderings after adding/removing an earlier edit; model-generated cross-operation references pointing past the end.","solutions":["Change the »N reference to point at an operation defined earlier that actually deletes text.","Remove the »N line if the referenced deletion no longer exists; type the content literally instead.","Recount operations in the payload so reference numbers match the 1-based deletion order."],"exampleFix":"// before\n» 3   // only 2 earlier deletions exist\n\n// after\n» 2","handlingStrategy":"validation","validationCode":"function assertReferencesValid(payload: string, deletionCount: number) {\n  for (const m of payload.matchAll(/^»([1-9]\\d*)$/gmu)) {\n    const n = Number(m[1]);\n    if (n > deletionCount) throw new Error(`Reference »${n} has no earlier deletion operation`);\n  }\n}","typeGuard":"const isValidDeletionReference = (n: number, removedByOperation: unknown[]): boolean =>\n  Number.isInteger(n) && n >= 1 && removedByOperation[n - 1] !== undefined;","tryCatchPattern":"try {\n  applySloppyEdit(payload);\n} catch (err) {\n  if (err instanceof Error && /»\\d+.*earlier deletion/.test(err.message)) {\n    payload = inlineDanglingReferences(payload);\n    applySloppyEdit(payload);\n  } else throw err;\n}","preventionTips":["Count deletion operations (1-based) before writing »N references","Only reference operations that actually delete text — no-ops register nothing","After reordering a payload, renumber all »N references"],"tags":["edit-dsl","dangling-reference","cross-operation"],"backgroundTag":"invalid-reference","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}