FAILURE MAP
← Case archive

FA-80071 / Typography line breaking / Open access

Justified interword spacing: remainder placement · case 01

Extra spacing units cluster on the left side of the line.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Remainder units are given to the leftmost gaps.

VERIFIED REPAIR

Give the remainder units to the rightmost gaps.

Unsuccessful approach: Using > instead of >= shifts the remainder one gap too far right and loses a unit.

Case contract

Input [word widths, target width, is_last, natural space, min space, max space]. Last lines and single-word lines are set ragged with natural spaces. Otherwise distribute target-sum(words) over the gaps: equal share with the remainder units added to the rightmost gaps; a share below min space is ["overfull"]; if any gap would exceed max space fall back to ragged. Return word x positions.

Why this case matters

Line breaking decides where paragraphs wrap on screen and in print; a wrong decision point shifts every following line.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    words, target, is_last, sp, lo, hi = x
    n = len(words)
    gaps = n - 1
    def natural():
        pos, xx = [], 0
        for w in words:
            pos.append(xx)
            xx += w + sp
        return pos
    if is_last or gaps == 0:
        return natural()
    space = target - sum(words)
    per, rem = divmod(space, gaps)
    if per < lo:
        return ['overfull']
    if per + (1 if rem else 0) > hi:
        return natural()
    pos, xx = [], 0
    for k, w in enumerate(words):
        pos.append(xx)
        if k < gaps:
            xx += w + per + (1 if k < rem else 0)
    return pos
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: remainder placement', [[7, 2, 8, 4, 4], 46, False, 2, 2, 6], [0, 12, 19, 32, 42]), ('regression: remainder placement', [[6, 4, 4, 7, 3, 5], 38, False, 3, 1, 6], [0, 7, 13, 19, 28, 33]), ('regression: remainder placement', [[8, 9, 2, 3, 5], 46, False, 2, 1, 5], [0, 12, 26, 33, 41]), ('regression: remainder placement', [[8, 9, 7, 2, 9, 4], 53, False, 3, 1, 7], [0, 10, 22, 32, 37, 49]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('control layout', [[2, 9, 6, 3], 32, True, 3, 2, 5], [0, 5, 17, 26]), ('control layout', [[8, 3, 3, 2], 22, False, 3, 1, 4], [0, 10, 15, 20])], [('regression: remainder placement', [[2, 7, 5], 25, False, 2, 2, 6], [0, 7, 20]), ('regression: remainder placement', [[6, 8, 5], 24, False, 3, 1, 4], [0, 8, 19]), ('regression: remainder placement', [[3, 2, 5, 8], 31, False, 3, 2, 5], [0, 7, 13, 23]), ('regression: remainder placement', [[5, 9, 8, 2, 7, 4], 58, False, 3, 1, 7], [0, 9, 22, 35, 42, 54]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('control layout', [[2, 7, 7], 18, False, 2, 2, 3], ['overfull']), ('control layout', [[9, 8, 3, 8], 40, False, 2, 1, 3], [0, 11, 21, 26])], [('regression: remainder placement', [[2, 4, 6], 25, False, 3, 2, 7], [0, 8, 19]), ('regression: remainder placement', [[9, 8, 8, 9], 41, False, 2, 1, 4], [0, 11, 21, 32]), ('regression: remainder placement', [[4, 9, 9], 29, False, 2, 2, 4], [0, 7, 20]), ('regression: remainder placement', [[8, 7, 2, 8, 4, 4], 56, False, 3, 2, 7], [0, 12, 23, 30, 43, 52]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('last line ragged', [[3, 4, 5], 20, True, 2, 1, 6], [0, 5, 11]), ('control layout', [[7, 9], 21, False, 3, 3, 7], [0, 12])], [('regression: remainder placement', [[5, 5, 4, 8, 7, 9], 51, False, 3, 1, 5], [0, 7, 14, 21, 32, 42]), ('regression: remainder placement', [[8, 7, 2, 8, 4, 4], 56, False, 3, 2, 7], [0, 12, 23, 30, 43, 52]), ('regression: remainder placement', [[8, 9, 3, 7, 9, 8], 51, False, 2, 1, 5], [0, 9, 19, 23, 32, 43]), ('regression: remainder placement', [[6, 3, 2], 14, False, 2, 1, 5], [0, 7, 12]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('control layout', [[2, 6, 8, 6, 6, 9], 75, False, 2, 1, 6], [0, 4, 12, 22, 30, 38]), ('control layout', [[9, 3], 15, False, 2, 2, 5], [0, 12])], [('regression: remainder placement', [[7, 3, 6, 6, 7], 36, False, 2, 1, 6], [0, 8, 13, 21, 29]), ('regression: remainder placement', [[3, 9, 4, 9, 4, 4], 44, False, 2, 2, 3], [0, 5, 16, 22, 33, 40]), ('regression: remainder placement', [[8, 8, 5, 6], 34, False, 2, 2, 5], [0, 10, 20, 28]), ('regression: remainder placement', [[8, 9, 2, 3, 5], 46, False, 2, 1, 5], [0, 12, 26, 33, 41]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('control layout', [[6, 3, 9, 8, 2], 48, False, 3, 3, 7], [0, 11, 19, 33, 46]), ('control layout', [[7, 2, 9, 2, 8], 29, False, 3, 3, 4], ['overfull'])]]
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 fixtureActualExpectedOutcome
regression: remainder placement[0, 13, 20, 33, 42][0, 12, 19, 32, 42]Failed
regression: remainder placement[0, 8, 14, 20, 29, 33][0, 7, 13, 19, 28, 33]Failed
regression: remainder placement[0, 13, 27, 34, 41][0, 12, 26, 33, 41]Failed
regression: remainder placement[0, 11, 23, 33, 38, 49][0, 10, 22, 32, 37, 49]Failed
exactly minimum share[0, 4, 8][0, 4, 8]Passed
remainder goes to right gaps[0, 5, 11, 18][0, 5, 11, 18]Passed
control layout[0, 5, 17, 26][0, 5, 17, 26]Passed
control layout[0, 10, 15, 20][0, 10, 15, 20]Passed

