{"record":{"id":"8552a4659664f0bc","repo":"can1357/oh-my-pi","slug":"operation-operationnumber-has-nested-selection","errorCode":null,"errorMessage":"Operation ${operationNumber} has nested selection markers; use one selection per replacement.","messagePattern":"Operation (.+?) has nested selection markers; use one selection per replacement\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/sloppy.ts","lineNumber":659,"sourceCode":"\tlet sawInline = false;\n\n\tfor (let index = 0; index < pattern.length; ) {\n\t\tconst codePoint = pattern.codePointAt(index);\n\t\tif (codePoint === undefined) break;\n\t\tconst character = String.fromCodePoint(codePoint);\n\t\tif (character === SELECT_CLOSE) {\n\t\t\tthrow new Error(`Operation ${operationNumber} has an unmatched closing selection marker ⟫; add opening ⟪.`);\n\t\t}\n\t\tif (character !== SELECT_OPEN) {\n\t\t\tpatternText += character;\n\t\t\tindex += character.length;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst close = pattern.indexOf(SELECT_CLOSE, index + character.length);\n\t\tconst selected = pattern.slice(index + character.length, close);\n\t\tif (selected.includes(SELECT_OPEN)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Operation ${operationNumber} has nested selection markers; use one selection per replacement.`,\n\t\t\t);\n\t\t}\n\t\tconst divider = selected.indexOf(SELECT_DIVIDER);\n\t\tif (divider === -1) {\n\t\t\tsawBare = true;\n\t\t\tpatternText += pattern.slice(index, close + SELECT_CLOSE.length);\n\t\t} else {\n\t\t\tsawInline = true;\n\t\t\tif (selected.indexOf(SELECT_DIVIDER, divider + SELECT_DIVIDER.length) === -1) {\n\t\t\t\tpatternText += `${SELECT_OPEN}${selected.slice(0, divider)}${SELECT_CLOSE}`;\n\t\t\t\treplacements.push(selected.slice(divider + SELECT_DIVIDER.length));\n\t\t\t} else {\n\t\t\t\tconst resolved = resolveLiteralDividers(selected, operationNumber);\n\t\t\t\tpatternText += `${SELECT_OPEN}${resolved.old}${SELECT_CLOSE}`;\n\t\t\t\treplacements.push(resolved.desired);\n\t\t\t\tnotes.push(resolved.note);\n\t\t\t}","sourceCodeStart":641,"sourceCodeEnd":677,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/sloppy.ts#L641-L677","documentation":"A selection span (⟪…⟫) may not contain another ⟪. Nested selections are ambiguous — which span does the replacement target? The parser rejects them outright and asks for one selection per replacement.","triggerScenarios":"An operation pattern like ⟪outer ⟪inner│new⟫ text⟫ where a second ⟪ appears inside the currently open selection before its ⟫.","commonSituations":"An LLM tries to replace two overlapping/nearby spans with one selection; markers accidentally doubled around the same text; the intended inner ⟪ is actually literal content (escape or rewrite it as plain text).","solutions":["Split into two operations, one selection each","Remove the inner ⟪/⟫ if only the outer span should be replaced","If the inner markers are literal characters in the code, escape them or restructure the pattern so they fall outside a selection"],"exampleFix":"// before\n⟪a ⟪b│x⟫ c⟫»y\n// after\n⟪a b c⟫»y  (or two separate ops for a and b)","handlingStrategy":"validation","validationCode":"let open = false;\nfor (const ch of pattern) {\n  if (ch === '⟪') { if (open) throw new Error('nested selection'); open = true; }\n  if (ch === '⟫') open = false;\n}","typeGuard":null,"tryCatchPattern":"try {\n  applySloppy(content, input, ctx);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('nested selection markers')) {\n    // split into one selection per operation and re-send\n  } else throw err;\n}","preventionTips":["One ⟪…⟫ span open at any time per operation","Split overlapping edits into separate operations","Treat inner ⟪ as literal text by escaping or restructuring the pattern"],"tags":["sloppy","selection-markers","nesting"],"backgroundTag":"nested-selection-markers","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}