FAILURE MAP
← Case archive

FA-75836 / Text diff and three-way merge / Open access

Diffstat path truncation: the directory separator is dropped after the ellipsis · case 01

Truncated paths read "...file.py" instead of ".../file.py", hiding that a directory was cut.

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

ROOT CAUSE

The cut starts after the slash instead of at it.

VERIFIED REPAIR

Cut the tail at the first slash and keep the slash.

Unsuccessful approach: Cutting at the last slash discards more of the path than necessary.

Case contract

A path longer than width is shown as "..." plus its last width-3 characters, further shortened to start at the first "/" inside that tail when there is one (keeping the slash). Paths not longer than width are unchanged.

Why this case matters

Narrow terminals truncate long paths in diffstat output; the rule keeps the most informative part of the path.

1 / The failure

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

N = 1
observations = []
def solve(names, width):
    res = []
    for name in names:
        if len(name) <= width:
            res.append(name)
            continue
        keep = width - 3
        tail = name[len(name) - keep:] if keep > 0 else ''
        slash = tail.find('/')
        if slash >= 0:
            tail = tail[slash + 1:]
        res.append('...' + tail)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    2: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    3: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    4: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    5: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
}[N]
for label, args, expected in cases:
    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
short name unchanged['src/a.c']['src/a.c']Passed
name exactly the width['abcdefghij']['abcdefghij']Passed
long name cut at a directory boundary['...file_name.py']['.../file_name.py']Failed
no slash in the kept tail['...ename.txt']['...ename.txt']Passed
several names['...g/h.txt', 'x.c', '...yyyyyyyyy']['.../g/h.txt', 'x.c', '...yyyyyyyyy']Failed
tail starts exactly at a slash['...cc']['.../cc']Failed
width just above the name['p/q/r.txt']['p/q/r.txt']Passed

SHA-256 / c85a20cdb26a0bd4056d8e57a7fca6bd67001217550461b2aa13bdb3a1ed6d37

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(names, width):
    res = []
    for name in names:
        if len(name) <= width:
            res.append(name)
            continue
        keep = width - 3
        tail = name[len(name) - keep:] if keep > 0 else ''
        slash = tail.rfind('/')
        if slash >= 0:
            tail = tail[slash:]
        res.append('...' + tail)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    2: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    3: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    4: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    5: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
}[N]
for label, args, expected in cases:
    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
short name unchanged['src/a.c']['src/a.c']Passed
name exactly the width['abcdefghij']['abcdefghij']Passed
long name cut at a directory boundary['.../file_name.py']['.../file_name.py']Passed
no slash in the kept tail['...ename.txt']['...ename.txt']Passed
several names['.../h.txt', 'x.c', '...yyyyyyyyy']['.../g/h.txt', 'x.c', '...yyyyyyyyy']Failed
tail starts exactly at a slash['.../cc']['.../cc']Passed
width just above the name['p/q/r.txt']['p/q/r.txt']Passed

SHA-256 / 358429a27b3feaa1ce5f10fc6e3f20d953e5674ec8c5bfb6969f6969e349797c

3 / The verified repair

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

N = 1
observations = []
def solve(names, width):
    res = []
    for name in names:
        if len(name) <= width:
            res.append(name)
            continue
        keep = width - 3
        tail = name[len(name) - keep:] if keep > 0 else ''
        slash = tail.find('/')
        if slash >= 0:
            tail = tail[slash:]
        res.append('...' + tail)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    2: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    3: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    4: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
    5: [('short name unchanged', [['src/a.c'], 20], ['src/a.c']), ('name exactly the width', [['abcdefghij'], 10], ['abcdefghij']), ('long name cut at a directory boundary', [['src/module/deep/file_name.py'], 18], ['.../file_name.py']), ('no slash in the kept tail', [['averyveryverylongfilename.txt'], 12], ['...ename.txt']), ('several names', [['a/b/c/d/e/f/g/h.txt', 'x.c', 'dir/yyyyyyyyyyyyyyy'], 12], ['.../g/h.txt', 'x.c', '...yyyyyyyyy']), ('tail starts exactly at a slash', [['aaaa/bbbb/cc'], 8], ['.../cc']), ('width just above the name', [['p/q/r.txt'], 10], ['p/q/r.txt'])],
}[N]
for label, args, expected in cases:
    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
short name unchanged['src/a.c']['src/a.c']Passed
name exactly the width['abcdefghij']['abcdefghij']Passed
long name cut at a directory boundary['.../file_name.py']['.../file_name.py']Passed
no slash in the kept tail['...ename.txt']['...ename.txt']Passed
several names['.../g/h.txt', 'x.c', '...yyyyyyyyy']['.../g/h.txt', 'x.c', '...yyyyyyyyy']Passed
tail starts exactly at a slash['.../cc']['.../cc']Passed
width just above the name['p/q/r.txt']['p/q/r.txt']Passed

SHA-256 / ff162986d34f41572b7f9289a68e9da9931d4ac6dd15db61df73d5a9e83f9967

Verification & scope

A deterministic, bounded teaching model of one diff, patch or merge rule with stipulated conventions; it is not a production diff or version-control implementation and makes no claim of conformance to any specific tool. 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:10.460177+00:00.

Case digest / 89793ada86fafa99d3394bd7bf53b3ba1433ed5b9b941977251f6b73713451a9