{"abstract":"Compound words marked with a non-joiner still form ligatures.","category":"Typography line breaking","checks":8,"contract":"Input [words, width]. Glyph widths: i,l,j,.,, 4; t,f 6; m 15; w 14; M 16; W 18; other lowercase 10; other uppercase 13; space 5. Within a word, fi/fl/ff form ligatures (11/11/12) with no kerning into or out of them; case-sensitive kern pairs apply between adjacent glyphs; \"|\" is a non-joiner (invisible, blocks ligatures and kerning). No kerning across spaces. Greedy fill. Return [[text, width]].","evaluation_group":"w2-typography-line-breaking-kern-ligature-measure","failed_approach":"Skipping the non-joiner without resetting the kerning state still kerns across it.","family":"w2-typography-line-breaking-kern-ligature-measure-non-joiner-handling","id":"FA-80176","implementations":{"attempt":{"sha256":"0f7951b0798e21a336c832729ab2c5d4cd40e344b8d0e910e33177b2d502f938","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    words, width = x\n    W = {'i': 4, 'l': 4, 'j': 4, '.': 4, ',': 4, 't': 6, 'f': 6, 'm': 15, 'w': 14, 'M': 16, 'W': 18}\n    LIG = {'fi': 11, 'fl': 11, 'ff': 12}\n    KERN = {'AV': -3, 'VA': -3, 'To': -2, 'Ta': -2, 'Yo': -2, 'LT': -3, 'Wa': -2, 'av': -1, 'va': -1, 'y.': -2, 'r.': -2, 'l.': -1, 'f.': -1, 'Va': -2}\n    SPACE = 5\n    def glyph(c):\n        return W.get(c, 13 if c.isupper() else 10)\n    def measure(w):\n        total, prev, i = 0, None, 0\n        while i < len(w):\n            if w[i] == '|':\n                i += 1\n                continue\n            pair = w[i:i + 2]\n            if pair in LIG:\n                total += LIG[pair]\n                prev = None\n                i += 2\n                continue\n            g = w[i]\n            total += glyph(g)\n            if prev is not None:\n                total += KERN.get(prev + g, 0)\n            prev = g\n            i += 1\n        return total\n    def line_width(ws):\n        return sum(measure(t) for t in ws) + SPACE * (len(ws) - 1)\n    lines, cur = [], []\n    for w in words:\n        cand = cur + [w]\n        if not cur or line_width(cand) <= width:\n            cur = cand\n        else:\n            lines.append(cur)\n            cur = [w]\n    if cur:\n        lines.append(cur)\n    return [[' '.join(t.replace('|', '') for t in ln), line_width(ln)] for ln in lines]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('regression: non-joiner handling', [['LA', 'fl.', 'av', 'LA|VALLE', 'Vat', 'Wavy'], 112], [['LA fl. av', 70], ['LAVALLE', 88], ['Vat Wavy', 77]]), ('regression: non-joiner handling', [['LA|VALLE', 'LA', 'y.'], 128], [['LAVALLE LA', 119], ['y.', 12]]), ('regression: non-joiner handling', [['Tofu', 'LA|VALLE', 'flow'], 134], [['Tofu LAVALLE', 130], ['flow', 35]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['fly.', 'fi', 'fl.', 'av'], 74], [['fly. fi fl.', 59], ['av', 19]]), ('control layout', [['LA', 'VIA'], 102], [['LA VIA', 70]])], [('regression: non-joiner handling', [['shelf|life', 'AVAIL', 'LA|VALLE', 'Wavy', 'Tofu', 'Vat', 'y.'], 131], [['shelflife AVAIL', 128], ['LAVALLE', 88], ['Wavy Tofu Vat', 119], ['y.', 12]]), ('regression: non-joiner handling', [['office', 'wolf|like', 'fl.', 'y.', 'fl.'], 72], [['office', 46], ['wolflike', 62], ['fl. y. fl.', 52]]), ('regression: non-joiner handling', [['office', 'LT', 'Wavy', 'AT', 'Vat', 'LA|VALLE', 'our'], 65], [['office', 46], ['LT', 23], ['Wavy', 45], ['AT Vat', 58], ['LAVALLE', 88], ['our', 30]]), ('regression: non-joiner handling', [['LA|VALLE', 'VIA', 'raffle', 'dry.'], 97], [['LAVALLE', 88], ['VIA raffle', 90], ['dry.', 32]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('cross-word pair must not kern', [['LA', 'Vat'], 200], [['LA Vat', 58]]), ('control layout', [['fly.', 'flow', 'Wavy', 'av', 'LT'], 132], [['fly. flow Wavy', 113], ['av LT', 47]]), ('control layout', [['LA', 'office', 'fl.', 'VIA', 'LA'], 96], [['LA office', 77], ['fl. VIA LA', 90]])], [('regression: non-joiner handling', [['LA|VALLE', 'fl.'], 138], [['LAVALLE fl.', 108]]), ('regression: non-joiner handling', [['LA', 'fl.', 'av', 'LA|VALLE', 'Vat', 'Wavy'], 112], [['LA fl. av', 70], ['LAVALLE', 88], ['Vat Wavy', 77]]), ('regression: non-joiner handling', [['LA|VALLE', 'shelf|life', 'office', 'AT', 'wolf|like'], 116], [['LAVALLE', 88], ['shelflife office', 115], ['AT wolflike', 93]]), ('regression: non-joiner handling', [['Yo', 'LA|VALLE', 'Tofu', 'Ta', 'Av'], 56], [['Yo', 21], ['LAVALLE', 88], ['Tofu', 37], ['Ta Av', 49]]), ('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['our', 'av', 'AT', 'Yo'], 92], [['our av AT', 85], ['Yo', 21]]), ('control layout', [['fl.', 'Yo', 'Tofu'], 112], [['fl. Yo Tofu', 83]])], [('regression: non-joiner handling', [['LA|VALLE', 'office', 'raffle', 'LA', 'staff.'], 129], [['LAVALLE', 88], ['office raffle LA', 128], ['staff.', 42]]), ('regression: non-joiner handling', [['flow', 'shelf|life', 'Wavy', 'AVAIL', 'dry.'], 88], [['flow', 35], ['shelflife', 64], ['Wavy', 45], ['AVAIL', 59], ['dry.', 32]]), ('regression: non-joiner handling', [['LA|VALLE', 'flow', 'y.', 'dry.', 'AVAIL', 'LA'], 106], [['LAVALLE', 88], ['flow y. dry.', 89], ['AVAIL LA', 90]]), ('regression: non-joiner handling', [['LA|VALLE', 'shelf|life'], 127], [['LAVALLE', 88], ['shelflife', 64]]), ('cross-word pair must not kern', [['LA', 'Vat'], 200], [['LA Vat', 58]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['AT', 'raffle', 'Wavy', 'Vat', 'AT', 'dry.', 'AVAIL'], 98], [['AT raffle', 77], ['Wavy Vat', 77], ['AT dry.', 63], ['AVAIL', 59]]), ('control layout', [['VIA', 'flow', 'dry.', 'y.', 'AVAIL', 'fl.', 'av'], 42], [['VIA', 39], ['flow', 35], ['dry.', 32], ['y.', 12], ['AVAIL', 59], ['fl. av', 39]])], [('regression: non-joiner handling', [['fi', 'flow', 'shelf|life', 'LA', 'our', 'Yo'], 104], [['fi flow', 51], ['shelflife LA', 95], ['our Yo', 56]]), ('regression: non-joiner handling', [['wolf|like', 'Tofu', 'Yo', 'AVAIL', 'Wavy', 'Av'], 108], [['wolflike Tofu', 104], ['Yo AVAIL', 85], ['Wavy Av', 73]]), ('regression: non-joiner handling', [['fly.', 'LA|VALLE'], 52], [['fly.', 23], ['LAVALLE', 88]]), ('regression: non-joiner handling', [['Ta', 'raffle', 'VIA', 'LA|VALLE'], 66], [['Ta', 21], ['raffle', 46], ['VIA', 39], ['LAVALLE', 88]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('control layout', [['Wavy', 'fi', 'Av', 'LT'], 86], [['Wavy fi', 61], ['Av LT', 51]]), ('control layout', [['fi', 'y.', 'fly.', 'office'], 58], [['fi y. fly.', 56], ['office', 46]])]]\nfor label, args, expected in fixtures[N - 1]:\n    check(label, solve(args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"d442c92794f2812f740494d16f9e8214c36989ed4cac5e19fc0fc4c0ff8a1418","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    words, width = x\n    W = {'i': 4, 'l': 4, 'j': 4, '.': 4, ',': 4, 't': 6, 'f': 6, 'm': 15, 'w': 14, 'M': 16, 'W': 18}\n    LIG = {'fi': 11, 'fl': 11, 'ff': 12}\n    KERN = {'AV': -3, 'VA': -3, 'To': -2, 'Ta': -2, 'Yo': -2, 'LT': -3, 'Wa': -2, 'av': -1, 'va': -1, 'y.': -2, 'r.': -2, 'l.': -1, 'f.': -1, 'Va': -2}\n    SPACE = 5\n    def glyph(c):\n        return W.get(c, 13 if c.isupper() else 10)\n    def measure(w):\n        w = w.replace('|', '')\n        total, prev, i = 0, None, 0\n        while i < len(w):\n            if w[i] == '|':\n                prev = None\n                i += 1\n                continue\n            pair = w[i:i + 2]\n            if pair in LIG:\n                total += LIG[pair]\n                prev = None\n                i += 2\n                continue\n            g = w[i]\n            total += glyph(g)\n            if prev is not None:\n                total += KERN.get(prev + g, 0)\n            prev = g\n            i += 1\n        return total\n    def line_width(ws):\n        return sum(measure(t) for t in ws) + SPACE * (len(ws) - 1)\n    lines, cur = [], []\n    for w in words:\n        cand = cur + [w]\n        if not cur or line_width(cand) <= width:\n            cur = cand\n        else:\n            lines.append(cur)\n            cur = [w]\n    if cur:\n        lines.append(cur)\n    return [[' '.join(t.replace('|', '') for t in ln), line_width(ln)] for ln in lines]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('regression: non-joiner handling', [['LA', 'fl.', 'av', 'LA|VALLE', 'Vat', 'Wavy'], 112], [['LA fl. av', 70], ['LAVALLE', 88], ['Vat Wavy', 77]]), ('regression: non-joiner handling', [['LA|VALLE', 'LA', 'y.'], 128], [['LAVALLE LA', 119], ['y.', 12]]), ('regression: non-joiner handling', [['Tofu', 'LA|VALLE', 'flow'], 134], [['Tofu LAVALLE', 130], ['flow', 35]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['fly.', 'fi', 'fl.', 'av'], 74], [['fly. fi fl.', 59], ['av', 19]]), ('control layout', [['LA', 'VIA'], 102], [['LA VIA', 70]])], [('regression: non-joiner handling', [['shelf|life', 'AVAIL', 'LA|VALLE', 'Wavy', 'Tofu', 'Vat', 'y.'], 131], [['shelflife AVAIL', 128], ['LAVALLE', 88], ['Wavy Tofu Vat', 119], ['y.', 12]]), ('regression: non-joiner handling', [['office', 'wolf|like', 'fl.', 'y.', 'fl.'], 72], [['office', 46], ['wolflike', 62], ['fl. y. fl.', 52]]), ('regression: non-joiner handling', [['office', 'LT', 'Wavy', 'AT', 'Vat', 'LA|VALLE', 'our'], 65], [['office', 46], ['LT', 23], ['Wavy', 45], ['AT Vat', 58], ['LAVALLE', 88], ['our', 30]]), ('regression: non-joiner handling', [['LA|VALLE', 'VIA', 'raffle', 'dry.'], 97], [['LAVALLE', 88], ['VIA raffle', 90], ['dry.', 32]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('cross-word pair must not kern', [['LA', 'Vat'], 200], [['LA Vat', 58]]), ('control layout', [['fly.', 'flow', 'Wavy', 'av', 'LT'], 132], [['fly. flow Wavy', 113], ['av LT', 47]]), ('control layout', [['LA', 'office', 'fl.', 'VIA', 'LA'], 96], [['LA office', 77], ['fl. VIA LA', 90]])], [('regression: non-joiner handling', [['LA|VALLE', 'fl.'], 138], [['LAVALLE fl.', 108]]), ('regression: non-joiner handling', [['LA', 'fl.', 'av', 'LA|VALLE', 'Vat', 'Wavy'], 112], [['LA fl. av', 70], ['LAVALLE', 88], ['Vat Wavy', 77]]), ('regression: non-joiner handling', [['LA|VALLE', 'shelf|life', 'office', 'AT', 'wolf|like'], 116], [['LAVALLE', 88], ['shelflife office', 115], ['AT wolflike', 93]]), ('regression: non-joiner handling', [['Yo', 'LA|VALLE', 'Tofu', 'Ta', 'Av'], 56], [['Yo', 21], ['LAVALLE', 88], ['Tofu', 37], ['Ta Av', 49]]), ('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['our', 'av', 'AT', 'Yo'], 92], [['our av AT', 85], ['Yo', 21]]), ('control layout', [['fl.', 'Yo', 'Tofu'], 112], [['fl. Yo Tofu', 83]])], [('regression: non-joiner handling', [['LA|VALLE', 'office', 'raffle', 'LA', 'staff.'], 129], [['LAVALLE', 88], ['office raffle LA', 128], ['staff.', 42]]), ('regression: non-joiner handling', [['flow', 'shelf|life', 'Wavy', 'AVAIL', 'dry.'], 88], [['flow', 35], ['shelflife', 64], ['Wavy', 45], ['AVAIL', 59], ['dry.', 32]]), ('regression: non-joiner handling', [['LA|VALLE', 'flow', 'y.', 'dry.', 'AVAIL', 'LA'], 106], [['LAVALLE', 88], ['flow y. dry.', 89], ['AVAIL LA', 90]]), ('regression: non-joiner handling', [['LA|VALLE', 'shelf|life'], 127], [['LAVALLE', 88], ['shelflife', 64]]), ('cross-word pair must not kern', [['LA', 'Vat'], 200], [['LA Vat', 58]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['AT', 'raffle', 'Wavy', 'Vat', 'AT', 'dry.', 'AVAIL'], 98], [['AT raffle', 77], ['Wavy Vat', 77], ['AT dry.', 63], ['AVAIL', 59]]), ('control layout', [['VIA', 'flow', 'dry.', 'y.', 'AVAIL', 'fl.', 'av'], 42], [['VIA', 39], ['flow', 35], ['dry.', 32], ['y.', 12], ['AVAIL', 59], ['fl. av', 39]])], [('regression: non-joiner handling', [['fi', 'flow', 'shelf|life', 'LA', 'our', 'Yo'], 104], [['fi flow', 51], ['shelflife LA', 95], ['our Yo', 56]]), ('regression: non-joiner handling', [['wolf|like', 'Tofu', 'Yo', 'AVAIL', 'Wavy', 'Av'], 108], [['wolflike Tofu', 104], ['Yo AVAIL', 85], ['Wavy Av', 73]]), ('regression: non-joiner handling', [['fly.', 'LA|VALLE'], 52], [['fly.', 23], ['LAVALLE', 88]]), ('regression: non-joiner handling', [['Ta', 'raffle', 'VIA', 'LA|VALLE'], 66], [['Ta', 21], ['raffle', 46], ['VIA', 39], ['LAVALLE', 88]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('control layout', [['Wavy', 'fi', 'Av', 'LT'], 86], [['Wavy fi', 61], ['Av LT', 51]]), ('control layout', [['fi', 'y.', 'fly.', 'office'], 58], [['fi y. fly.', 56], ['office', 46]])]]\nfor label, args, expected in fixtures[N - 1]:\n    check(label, solve(args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"fd9d208b6b3f2a68b9a04de47ddf6443f3c9a74bae6579055f2b77f2abbb05ce","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    words, width = x\n    W = {'i': 4, 'l': 4, 'j': 4, '.': 4, ',': 4, 't': 6, 'f': 6, 'm': 15, 'w': 14, 'M': 16, 'W': 18}\n    LIG = {'fi': 11, 'fl': 11, 'ff': 12}\n    KERN = {'AV': -3, 'VA': -3, 'To': -2, 'Ta': -2, 'Yo': -2, 'LT': -3, 'Wa': -2, 'av': -1, 'va': -1, 'y.': -2, 'r.': -2, 'l.': -1, 'f.': -1, 'Va': -2}\n    SPACE = 5\n    def glyph(c):\n        return W.get(c, 13 if c.isupper() else 10)\n    def measure(w):\n        total, prev, i = 0, None, 0\n        while i < len(w):\n            if w[i] == '|':\n                prev = None\n                i += 1\n                continue\n            pair = w[i:i + 2]\n            if pair in LIG:\n                total += LIG[pair]\n                prev = None\n                i += 2\n                continue\n            g = w[i]\n            total += glyph(g)\n            if prev is not None:\n                total += KERN.get(prev + g, 0)\n            prev = g\n            i += 1\n        return total\n    def line_width(ws):\n        return sum(measure(t) for t in ws) + SPACE * (len(ws) - 1)\n    lines, cur = [], []\n    for w in words:\n        cand = cur + [w]\n        if not cur or line_width(cand) <= width:\n            cur = cand\n        else:\n            lines.append(cur)\n            cur = [w]\n    if cur:\n        lines.append(cur)\n    return [[' '.join(t.replace('|', '') for t in ln), line_width(ln)] for ln in lines]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('regression: non-joiner handling', [['LA', 'fl.', 'av', 'LA|VALLE', 'Vat', 'Wavy'], 112], [['LA fl. av', 70], ['LAVALLE', 88], ['Vat Wavy', 77]]), ('regression: non-joiner handling', [['LA|VALLE', 'LA', 'y.'], 128], [['LAVALLE LA', 119], ['y.', 12]]), ('regression: non-joiner handling', [['Tofu', 'LA|VALLE', 'flow'], 134], [['Tofu LAVALLE', 130], ['flow', 35]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['fly.', 'fi', 'fl.', 'av'], 74], [['fly. fi fl.', 59], ['av', 19]]), ('control layout', [['LA', 'VIA'], 102], [['LA VIA', 70]])], [('regression: non-joiner handling', [['shelf|life', 'AVAIL', 'LA|VALLE', 'Wavy', 'Tofu', 'Vat', 'y.'], 131], [['shelflife AVAIL', 128], ['LAVALLE', 88], ['Wavy Tofu Vat', 119], ['y.', 12]]), ('regression: non-joiner handling', [['office', 'wolf|like', 'fl.', 'y.', 'fl.'], 72], [['office', 46], ['wolflike', 62], ['fl. y. fl.', 52]]), ('regression: non-joiner handling', [['office', 'LT', 'Wavy', 'AT', 'Vat', 'LA|VALLE', 'our'], 65], [['office', 46], ['LT', 23], ['Wavy', 45], ['AT Vat', 58], ['LAVALLE', 88], ['our', 30]]), ('regression: non-joiner handling', [['LA|VALLE', 'VIA', 'raffle', 'dry.'], 97], [['LAVALLE', 88], ['VIA raffle', 90], ['dry.', 32]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('cross-word pair must not kern', [['LA', 'Vat'], 200], [['LA Vat', 58]]), ('control layout', [['fly.', 'flow', 'Wavy', 'av', 'LT'], 132], [['fly. flow Wavy', 113], ['av LT', 47]]), ('control layout', [['LA', 'office', 'fl.', 'VIA', 'LA'], 96], [['LA office', 77], ['fl. VIA LA', 90]])], [('regression: non-joiner handling', [['LA|VALLE', 'fl.'], 138], [['LAVALLE fl.', 108]]), ('regression: non-joiner handling', [['LA', 'fl.', 'av', 'LA|VALLE', 'Vat', 'Wavy'], 112], [['LA fl. av', 70], ['LAVALLE', 88], ['Vat Wavy', 77]]), ('regression: non-joiner handling', [['LA|VALLE', 'shelf|life', 'office', 'AT', 'wolf|like'], 116], [['LAVALLE', 88], ['shelflife office', 115], ['AT wolflike', 93]]), ('regression: non-joiner handling', [['Yo', 'LA|VALLE', 'Tofu', 'Ta', 'Av'], 56], [['Yo', 21], ['LAVALLE', 88], ['Tofu', 37], ['Ta Av', 49]]), ('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['our', 'av', 'AT', 'Yo'], 92], [['our av AT', 85], ['Yo', 21]]), ('control layout', [['fl.', 'Yo', 'Tofu'], 112], [['fl. Yo Tofu', 83]])], [('regression: non-joiner handling', [['LA|VALLE', 'office', 'raffle', 'LA', 'staff.'], 129], [['LAVALLE', 88], ['office raffle LA', 128], ['staff.', 42]]), ('regression: non-joiner handling', [['flow', 'shelf|life', 'Wavy', 'AVAIL', 'dry.'], 88], [['flow', 35], ['shelflife', 64], ['Wavy', 45], ['AVAIL', 59], ['dry.', 32]]), ('regression: non-joiner handling', [['LA|VALLE', 'flow', 'y.', 'dry.', 'AVAIL', 'LA'], 106], [['LAVALLE', 88], ['flow y. dry.', 89], ['AVAIL LA', 90]]), ('regression: non-joiner handling', [['LA|VALLE', 'shelf|life'], 127], [['LAVALLE', 88], ['shelflife', 64]]), ('cross-word pair must not kern', [['LA', 'Vat'], 200], [['LA Vat', 58]]), ('ligature then period', [['fl.', 'fi,'], 200], [['fl. fi,', 35]]), ('control layout', [['AT', 'raffle', 'Wavy', 'Vat', 'AT', 'dry.', 'AVAIL'], 98], [['AT raffle', 77], ['Wavy Vat', 77], ['AT dry.', 63], ['AVAIL', 59]]), ('control layout', [['VIA', 'flow', 'dry.', 'y.', 'AVAIL', 'fl.', 'av'], 42], [['VIA', 39], ['flow', 35], ['dry.', 32], ['y.', 12], ['AVAIL', 59], ['fl. av', 39]])], [('regression: non-joiner handling', [['fi', 'flow', 'shelf|life', 'LA', 'our', 'Yo'], 104], [['fi flow', 51], ['shelflife LA', 95], ['our Yo', 56]]), ('regression: non-joiner handling', [['wolf|like', 'Tofu', 'Yo', 'AVAIL', 'Wavy', 'Av'], 108], [['wolflike Tofu', 104], ['Yo AVAIL', 85], ['Wavy Av', 73]]), ('regression: non-joiner handling', [['fly.', 'LA|VALLE'], 52], [['fly.', 23], ['LAVALLE', 88]]), ('regression: non-joiner handling', [['Ta', 'raffle', 'VIA', 'LA|VALLE'], 66], [['Ta', 21], ['raffle', 46], ['VIA', 39], ['LAVALLE', 88]]), ('case-sensitive pair', [['Av', 'av'], 200], [['Av av', 47]]), ('non-joiner blocks ligature', [['shelf|life'], 200], [['shelflife', 64]]), ('control layout', [['Wavy', 'fi', 'Av', 'LT'], 86], [['Wavy fi', 61], ['Av LT', 51]]), ('control layout', [['fi', 'y.', 'fly.', 'office'], 58], [['fi y. fly.', 56], ['office', 46]])]]\nfor label, args, expected in fixtures[N - 1]:\n    check(label, solve(args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"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.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-typography-line-breaking-kern-ligature-measure-non-joiner-handling","generated_at":"2026-09-29T14:49:51.554503+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Line breaking decides where paragraphs wrap on screen and in print; a wrong decision point shifts every following line.","repair":"Treat the non-joiner as an invisible barrier that blocks ligatures and kerning.","root_cause":"Non-joiners are stripped before measuring, letting ligatures form across them.","sha256":"4668a507428cfb3d7b5391aa4521aedd95d7a79add2b5455d1c6b570982b5cd7","title":"Kerning and ligature line measure: non-joiner handling · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":46.515,"exit_code":1,"observations":[{"actual":[["shelflife",64]],"check":"non-joiner blocks ligature","expected":[["shelflife",64]],"passed":true},{"actual":[["LA fl. av",70],["LAVALLE",85],["Vat Wavy",77]],"check":"regression: non-joiner handling","expected":[["LA fl. av",70],["LAVALLE",88],["Vat Wavy",77]],"passed":false},{"actual":[["LAVALLE LA",116],["y.",12]],"check":"regression: non-joiner handling","expected":[["LAVALLE LA",119],["y.",12]],"passed":false},{"actual":[["Tofu LAVALLE",127],["flow",35]],"check":"regression: non-joiner handling","expected":[["Tofu LAVALLE",130],["flow",35]],"passed":false},{"actual":[["Av av",47]],"check":"case-sensitive pair","expected":[["Av av",47]],"passed":true},{"actual":[["fl. fi,",35]],"check":"ligature then period","expected":[["fl. fi,",35]],"passed":true},{"actual":[["fly. fi fl.",59],["av",19]],"check":"control layout","expected":[["fly. fi fl.",59],["av",19]],"passed":true},{"actual":[["LA VIA",70]],"check":"control layout","expected":[["LA VIA",70]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"non-joiner blocks ligature\", \"actual\": [[\"shelflife\", 64]], \"expected\": [[\"shelflife\", 64]], \"passed\": true}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"LA fl. av\", 70], [\"LAVALLE\", 85], [\"Vat Wavy\", 77]], \"expected\": [[\"LA fl. av\", 70], [\"LAVALLE\", 88], [\"Vat Wavy\", 77]], \"passed\": false}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"LAVALLE LA\", 116], [\"y.\", 12]], \"expected\": [[\"LAVALLE LA\", 119], [\"y.\", 12]], \"passed\": false}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"Tofu LAVALLE\", 127], [\"flow\", 35]], \"expected\": [[\"Tofu LAVALLE\", 130], [\"flow\", 35]], \"passed\": false}, {\"check\": \"case-sensitive pair\", \"actual\": [[\"Av av\", 47]], \"expected\": [[\"Av av\", 47]], \"passed\": true}, {\"check\": \"ligature then period\", \"actual\": [[\"fl. fi,\", 35]], \"expected\": [[\"fl. fi,\", 35]], \"passed\": true}, {\"check\": \"control layout\", \"actual\": [[\"fly. fi fl.\", 59], [\"av\", 19]], \"expected\": [[\"fly. fi fl.\", 59], [\"av\", 19]], \"passed\": true}, {\"check\": \"control layout\", \"actual\": [[\"LA VIA\", 70]], \"expected\": [[\"LA VIA\", 70]], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":42.899,"exit_code":1,"observations":[{"actual":[["shelflife",65]],"check":"non-joiner blocks ligature","expected":[["shelflife",64]],"passed":false},{"actual":[["LA fl. av",70],["LAVALLE",85],["Vat Wavy",77]],"check":"regression: non-joiner handling","expected":[["LA fl. av",70],["LAVALLE",88],["Vat Wavy",77]],"passed":false},{"actual":[["LAVALLE LA",116],["y.",12]],"check":"regression: non-joiner handling","expected":[["LAVALLE LA",119],["y.",12]],"passed":false},{"actual":[["Tofu LAVALLE",127],["flow",35]],"check":"regression: non-joiner handling","expected":[["Tofu LAVALLE",130],["flow",35]],"passed":false},{"actual":[["Av av",47]],"check":"case-sensitive pair","expected":[["Av av",47]],"passed":true},{"actual":[["fl. fi,",35]],"check":"ligature then period","expected":[["fl. fi,",35]],"passed":true},{"actual":[["fly. fi fl.",59],["av",19]],"check":"control layout","expected":[["fly. fi fl.",59],["av",19]],"passed":true},{"actual":[["LA VIA",70]],"check":"control layout","expected":[["LA VIA",70]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"non-joiner blocks ligature\", \"actual\": [[\"shelflife\", 65]], \"expected\": [[\"shelflife\", 64]], \"passed\": false}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"LA fl. av\", 70], [\"LAVALLE\", 85], [\"Vat Wavy\", 77]], \"expected\": [[\"LA fl. av\", 70], [\"LAVALLE\", 88], [\"Vat Wavy\", 77]], \"passed\": false}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"LAVALLE LA\", 116], [\"y.\", 12]], \"expected\": [[\"LAVALLE LA\", 119], [\"y.\", 12]], \"passed\": false}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"Tofu LAVALLE\", 127], [\"flow\", 35]], \"expected\": [[\"Tofu LAVALLE\", 130], [\"flow\", 35]], \"passed\": false}, {\"check\": \"case-sensitive pair\", \"actual\": [[\"Av av\", 47]], \"expected\": [[\"Av av\", 47]], \"passed\": true}, {\"check\": \"ligature then period\", \"actual\": [[\"fl. fi,\", 35]], \"expected\": [[\"fl. fi,\", 35]], \"passed\": true}, {\"check\": \"control layout\", \"actual\": [[\"fly. fi fl.\", 59], [\"av\", 19]], \"expected\": [[\"fly. fi fl.\", 59], [\"av\", 19]], \"passed\": true}, {\"check\": \"control layout\", \"actual\": [[\"LA VIA\", 70]], \"expected\": [[\"LA VIA\", 70]], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":42.754,"exit_code":0,"observations":[{"actual":[["shelflife",64]],"check":"non-joiner blocks ligature","expected":[["shelflife",64]],"passed":true},{"actual":[["LA fl. av",70],["LAVALLE",88],["Vat Wavy",77]],"check":"regression: non-joiner handling","expected":[["LA fl. av",70],["LAVALLE",88],["Vat Wavy",77]],"passed":true},{"actual":[["LAVALLE LA",119],["y.",12]],"check":"regression: non-joiner handling","expected":[["LAVALLE LA",119],["y.",12]],"passed":true},{"actual":[["Tofu LAVALLE",130],["flow",35]],"check":"regression: non-joiner handling","expected":[["Tofu LAVALLE",130],["flow",35]],"passed":true},{"actual":[["Av av",47]],"check":"case-sensitive pair","expected":[["Av av",47]],"passed":true},{"actual":[["fl. fi,",35]],"check":"ligature then period","expected":[["fl. fi,",35]],"passed":true},{"actual":[["fly. fi fl.",59],["av",19]],"check":"control layout","expected":[["fly. fi fl.",59],["av",19]],"passed":true},{"actual":[["LA VIA",70]],"check":"control layout","expected":[["LA VIA",70]],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"non-joiner blocks ligature\", \"actual\": [[\"shelflife\", 64]], \"expected\": [[\"shelflife\", 64]], \"passed\": true}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"LA fl. av\", 70], [\"LAVALLE\", 88], [\"Vat Wavy\", 77]], \"expected\": [[\"LA fl. av\", 70], [\"LAVALLE\", 88], [\"Vat Wavy\", 77]], \"passed\": true}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"LAVALLE LA\", 119], [\"y.\", 12]], \"expected\": [[\"LAVALLE LA\", 119], [\"y.\", 12]], \"passed\": true}, {\"check\": \"regression: non-joiner handling\", \"actual\": [[\"Tofu LAVALLE\", 130], [\"flow\", 35]], \"expected\": [[\"Tofu LAVALLE\", 130], [\"flow\", 35]], \"passed\": true}, {\"check\": \"case-sensitive pair\", \"actual\": [[\"Av av\", 47]], \"expected\": [[\"Av av\", 47]], \"passed\": true}, {\"check\": \"ligature then period\", \"actual\": [[\"fl. fi,\", 35]], \"expected\": [[\"fl. fi,\", 35]], \"passed\": true}, {\"check\": \"control layout\", \"actual\": [[\"fly. fi fl.\", 59], [\"av\", 19]], \"expected\": [[\"fly. fi fl.\", 59], [\"av\", 19]], \"passed\": true}, {\"check\": \"control layout\", \"actual\": [[\"LA VIA\", 70]], \"expected\": [[\"LA VIA\", 70]], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}