{"record":{"id":"eb71287d9a5b7c63","repo":"can1357/oh-my-pi","slug":"referenceseparator-after-match-reads-as-the-r","errorCode":null,"errorMessage":"${referenceSeparator} after MATCH reads as the ${REWRITE_HEADER} separator, leaving REWRITE empty.\\nCopy-ready corrected payload (fill in the final text):\\n${correctedLines.join(\"\\n\")}","messagePattern":"(.+?) after MATCH reads as the (.+?) separator, leaving REWRITE empty\\.\\\\nCopy-ready corrected payload \\(fill in the final text\\):\\\\n(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/sloppy.ts","lineNumber":1173,"sourceCode":"\tlet patternLines: string[] = [];\n\tlet rewriteLines: string[] = [];\n\tlet referenceSeparator: string | undefined;\n\n\tconst finish = (endIndex: number) => {\n\t\tconst sourcePatternText = normalizeBlock(patternLines, false);\n\t\tconst rewriteText = normalizeBlock(rewriteLines, true);\n\t\tif (referenceSeparator !== undefined && rewriteText.trim() === \"\") {\n\t\t\t// A trailing »N produced no rewrite: noise after an inline operation;\n\t\t\t// after a legacy MATCH the final text is missing — hand back a\n\t\t\t// fill-in skeleton instead of echoing the broken payload.\n\t\t\tif (!hasInlineSelection(sourcePatternText)) {\n\t\t\t\tconst correctedLines = [...lines];\n\t\t\t\tconst separatorIndex = correctedLines.findLastIndex(\n\t\t\t\t\t(line, index) => index < endIndex && line.trim() === referenceSeparator,\n\t\t\t\t);\n\t\t\t\tcorrectedLines[separatorIndex] = REWRITE_HEADER;\n\t\t\t\tcorrectedLines.splice(endIndex, 0, \"<final text>\");\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${referenceSeparator} after MATCH reads as the ${REWRITE_HEADER} separator, leaving REWRITE empty.\\nCopy-ready corrected payload (fill in the final text):\\n${correctedLines.join(\"\\n\")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\toperations.push(createOperation(sourcePatternText, \"\", allMatches, operations.length + 1, false));\n\t\t\treturn;\n\t\t}\n\t\toperations.push(createOperation(sourcePatternText, rewriteText, allMatches, operations.length + 1, true));\n\t};\n\tconst pendingSeparatorErrors = new Map<number, string>();\n\tconst finishPattern = (endIndex: number) => {\n\t\tconst sourcePatternText = normalizeBlock(patternLines, false);\n\t\tif (\n\t\t\thasInlineSelection(sourcePatternText) ||\n\t\t\thasMarkerLines(sourcePatternText) ||\n\t\t\thasBareDesired(sourcePatternText)\n\t\t) {\n\t\t\toperations.push(createOperation(sourcePatternText, \"\", allMatches, operations.length + 1, false));\n\t\t\treturn;","sourceCodeStart":1155,"sourceCodeEnd":1191,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/sloppy.ts#L1155-L1191","documentation":"When a MATCH operation is followed by a line equal to the » separator, the separator would terminate the pattern and leave an empty REWRITE. The parser detects this recoverable mistake and throws an error that embeds a copy-ready corrected payload: the erroneous separator line is replaced with » and a '<final text>' placeholder is inserted, so the caller can fill in the replacement and re-send.","triggerScenarios":"A payload where a MATCH section's pattern is terminated by a line consisting solely of » (the reference separator) instead of the » rewrite header, producing an empty rewrite body.","commonSituations":"An LLM uses a bare '»' line as a section divider without knowing it doubles as the REWRITE header; copy/paste collapses '» rewrite' into just '»'.","solutions":["Use the corrected payload printed in the error: keep the » header line and fill in '<final text>' after it","If no rewrite is intended, delete the bare » line so the MATCH stays pattern-only (or use allMatches form)","Re-send the full payload — operations apply atomically"],"exampleFix":"// before\n§ MATCH\nold text\n»\n// after\n§ MATCH\nold text\n»\n<final text>","handlingStrategy":"validation","validationCode":"const lines = payload.split('\\n');\nfor (let i = 0; i < lines.length; i++) {\n  if (lines[i].trim() === '»' && lines[i + 1] === undefined) {\n    throw new Error('bare » line terminates MATCH with an empty REWRITE');\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  applySloppy(content, input, ctx);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('reads as the » separator')) {\n    const corrected = err.message.match(/Copy-ready corrected payload[\\s\\S]*/)?.[0];\n    // fill '<final text>' in corrected payload and re-send\n  } else throw err;\n}","preventionTips":["Never use a bare » line as a visual divider — it is the REWRITE header","Follow every » header with the replacement text","If no rewrite is needed, omit the separator entirely (pattern-only MATCH)"],"tags":["sloppy","rewrite","recovery"],"backgroundTag":"empty-rewrite-section","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}