FA-80751 / Bidirectional text layout / Open access
Direction-relative alignment: justified last line · case 01
The last line of a justified RTL paragraph sits on the left.
ROOT CAUSE
justify is mapped to left instead of start.
VERIFIED REPAIR
Treat justify as start on the last line.
Unsuccessful approach: Centering the last line is not start alignment.
Case contract
Input [line width, content width, align, rtl]. justify (last line) behaves as start. start = left for LTR, right for RTL; end is the opposite. Overflowing centered content aligns to start. center offset is floor(slack/2) for LTR and ceil(slack/2) for RTL. Return the x offset of the content.
Why this case matters
Mixed right-to-left and left-to-right text must resolve levels and visual order exactly, or words, numbers and carets land in the wrong place.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
lw, cw, align, rtl = x
if align == 'justify':
align = 'left'
if align == 'start':
align = 'right' if rtl else 'left'
elif align == 'end':
align = 'left' if rtl else 'right'
if cw > lw and align == 'center':
align = 'left' if not rtl else 'right'
if align == 'left':
return 0
if align == 'right':
return lw - cw
slack = lw - cw
return (slack + 1) // 2 if rtl else slack // 2
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: justified last line', [13, 48, 'justify', True], -35), ('regression: justified last line', [22, 44, 'justify', True], -22), ('regression: justified last line', [18, 12, 'justify', True], 6), ('regression: justified last line', [33, 4, 'justify', True], 29), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [36, 2, 'center', True], 17), ('control layout', [17, 15, 'left', True], 0)], [('regression: justified last line', [27, 25, 'justify', True], 2), ('regression: justified last line', [21, 48, 'justify', True], -27), ('partial-repair probe', [36, 23, 'justify', False], 0), ('partial-repair probe', [31, 16, 'justify', False], 0), ('RTL end is left', [20, 5, 'end', True], 0), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [30, 30, 'end', True], 0), ('control layout', [30, 34, 'justify', False], 0)], [('regression: justified last line', [37, 31, 'justify', True], 6), ('regression: justified last line', [12, 31, 'justify', True], -19), ('regression: justified last line', [17, 9, 'justify', True], 8), ('regression: justified last line', [38, 35, 'justify', True], 3), ('RTL end is left', [20, 5, 'end', True], 0), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [22, 21, 'right', False], 1), ('control layout', [16, 28, 'start', False], 0)], [('regression: justified last line', [23, 3, 'justify', True], 20), ('regression: justified last line', [29, 38, 'justify', True], -9), ('partial-repair probe', [26, 19, 'justify', False], 0), ('regression: justified last line', [38, 31, 'justify', True], 7), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [17, 15, 'left', True], 0), ('control layout', [21, 8, 'end', True], 0)], [('regression: justified last line', [38, 10, 'justify', True], 28), ('regression: justified last line', [38, 31, 'justify', True], 7), ('regression: justified last line', [17, 9, 'justify', True], 8), ('regression: justified last line', [37, 31, 'justify', True], 6), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [24, 27, 'start', True], -3), ('control layout', [24, 46, 'start', True], -22)]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(args), expected)
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 |
|---|---|---|---|
| regression: justified last line | 0 | -35 | Failed |
| regression: justified last line | 0 | -22 | Failed |
| regression: justified last line | 0 | 6 | Failed |
| regression: justified last line | 0 | 29 | Failed |
| odd slack RTL center | 8 | 8 | Passed |
| overflowing center RTL | -5 | -5 | Passed |
| control layout | 17 | 17 | Passed |
| control layout | 0 | 0 | Passed |
SHA-256 / 5dd3b1db91d3bcfd32db8006da72094e390aec37ecb9309ca37c8a4d85d2eba6
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
lw, cw, align, rtl = x
if align == 'justify':
align = 'center'
if align == 'start':
align = 'right' if rtl else 'left'
elif align == 'end':
align = 'left' if rtl else 'right'
if cw > lw and align == 'center':
align = 'left' if not rtl else 'right'
if align == 'left':
return 0
if align == 'right':
return lw - cw
slack = lw - cw
return (slack + 1) // 2 if rtl else slack // 2
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: justified last line', [13, 48, 'justify', True], -35), ('regression: justified last line', [22, 44, 'justify', True], -22), ('regression: justified last line', [18, 12, 'justify', True], 6), ('regression: justified last line', [33, 4, 'justify', True], 29), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [36, 2, 'center', True], 17), ('control layout', [17, 15, 'left', True], 0)], [('regression: justified last line', [27, 25, 'justify', True], 2), ('regression: justified last line', [21, 48, 'justify', True], -27), ('partial-repair probe', [36, 23, 'justify', False], 0), ('partial-repair probe', [31, 16, 'justify', False], 0), ('RTL end is left', [20, 5, 'end', True], 0), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [30, 30, 'end', True], 0), ('control layout', [30, 34, 'justify', False], 0)], [('regression: justified last line', [37, 31, 'justify', True], 6), ('regression: justified last line', [12, 31, 'justify', True], -19), ('regression: justified last line', [17, 9, 'justify', True], 8), ('regression: justified last line', [38, 35, 'justify', True], 3), ('RTL end is left', [20, 5, 'end', True], 0), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [22, 21, 'right', False], 1), ('control layout', [16, 28, 'start', False], 0)], [('regression: justified last line', [23, 3, 'justify', True], 20), ('regression: justified last line', [29, 38, 'justify', True], -9), ('partial-repair probe', [26, 19, 'justify', False], 0), ('regression: justified last line', [38, 31, 'justify', True], 7), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [17, 15, 'left', True], 0), ('control layout', [21, 8, 'end', True], 0)], [('regression: justified last line', [38, 10, 'justify', True], 28), ('regression: justified last line', [38, 31, 'justify', True], 7), ('regression: justified last line', [17, 9, 'justify', True], 8), ('regression: justified last line', [37, 31, 'justify', True], 6), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [24, 27, 'start', True], -3), ('control layout', [24, 46, 'start', True], -22)]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(args), expected)
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 |
|---|---|---|---|
| regression: justified last line | -35 | -35 | Passed |
| regression: justified last line | -22 | -22 | Passed |
| regression: justified last line | 3 | 6 | Failed |
| regression: justified last line | 15 | 29 | Failed |
| odd slack RTL center | 8 | 8 | Passed |
| overflowing center RTL | -5 | -5 | Passed |
| control layout | 17 | 17 | Passed |
| control layout | 0 | 0 | Passed |
SHA-256 / cceb2b27686e7dea1ebeeeb1309498c1f298ccafa71c4433c44bd47a92439056
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
lw, cw, align, rtl = x
if align == 'justify':
align = 'start'
if align == 'start':
align = 'right' if rtl else 'left'
elif align == 'end':
align = 'left' if rtl else 'right'
if cw > lw and align == 'center':
align = 'left' if not rtl else 'right'
if align == 'left':
return 0
if align == 'right':
return lw - cw
slack = lw - cw
return (slack + 1) // 2 if rtl else slack // 2
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: justified last line', [13, 48, 'justify', True], -35), ('regression: justified last line', [22, 44, 'justify', True], -22), ('regression: justified last line', [18, 12, 'justify', True], 6), ('regression: justified last line', [33, 4, 'justify', True], 29), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [36, 2, 'center', True], 17), ('control layout', [17, 15, 'left', True], 0)], [('regression: justified last line', [27, 25, 'justify', True], 2), ('regression: justified last line', [21, 48, 'justify', True], -27), ('partial-repair probe', [36, 23, 'justify', False], 0), ('partial-repair probe', [31, 16, 'justify', False], 0), ('RTL end is left', [20, 5, 'end', True], 0), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [30, 30, 'end', True], 0), ('control layout', [30, 34, 'justify', False], 0)], [('regression: justified last line', [37, 31, 'justify', True], 6), ('regression: justified last line', [12, 31, 'justify', True], -19), ('regression: justified last line', [17, 9, 'justify', True], 8), ('regression: justified last line', [38, 35, 'justify', True], 3), ('RTL end is left', [20, 5, 'end', True], 0), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [22, 21, 'right', False], 1), ('control layout', [16, 28, 'start', False], 0)], [('regression: justified last line', [23, 3, 'justify', True], 20), ('regression: justified last line', [29, 38, 'justify', True], -9), ('partial-repair probe', [26, 19, 'justify', False], 0), ('regression: justified last line', [38, 31, 'justify', True], 7), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [17, 15, 'left', True], 0), ('control layout', [21, 8, 'end', True], 0)], [('regression: justified last line', [38, 10, 'justify', True], 28), ('regression: justified last line', [38, 31, 'justify', True], 7), ('regression: justified last line', [17, 9, 'justify', True], 8), ('regression: justified last line', [37, 31, 'justify', True], 6), ('odd slack RTL center', [20, 5, 'center', True], 8), ('overflowing center RTL', [10, 15, 'center', True], -5), ('control layout', [24, 27, 'start', True], -3), ('control layout', [24, 46, 'start', True], -22)]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(args), expected)
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 |
|---|---|---|---|
| regression: justified last line | -35 | -35 | Passed |
| regression: justified last line | -22 | -22 | Passed |
| regression: justified last line | 6 | 6 | Passed |
| regression: justified last line | 29 | 29 | Passed |
| odd slack RTL center | 8 | 8 | Passed |
| overflowing center RTL | -5 | -5 | Passed |
| control layout | 17 | 17 | Passed |
| control layout | 0 | 0 | Passed |
SHA-256 / 7c0531e534d9cac23a96864d07dc7a91aeea9c5f7e9f49b50d3924358dd0be0e
Verification & scope
A deterministic toy bidi model over stipulated class labels and integer levels; it is inspired by, but does not claim conformance to, any published algorithm. 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:49:56.749789+00:00.
Case digest / 4e010e617b3c14b2e7b1a5b3798aa8cfb7d9252edaf0c0c1a8993f5dc165aa21