SHA-256 / 5cdfc7d4ce457dded518e2fcf92334ba17fb831606723c1fe20c75460d4e244d

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    words, target, is_last, sp, lo, hi = x
    n = len(words)
    gaps = n - 1
    def natural():
        pos, xx = [], 0
        for w in words:
            pos.append(xx)
            xx += w + sp
        return pos
    if is_last or gaps == 0:
        return natural()
    space = target - sum(words)
    per, rem = divmod(space, gaps)
    if per < lo:
        return ['overfull']
    if per + (1 if rem else 0) > hi:
        return natural()
    pos, xx = [], 0
    for k, w in enumerate(words):
        pos.append(xx)
        if k < gaps:
            xx += w + per + (1 if k > gaps - rem else 0)
    return pos
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: remainder placement', [[7, 2, 8, 4, 4], 46, False, 2, 2, 6], [0, 12, 19, 32, 42]), ('regression: remainder placement', [[6, 4, 4, 7, 3, 5], 38, False, 3, 1, 6], [0, 7, 13, 19, 28, 33]), ('regression: remainder placement', [[8, 9, 2, 3, 5], 46, False, 2, 1, 5], [0, 12, 26, 33, 41]), ('regression: remainder placement', [[8, 9, 7, 2, 9, 4], 53, False, 3, 1, 7], [0, 10, 22, 32, 37, 49]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('control layout', [[2, 9, 6, 3], 32, True, 3, 2, 5], [0, 5, 17, 26]), ('control layout', [[8, 3, 3, 2], 22, False, 3, 1, 4], [0, 10, 15, 20])], [('regression: remainder placement', [[2, 7, 5], 25, False, 2, 2, 6], [0, 7, 20]), ('regression: remainder placement', [[6, 8, 5], 24, False, 3, 1, 4], [0, 8, 19]), ('regression: remainder placement', [[3, 2, 5, 8], 31, False, 3, 2, 5], [0, 7, 13, 23]), ('regression: remainder placement', [[5, 9, 8, 2, 7, 4], 58, False, 3, 1, 7], [0, 9, 22, 35, 42, 54]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('control layout', [[2, 7, 7], 18, False, 2, 2, 3], ['overfull']), ('control layout', [[9, 8, 3, 8], 40, False, 2, 1, 3], [0, 11, 21, 26])], [('regression: remainder placement', [[2, 4, 6], 25, False, 3, 2, 7], [0, 8, 19]), ('regression: remainder placement', [[9, 8, 8, 9], 41, False, 2, 1, 4], [0, 11, 21, 32]), ('regression: remainder placement', [[4, 9, 9], 29, False, 2, 2, 4], [0, 7, 20]), ('regression: remainder placement', [[8, 7, 2, 8, 4, 4], 56, False, 3, 2, 7], [0, 12, 23, 30, 43, 52]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('last line ragged', [[3, 4, 5], 20, True, 2, 1, 6], [0, 5, 11]), ('control layout', [[7, 9], 21, False, 3, 3, 7], [0, 12])], [('regression: remainder placement', [[5, 5, 4, 8, 7, 9], 51, False, 3, 1, 5], [0, 7, 14, 21, 32, 42]), ('regression: remainder placement', [[8, 7, 2, 8, 4, 4], 56, False, 3, 2, 7], [0, 12, 23, 30, 43, 52]), ('regression: remainder placement', [[8, 9, 3, 7, 9, 8], 51, False, 2, 1, 5], [0, 9, 19, 23, 32, 43]), ('regression: remainder placement', [[6, 3, 2], 14, False, 2, 1, 5], [0, 7, 12]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('control layout', [[2, 6, 8, 6, 6, 9], 75, False, 2, 1, 6], [0, 4, 12, 22, 30, 38]), ('control layout', [[9, 3], 15, False, 2, 2, 5], [0, 12])], [('regression: remainder placement', [[7, 3, 6, 6, 7], 36, False, 2, 1, 6], [0, 8, 13, 21, 29]), ('regression: remainder placement', [[3, 9, 4, 9, 4, 4], 44, False, 2, 2, 3], [0, 5, 16, 22, 33, 40]), ('regression: remainder placement', [[8, 8, 5, 6], 34, False, 2, 2, 5], [0, 10, 20, 28]), ('regression: remainder placement', [[8, 9, 2, 3, 5], 46, False, 2, 1, 5], [0, 12, 26, 33, 41]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('control layout', [[6, 3, 9, 8, 2], 48, False, 3, 3, 7], [0, 11, 19, 33, 46]), ('control layout', [[7, 2, 9, 2, 8], 29, False, 3, 3, 4], ['overfull'])]]
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 fixtureActualExpectedOutcome
regression: remainder placement[0, 12, 19, 32, 41][0, 12, 19, 32, 42]Failed
regression: remainder placement[0, 7, 12, 18, 27, 32][0, 7, 13, 19, 28, 33]Failed
regression: remainder placement[0, 12, 25, 32, 40][0, 12, 26, 33, 41]Failed
regression: remainder placement[0, 10, 21, 31, 36, 48][0, 10, 22, 32, 37, 49]Failed
exactly minimum share[0, 4, 8][0, 4, 8]Passed
remainder goes to right gaps[0, 5, 11, 18][0, 5, 11, 18]Passed
control layout[0, 5, 17, 26][0, 5, 17, 26]Passed
control layout[0, 10, 15, 20][0, 10, 15, 20]Passed

