FA-7911 / Text editing / Open access
Text selection replacement: Backward selections start replacement at the anchor · case 01
Backward selections start replacement at the anchor.
ROOT CAUSE
The backward start operation uses `anchor` where the contract requires `min(anchor, focus)`.
VERIFIED REPAIR
Implement the backward start operation as `min(anchor, focus)`.
Unsuccessful approach: Using the upper endpoint discards the selection direction normalization.
Case contract
Composition is preserved; replace the normalized half-open selection and collapse both endpoints immediately after inserted text.
Why this case matters
A deterministic model of text selection replacement; this isolates one interface invariant without requiring a browser.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(text, anchor, focus, replacement, composing):
if composing: return (text, anchor, focus)
lo = anchor
hi = max(anchor, focus)
result = text[:lo] + replacement + text[hi:]
caret = lo + len(replacement)
return (result, caret, caret)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('composition', solve('abcdef', 1, 4, 'XY', True), ('abcdef', 1, 4))
check('forward', solve('abcdef', 1, 4, 'XY', False), ('aXYef', 3, 3))
check('backward', solve('abcdef', 4, 1, 'XY', False), ('aXYef', 3, 3))
check('insertion', solve('ab', 1, 1, 'XYZ', False), ('aXYZb', 4, 4))
check('delete', solve('abc', 0, 3, '', False), ('', 0, 0))
check('no selection', solve('abc', 2, 2, '', False), ('abc', 2, 2))
check('parameterized selected length', solve('a'*N, 0, N, 'X', False), ('X', 1, 1))
for repetition in range(N):
check('repeat no selection', solve('abc', 2, 2, '', False), ('abc', 2, 2))
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| composition | ['abcdef', 1, 4] | ['abcdef', 1, 4] | Passed |
| forward | ['aXYef', 3, 3] | ['aXYef', 3, 3] | Passed |
| backward | ['abcdXYef', 6, 6] | ['aXYef', 3, 3] | Failed |
| insertion | ['aXYZb', 4, 4] | ['aXYZb', 4, 4] | Passed |
| delete | ['', 0, 0] | ['', 0, 0] | Passed |
| no selection | ['abc', 2, 2] | ['abc', 2, 2] | Passed |
| parameterized selected length | ['X', 1, 1] | ['X', 1, 1] | Passed |
| repeat no selection | ['abc', 2, 2] | ['abc', 2, 2] | Passed |
SHA-256 / ccc1689ab8bc23b91b62a15cd4df140c1c2c3debba9c0225db31a081510d677f
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(text, anchor, focus, replacement, composing):
if composing: return (text, anchor, focus)
lo = max(anchor, focus)
hi = max(anchor, focus)
result = text[:lo] + replacement + text[hi:]
caret = lo + len(replacement)
return (result, caret, caret)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('composition', solve('abcdef', 1, 4, 'XY', True), ('abcdef', 1, 4))
check('forward', solve('abcdef', 1, 4, 'XY', False), ('aXYef', 3, 3))
check('backward', solve('abcdef', 4, 1, 'XY', False), ('aXYef', 3, 3))
check('insertion', solve('ab', 1, 1, 'XYZ', False), ('aXYZb', 4, 4))
check('delete', solve('abc', 0, 3, '', False), ('', 0, 0))
check('no selection', solve('abc', 2, 2, '', False), ('abc', 2, 2))
check('parameterized selected length', solve('a'*N, 0, N, 'X', False), ('X', 1, 1))
for repetition in range(N):
check('repeat no selection', solve('abc', 2, 2, '', False), ('abc', 2, 2))
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| composition | ['abcdef', 1, 4] | ['abcdef', 1, 4] | Passed |
| forward | ['abcdXYef', 6, 6] | ['aXYef', 3, 3] | Failed |
| backward | ['abcdXYef', 6, 6] | ['aXYef', 3, 3] | Failed |
| insertion | ['aXYZb', 4, 4] | ['aXYZb', 4, 4] | Passed |
| delete | ['abc', 3, 3] | ['', 0, 0] | Failed |
| no selection | ['abc', 2, 2] | ['abc', 2, 2] | Passed |
| parameterized selected length | ['aX', 2, 2] | ['X', 1, 1] | Failed |
| repeat no selection | ['abc', 2, 2] | ['abc', 2, 2] | Passed |
SHA-256 / f8bb19297456c52fc070eb78ac7702cc105241140472403288d1d87a28368cad
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(text, anchor, focus, replacement, composing):
if composing: return (text, anchor, focus)
lo = min(anchor, focus)
hi = max(anchor, focus)
result = text[:lo] + replacement + text[hi:]
caret = lo + len(replacement)
return (result, caret, caret)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('composition', solve('abcdef', 1, 4, 'XY', True), ('abcdef', 1, 4))
check('forward', solve('abcdef', 1, 4, 'XY', False), ('aXYef', 3, 3))
check('backward', solve('abcdef', 4, 1, 'XY', False), ('aXYef', 3, 3))
check('insertion', solve('ab', 1, 1, 'XYZ', False), ('aXYZb', 4, 4))
check('delete', solve('abc', 0, 3, '', False), ('', 0, 0))
check('no selection', solve('abc', 2, 2, '', False), ('abc', 2, 2))
check('parameterized selected length', solve('a'*N, 0, N, 'X', False), ('X', 1, 1))
for repetition in range(N):
check('repeat no selection', solve('abc', 2, 2, '', False), ('abc', 2, 2))
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| composition | ['abcdef', 1, 4] | ['abcdef', 1, 4] | Passed |
| forward | ['aXYef', 3, 3] | ['aXYef', 3, 3] | Passed |
| backward | ['aXYef', 3, 3] | ['aXYef', 3, 3] | Passed |
| insertion | ['aXYZb', 4, 4] | ['aXYZb', 4, 4] | Passed |
| delete | ['', 0, 0] | ['', 0, 0] | Passed |
| no selection | ['abc', 2, 2] | ['abc', 2, 2] | Passed |
| parameterized selected length | ['X', 1, 1] | ['X', 1, 1] | Passed |
| repeat no selection | ['abc', 2, 2] | ['abc', 2, 2] | Passed |
SHA-256 / fc2f2c1a50e0138b1115cb5974ca3f32bfb6e374e5c68d2b170eef373d133908
Verification & scope
This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:38:16.454466+00:00.
Case digest / bbb864ecf781b518100f56105a7e8ed2d52f722898292862111bf885acfc63e6