FA-80011 / Typography line breaking / Open access
CJK kinsoku line breaking: hang followed by closer · case 01
A period hangs while its closing bracket starts the next line.
ROOT CAUSE
Hanging ignores whether the following character is itself line-start prohibited.
VERIFIED REPAIR
Only hang when the character after the hanging mark may start a line.
Unsuccessful approach: Checking the following character against the line-end set tests the wrong property.
Case contract
Input [text of full-width characters, line length L]. Lines take L characters. If the next character is a hanging comma/period (、。,.) and is not itself followed by a line-start-prohibited character, it hangs on the line (burasage). Otherwise move characters to the next line while the next line would start with a prohibited character (、。,.)」』!?ー and small kana), then while the line would end with an opening bracket; a line keeps at least one character. Return the lines.
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):
text, L = x
NO_START = '、。,.)」』!?ーぁぃぅぇぉっゃゅょ'
NO_END = '(「『'
HANG = '、。,.'
lines = []
pos = 0
n = len(text)
while pos < n:
end = pos + L
if end >= n:
lines.append(text[pos:])
break
if text[end] in HANG:
end += 1
else:
while end > pos + 1 and text[end] in NO_START:
end -= 1
while end > pos + 1 and text[end - 1] in NO_END:
end -= 1
lines.append(text[pos:end])
pos = end
return lines
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('period followed by bracket cannot hang', ['日本語文。」字組', 4], ['日本語', '文。」字', '組']), ('regression: hang followed by closer', ['くき)『いえ本(本『、字)ー。っ」字', 3], ['くき)', '『いえ', '本(本', '『、', '字', ')', 'ー', '。っ」', '字']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['「)。文お。い組、、い)、、っ」け「あえいけ日、', 4], ['「)。文', 'お。い', '組、、', 'い', ')', '、、っ」', 'け「あえ', 'いけ日、']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('small kana prohibited at line start', ['日本語かっこいい', 4], ['日本語', 'かっこい', 'い']), ('control layout', ['か本うくい日「、け字ー『こ字え。う', 3], ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う']), ('control layout', ['け。。「)ゃおお」けゃ」かあうう)か『か字い', 5], ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'])], [('regression: hang followed by closer', ['う」』』え組「。。『お文組う', 7], ['う」』』え組', '「。。『お文組', 'う']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['日ーゃ語文「っ日あこけ語っこい語。』本『', 8], ['日ーゃ語文「っ日', 'あこけ語っこい', '語。』本『']), ('regression: hang followed by closer', ['文版ゃき、。語。あ日ーっ日『、」』、組ゃか』え', 4], ['文版ゃ', 'き、。語。', 'あ日ーっ', '日', '『、」』、', '組ゃか』', 'え']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('period hangs past the measure', ['日本語文。字組版', 4], ['日本語文。', '字組版']), ('control layout', ['こ版あ)え『本)う)あい(え日組ーー『こ。き日', 6], ['こ版あ)え', '『本)う)あ', 'い(え日', '組ーー『こ。', 'き日']), ('control layout', [')。あおく本ー』い', 4], [')。あお', 'く本ー』', 'い'])], [('regression: hang followed by closer', ['版っ日けおく、)」版(「', 6], ['版っ日けお', 'く、)」版', '(「']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['版っ』い「)ー)。)', 3], ['版っ』', 'い', '「', ')', 'ー', ')。)']), ('partial-repair probe', ['語お』、「っお日けあ版))「か字字かこえ字組版', 3], ['語お』、', '「っお', '日けあ', '版))', '「か字', '字かこ', 'え字組', '版']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('opening bracket at line end', ['日本語「文字」組版', 4], ['日本語', '「文字」', '組版']), ('control layout', ['『』字)(ゃ『語けあ語か』え『い。え。日こ', 8], ['『』字)(ゃ『語', 'けあ語か』え『い。', 'え。日こ']), ('control layout', ['本かーこ))ー、文本本', 3], ['本かー', 'こ', '))ー、', '文本本'])], [('regression: hang followed by closer', ['「『日、く)、」組)っうお。(', 6], ['「『日、', 'く)、」', '組)っうお。', '(']), ('regression: hang followed by closer', ['』く「本え語おっかえい、。、きけこ組ゃこ『きあ』', 3], ['』く', '「本え', '語おっ', 'かえ', 'い、。、', 'きけこ', '組ゃこ', '『き', 'あ』']), ('regression: hang followed by closer', ['(日おあ」『こか、語。)本文っ、文えあゃ。', 5], ['(日おあ」', '『こか、', '語。)本', '文っ、文え', 'あゃ。']), ('regression: hang followed by closer', ['日組こ、『っ、ー日ーあ』っ「、き「字っ', 6], ['日組こ、', '『っ、ー日ー', 'あ』っ「、き', '「字っ']), ('period hangs past the measure', ['日本語文。字組版', 4], ['日本語文。', '字組版']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('control layout', ['かい』けえ』ゃ』版日けっ)', 7], ['かい』け', 'え』ゃ』版日', 'けっ)']), ('control layout', ['文くこ、』本)。版(』(『いえ『本こ」かっか', 4], ['文く', 'こ、』', '本)。版', '(』', '(『いえ', '『本こ」', 'かっか'])], [('regression: hang followed by closer', ['うこ文版」」。。か字えーっあ」っけ』いか語いっ', 6], ['うこ文', '版」」。。か', '字えーっ', 'あ」っけ』い', 'か語いっ']), ('regression: hang followed by closer', ['いあ『本く)く。ー', 3], ['いあ', '『本', 'く)', 'く。ー']), ('regression: hang followed by closer', ['くけおけあき組。か語おき「版(。っ組えく組', 5], ['くけおけあ', 'き組。か語', 'おき「版', '(。っ組え', 'く組']), ('partial-repair probe', ['』あ「組えか語おえきゃ)組。あ文、『」えこう', 8], ['』あ「組えか語お', 'えきゃ)組。あ文、', '『」えこう']), ('period followed by bracket cannot hang', ['日本語文。」字組', 4], ['日本語', '文。」字', '組']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('control layout', ['、ーく」ゃ』』ー本え組きけ本日こ』', 7], ['、ー', 'く」ゃ』』ー本', 'え組きけ本日', 'こ』']), ('control layout', ['組本)かゃ組っー', 6], ['組本)かゃ', '組っー'])]]
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 |
|---|---|---|---|
| period followed by bracket cannot hang | ['日本語文。', '」字組'] | ['日本語', '文。」字', '組'] | Failed |
| regression: hang followed by closer | ['くき)', '『いえ', '本(本', '『、', '字)ー。', 'っ」字'] | ['くき)', '『いえ', '本(本', '『、', '字', ')', 'ー', '。っ」', '字'] | Failed |
| regression: hang followed by closer | ['文字、」(ゃ日', 'き日』組文っー、', '、組本きっ組'] | ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組'] | Failed |
| regression: hang followed by closer | ['「)。文', 'お。い組、', '、い)、、', 'っ」け', '「あえい', 'け日、'] | ['「)。文', 'お。い', '組、、', 'い', ')', '、、っ」', 'け「あえ', 'いけ日、'] | Failed |
| closing bracket pushes out | ['日本語', '文」字組', '版'] | ['日本語', '文」字組', '版'] | Passed |
| small kana prohibited at line start | ['日本語', 'かっこい', 'い'] | ['日本語', 'かっこい', 'い'] | Passed |
| control layout | ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う'] | ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う'] | Passed |
| control layout | ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'] | ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'] | Passed |
SHA-256 / 25db4374ad9bcdf73c9f5f226817b30b62ca5d0132f73f8d7653c2d7f0d3f9da
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
text, L = x
NO_START = '、。,.)」』!?ーぁぃぅぇぉっゃゅょ'
NO_END = '(「『'
HANG = '、。,.'
lines = []
pos = 0
n = len(text)
while pos < n:
end = pos + L
if end >= n:
lines.append(text[pos:])
break
if text[end] in HANG and (end + 1 >= n or text[end + 1] not in NO_END):
end += 1
else:
while end > pos + 1 and text[end] in NO_START:
end -= 1
while end > pos + 1 and text[end - 1] in NO_END:
end -= 1
lines.append(text[pos:end])
pos = end
return lines
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('period followed by bracket cannot hang', ['日本語文。」字組', 4], ['日本語', '文。」字', '組']), ('regression: hang followed by closer', ['くき)『いえ本(本『、字)ー。っ」字', 3], ['くき)', '『いえ', '本(本', '『、', '字', ')', 'ー', '。っ」', '字']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['「)。文お。い組、、い)、、っ」け「あえいけ日、', 4], ['「)。文', 'お。い', '組、、', 'い', ')', '、、っ」', 'け「あえ', 'いけ日、']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('small kana prohibited at line start', ['日本語かっこいい', 4], ['日本語', 'かっこい', 'い']), ('control layout', ['か本うくい日「、け字ー『こ字え。う', 3], ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う']), ('control layout', ['け。。「)ゃおお」けゃ」かあうう)か『か字い', 5], ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'])], [('regression: hang followed by closer', ['う」』』え組「。。『お文組う', 7], ['う」』』え組', '「。。『お文組', 'う']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['日ーゃ語文「っ日あこけ語っこい語。』本『', 8], ['日ーゃ語文「っ日', 'あこけ語っこい', '語。』本『']), ('regression: hang followed by closer', ['文版ゃき、。語。あ日ーっ日『、」』、組ゃか』え', 4], ['文版ゃ', 'き、。語。', 'あ日ーっ', '日', '『、」』、', '組ゃか』', 'え']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('period hangs past the measure', ['日本語文。字組版', 4], ['日本語文。', '字組版']), ('control layout', ['こ版あ)え『本)う)あい(え日組ーー『こ。き日', 6], ['こ版あ)え', '『本)う)あ', 'い(え日', '組ーー『こ。', 'き日']), ('control layout', [')。あおく本ー』い', 4], [')。あお', 'く本ー』', 'い'])], [('regression: hang followed by closer', ['版っ日けおく、)」版(「', 6], ['版っ日けお', 'く、)」版', '(「']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['版っ』い「)ー)。)', 3], ['版っ』', 'い', '「', ')', 'ー', ')。)']), ('partial-repair probe', ['語お』、「っお日けあ版))「か字字かこえ字組版', 3], ['語お』、', '「っお', '日けあ', '版))', '「か字', '字かこ', 'え字組', '版']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('opening bracket at line end', ['日本語「文字」組版', 4], ['日本語', '「文字」', '組版']), ('control layout', ['『』字)(ゃ『語けあ語か』え『い。え。日こ', 8], ['『』字)(ゃ『語', 'けあ語か』え『い。', 'え。日こ']), ('control layout', ['本かーこ))ー、文本本', 3], ['本かー', 'こ', '))ー、', '文本本'])], [('regression: hang followed by closer', ['「『日、く)、」組)っうお。(', 6], ['「『日、', 'く)、」', '組)っうお。', '(']), ('regression: hang followed by closer', ['』く「本え語おっかえい、。、きけこ組ゃこ『きあ』', 3], ['』く', '「本え', '語おっ', 'かえ', 'い、。、', 'きけこ', '組ゃこ', '『き', 'あ』']), ('regression: hang followed by closer', ['(日おあ」『こか、語。)本文っ、文えあゃ。', 5], ['(日おあ」', '『こか、', '語。)本', '文っ、文え', 'あゃ。']), ('regression: hang followed by closer', ['日組こ、『っ、ー日ーあ』っ「、き「字っ', 6], ['日組こ、', '『っ、ー日ー', 'あ』っ「、き', '「字っ']), ('period hangs past the measure', ['日本語文。字組版', 4], ['日本語文。', '字組版']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('control layout', ['かい』けえ』ゃ』版日けっ)', 7], ['かい』け', 'え』ゃ』版日', 'けっ)']), ('control layout', ['文くこ、』本)。版(』(『いえ『本こ」かっか', 4], ['文く', 'こ、』', '本)。版', '(』', '(『いえ', '『本こ」', 'かっか'])], [('regression: hang followed by closer', ['うこ文版」」。。か字えーっあ」っけ』いか語いっ', 6], ['うこ文', '版」」。。か', '字えーっ', 'あ」っけ』い', 'か語いっ']), ('regression: hang followed by closer', ['いあ『本く)く。ー', 3], ['いあ', '『本', 'く)', 'く。ー']), ('regression: hang followed by closer', ['くけおけあき組。か語おき「版(。っ組えく組', 5], ['くけおけあ', 'き組。か語', 'おき「版', '(。っ組え', 'く組']), ('partial-repair probe', ['』あ「組えか語おえきゃ)組。あ文、『」えこう', 8], ['』あ「組えか語お', 'えきゃ)組。あ文、', '『」えこう']), ('period followed by bracket cannot hang', ['日本語文。」字組', 4], ['日本語', '文。」字', '組']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('control layout', ['、ーく」ゃ』』ー本え組きけ本日こ』', 7], ['、ー', 'く」ゃ』』ー本', 'え組きけ本日', 'こ』']), ('control layout', ['組本)かゃ組っー', 6], ['組本)かゃ', '組っー'])]]
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 |
|---|---|---|---|
| period followed by bracket cannot hang | ['日本語文。', '」字組'] | ['日本語', '文。」字', '組'] | Failed |
| regression: hang followed by closer | ['くき)', '『いえ', '本(本', '『、', '字)ー。', 'っ」字'] | ['くき)', '『いえ', '本(本', '『、', '字', ')', 'ー', '。っ」', '字'] | Failed |
| regression: hang followed by closer | ['文字、」(ゃ日', 'き日』組文っー、', '、組本きっ組'] | ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組'] | Failed |
| regression: hang followed by closer | ['「)。文', 'お。い組、', '、い)、、', 'っ」け', '「あえい', 'け日、'] | ['「)。文', 'お。い', '組、、', 'い', ')', '、、っ」', 'け「あえ', 'いけ日、'] | Failed |
| closing bracket pushes out | ['日本語', '文」字組', '版'] | ['日本語', '文」字組', '版'] | Passed |
| small kana prohibited at line start | ['日本語', 'かっこい', 'い'] | ['日本語', 'かっこい', 'い'] | Passed |
| control layout | ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う'] | ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う'] | Passed |
| control layout | ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'] | ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'] | Passed |
SHA-256 / 5c0c082b8df6de185071cd3107c0ad64943a0337935c671af4e1b95d69fe3c24
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
text, L = x
NO_START = '、。,.)」』!?ーぁぃぅぇぉっゃゅょ'
NO_END = '(「『'
HANG = '、。,.'
lines = []
pos = 0
n = len(text)
while pos < n:
end = pos + L
if end >= n:
lines.append(text[pos:])
break
if text[end] in HANG and (end + 1 >= n or text[end + 1] not in NO_START):
end += 1
else:
while end > pos + 1 and text[end] in NO_START:
end -= 1
while end > pos + 1 and text[end - 1] in NO_END:
end -= 1
lines.append(text[pos:end])
pos = end
return lines
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('period followed by bracket cannot hang', ['日本語文。」字組', 4], ['日本語', '文。」字', '組']), ('regression: hang followed by closer', ['くき)『いえ本(本『、字)ー。っ」字', 3], ['くき)', '『いえ', '本(本', '『、', '字', ')', 'ー', '。っ」', '字']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['「)。文お。い組、、い)、、っ」け「あえいけ日、', 4], ['「)。文', 'お。い', '組、、', 'い', ')', '、、っ」', 'け「あえ', 'いけ日、']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('small kana prohibited at line start', ['日本語かっこいい', 4], ['日本語', 'かっこい', 'い']), ('control layout', ['か本うくい日「、け字ー『こ字え。う', 3], ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う']), ('control layout', ['け。。「)ゃおお」けゃ」かあうう)か『か字い', 5], ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'])], [('regression: hang followed by closer', ['う」』』え組「。。『お文組う', 7], ['う」』』え組', '「。。『お文組', 'う']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['日ーゃ語文「っ日あこけ語っこい語。』本『', 8], ['日ーゃ語文「っ日', 'あこけ語っこい', '語。』本『']), ('regression: hang followed by closer', ['文版ゃき、。語。あ日ーっ日『、」』、組ゃか』え', 4], ['文版ゃ', 'き、。語。', 'あ日ーっ', '日', '『、」』、', '組ゃか』', 'え']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('period hangs past the measure', ['日本語文。字組版', 4], ['日本語文。', '字組版']), ('control layout', ['こ版あ)え『本)う)あい(え日組ーー『こ。き日', 6], ['こ版あ)え', '『本)う)あ', 'い(え日', '組ーー『こ。', 'き日']), ('control layout', [')。あおく本ー』い', 4], [')。あお', 'く本ー』', 'い'])], [('regression: hang followed by closer', ['版っ日けおく、)」版(「', 6], ['版っ日けお', 'く、)」版', '(「']), ('regression: hang followed by closer', ['文字、」(ゃ日き日』組文っー、、組本きっ組', 7], ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組']), ('regression: hang followed by closer', ['版っ』い「)ー)。)', 3], ['版っ』', 'い', '「', ')', 'ー', ')。)']), ('partial-repair probe', ['語お』、「っお日けあ版))「か字字かこえ字組版', 3], ['語お』、', '「っお', '日けあ', '版))', '「か字', '字かこ', 'え字組', '版']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('opening bracket at line end', ['日本語「文字」組版', 4], ['日本語', '「文字」', '組版']), ('control layout', ['『』字)(ゃ『語けあ語か』え『い。え。日こ', 8], ['『』字)(ゃ『語', 'けあ語か』え『い。', 'え。日こ']), ('control layout', ['本かーこ))ー、文本本', 3], ['本かー', 'こ', '))ー、', '文本本'])], [('regression: hang followed by closer', ['「『日、く)、」組)っうお。(', 6], ['「『日、', 'く)、」', '組)っうお。', '(']), ('regression: hang followed by closer', ['』く「本え語おっかえい、。、きけこ組ゃこ『きあ』', 3], ['』く', '「本え', '語おっ', 'かえ', 'い、。、', 'きけこ', '組ゃこ', '『き', 'あ』']), ('regression: hang followed by closer', ['(日おあ」『こか、語。)本文っ、文えあゃ。', 5], ['(日おあ」', '『こか、', '語。)本', '文っ、文え', 'あゃ。']), ('regression: hang followed by closer', ['日組こ、『っ、ー日ーあ』っ「、き「字っ', 6], ['日組こ、', '『っ、ー日ー', 'あ』っ「、き', '「字っ']), ('period hangs past the measure', ['日本語文。字組版', 4], ['日本語文。', '字組版']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('control layout', ['かい』けえ』ゃ』版日けっ)', 7], ['かい』け', 'え』ゃ』版日', 'けっ)']), ('control layout', ['文くこ、』本)。版(』(『いえ『本こ」かっか', 4], ['文く', 'こ、』', '本)。版', '(』', '(『いえ', '『本こ」', 'かっか'])], [('regression: hang followed by closer', ['うこ文版」」。。か字えーっあ」っけ』いか語いっ', 6], ['うこ文', '版」」。。か', '字えーっ', 'あ」っけ』い', 'か語いっ']), ('regression: hang followed by closer', ['いあ『本く)く。ー', 3], ['いあ', '『本', 'く)', 'く。ー']), ('regression: hang followed by closer', ['くけおけあき組。か語おき「版(。っ組えく組', 5], ['くけおけあ', 'き組。か語', 'おき「版', '(。っ組え', 'く組']), ('partial-repair probe', ['』あ「組えか語おえきゃ)組。あ文、『」えこう', 8], ['』あ「組えか語お', 'えきゃ)組。あ文、', '『」えこう']), ('period followed by bracket cannot hang', ['日本語文。」字組', 4], ['日本語', '文。」字', '組']), ('closing bracket pushes out', ['日本語文」字組版', 4], ['日本語', '文」字組', '版']), ('control layout', ['、ーく」ゃ』』ー本え組きけ本日こ』', 7], ['、ー', 'く」ゃ』』ー本', 'え組きけ本日', 'こ』']), ('control layout', ['組本)かゃ組っー', 6], ['組本)かゃ', '組っー'])]]
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 |
|---|---|---|---|
| period followed by bracket cannot hang | ['日本語', '文。」字', '組'] | ['日本語', '文。」字', '組'] | Passed |
| regression: hang followed by closer | ['くき)', '『いえ', '本(本', '『、', '字', ')', 'ー', '。っ」', '字'] | ['くき)', '『いえ', '本(本', '『、', '字', ')', 'ー', '。っ」', '字'] | Passed |
| regression: hang followed by closer | ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組'] | ['文字、」(ゃ日', 'き日』組', '文っー、、組本', 'きっ組'] | Passed |
| regression: hang followed by closer | ['「)。文', 'お。い', '組、、', 'い', ')', '、、っ」', 'け「あえ', 'いけ日、'] | ['「)。文', 'お。い', '組、、', 'い', ')', '、、っ」', 'け「あえ', 'いけ日、'] | Passed |
| closing bracket pushes out | ['日本語', '文」字組', '版'] | ['日本語', '文」字組', '版'] | Passed |
| small kana prohibited at line start | ['日本語', 'かっこい', 'い'] | ['日本語', 'かっこい', 'い'] | Passed |
| control layout | ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う'] | ['か本う', 'くい日', '「、け', '字ー', '『こ字', 'え。う'] | Passed |
| control layout | ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'] | ['け。。', '「)ゃお', 'お」けゃ」', 'かあうう)', 'か『か字い'] | Passed |
SHA-256 / 6e510f8eb015b28ee04b521daff4f6bc4b46fadbd18fe32d1695fda3eefe4379
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:49.874630+00:00.
Case digest / 1104469e61fb64fa26ad4915526501e80cef9fca3a1f4c6f0169e50521e48fb9