SHA-256 / 9af26c2d0adc6834006f2f08e20c4250de86643c533a1098a2225822ff86403f

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    words, target, is_last, sp, lo, hi = x
    n = len(words)
    gaps = n - 1
    def natural():
        pos, xx = [], 0
        for w in words:
            pos.append(xx)
            xx += w + sp
        return pos
    if is_last or gaps == 0:
        return natural()
    space = target - sum(words)
    per, rem = divmod(space, gaps)
    if per < lo:
        return ['overfull']
    if per + (1 if rem else 0) > hi:
        return natural()
    pos, xx = [], 0
    for k, w in enumerate(words):
        pos.append(xx)
        if k < gaps:
            xx += w + per + (1 if k >= gaps - rem else 0)
    return pos
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: remainder placement', [[7, 2, 8, 4, 4], 46, False, 2, 2, 6], [0, 12, 19, 32, 42]), ('regression: remainder placement', [[6, 4, 4, 7, 3, 5], 38, False, 3, 1, 6], [0, 7, 13, 19, 28, 33]), ('regression: remainder placement', [[8, 9, 2, 3, 5], 46, False, 2, 1, 5], [0, 12, 26, 33, 41]), ('regression: remainder placement', [[8, 9, 7, 2, 9, 4], 53, False, 3, 1, 7], [0, 10, 22, 32, 37, 49]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('control layout', [[2, 9, 6, 3], 32, True, 3, 2, 5], [0, 5, 17, 26]), ('control layout', [[8, 3, 3, 2], 22, False, 3, 1, 4], [0, 10, 15, 20])], [('regression: remainder placement', [[2, 7, 5], 25, False, 2, 2, 6], [0, 7, 20]), ('regression: remainder placement', [[6, 8, 5], 24, False, 3, 1, 4], [0, 8, 19]), ('regression: remainder placement', [[3, 2, 5, 8], 31, False, 3, 2, 5], [0, 7, 13, 23]), ('regression: remainder placement', [[5, 9, 8, 2, 7, 4], 58, False, 3, 1, 7], [0, 9, 22, 35, 42, 54]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('control layout', [[2, 7, 7], 18, False, 2, 2, 3], ['overfull']), ('control layout', [[9, 8, 3, 8], 40, False, 2, 1, 3], [0, 11, 21, 26])], [('regression: remainder placement', [[2, 4, 6], 25, False, 3, 2, 7], [0, 8, 19]), ('regression: remainder placement', [[9, 8, 8, 9], 41, False, 2, 1, 4], [0, 11, 21, 32]), ('regression: remainder placement', [[4, 9, 9], 29, False, 2, 2, 4], [0, 7, 20]), ('regression: remainder placement', [[8, 7, 2, 8, 4, 4], 56, False, 3, 2, 7], [0, 12, 23, 30, 43, 52]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('last line ragged', [[3, 4, 5], 20, True, 2, 1, 6], [0, 5, 11]), ('control layout', [[7, 9], 21, False, 3, 3, 7], [0, 12])], [('regression: remainder placement', [[5, 5, 4, 8, 7, 9], 51, False, 3, 1, 5], [0, 7, 14, 21, 32, 42]), ('regression: remainder placement', [[8, 7, 2, 8, 4, 4], 56, False, 3, 2, 7], [0, 12, 23, 30, 43, 52]), ('regression: remainder placement', [[8, 9, 3, 7, 9, 8], 51, False, 2, 1, 5], [0, 9, 19, 23, 32, 43]), ('regression: remainder placement', [[6, 3, 2], 14, False, 2, 1, 5], [0, 7, 12]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('exactly minimum share', [[3, 3, 3], 11, False, 2, 1, 4], [0, 4, 8]), ('control layout', [[2, 6, 8, 6, 6, 9], 75, False, 2, 1, 6], [0, 4, 12, 22, 30, 38]), ('control layout', [[9, 3], 15, False, 2, 2, 5], [0, 12])], [('regression: remainder placement', [[7, 3, 6, 6, 7], 36, False, 2, 1, 6], [0, 8, 13, 21, 29]), ('regression: remainder placement', [[3, 9, 4, 9, 4, 4], 44, False, 2, 2, 3], [0, 5, 16, 22, 33, 40]), ('regression: remainder placement', [[8, 8, 5, 6], 34, False, 2, 2, 5], [0, 10, 20, 28]), ('regression: remainder placement', [[8, 9, 2, 3, 5], 46, False, 2, 1, 5], [0, 12, 26, 33, 41]), ('remainder goes to right gaps', [[3, 4, 5, 2], 20, False, 2, 1, 4], [0, 5, 11, 18]), ('single word line', [[7], 20, False, 2, 1, 4], [0]), ('control layout', [[6, 3, 9, 8, 2], 48, False, 3, 3, 7], [0, 11, 19, 33, 46]), ('control layout', [[7, 2, 9, 2, 8], 29, False, 3, 3, 4], ['overfull'])]]
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 fixtureActualExpectedOutcome
regression: remainder placement[0, 12, 19, 32, 42][0, 12, 19, 32, 42]Passed
regression: remainder placement[0, 7, 13, 19, 28, 33][0, 7, 13, 19, 28, 33]Passed
regression: remainder placement[0, 12, 26, 33, 41][0, 12, 26, 33, 41]Passed
regression: remainder placement[0, 10, 22, 32, 37, 49][0, 10, 22, 32, 37, 49]Passed
exactly minimum share[0, 4, 8][0, 4, 8]Passed
remainder goes to right gaps[0, 5, 11, 18][0, 5, 11, 18]Passed
control layout[0, 5, 17, 26][0, 5, 17, 26]Passed
control layout[0, 10, 15, 20][0, 10, 15, 20]Passed

SHA-256 / c3b492e194998dc91126d6077acbfd44639eb514295bccf585598f60a03fabe1

Verification & scope

A deterministic toy typesetting model with integer widths and a stipulated rule set; it does not claim conformance to any engine. 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:50.337651+00:00.

Case digest / 65515c64ad49a170d9aee4b16fc5558c6f61a856969ce6cd4bca51e88770c2db