FA-21446 / Assistive announcements / Open access
Empty phrase creates a spoken empty packet · case 01
The announcement trace violates the stated sentence-packing contract.
ROOT CAUSE
Fault site: if e[1]: q.append([e[2],e[1]]) is implemented as q.append([e[2],e[1]])
VERIFIED REPAIR
Restore the stated transition: if e[1]: q.append([e[2],e[1]])
Unsuccessful approach: The attempted repair substitutes if e[1].strip(): q.append([e[2],e[1].strip()]) and still violates a regression oracle.
Case contract
Input operations configure character budget then append indivisible phrases [text,language]. Flush packs consecutive same-language phrases with one space while within budget. A phrase longer than budget is emitted alone intact. Language change always starts a new packet. Empty phrases are ignored. Break inserts hard boundary. Cancel removes queued phrases of one language. Returned packets are [language,text], queued phrase count and budget; flush consumes pending phrases.
Why this case matters
Deterministic controlled model of assistive announcement delivery.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
budget=10; q=[]; out=[]
for e in events:
if e[0]=='budget': budget=max(1,e[1])
elif e[0]=='phrase':
q.append([e[2],e[1]])
elif e[0]=='break': q.append(None)
elif e[0]=='cancel': q=[x for x in q if x is None or x[0]!=e[1]]
elif e[0]=='flush':
current=None
for row in q:
if row is None:
if current is not None: out.append(current); current=None
continue
if current is not None and current[0]==row[0] and len(current[1])+1+len(row[1])<=budget:
current[1]+=' '+row[1]
else:
if current is not None: out.append(current)
current=list(row)
if current is not None: out.append(current)
q.clear()
return [out,len(q),budget]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = ["[['budget',2*N+1],['phrase','a'*N,'en'],['phrase','b'*N,'en'],['phrase','c','en'],['flush']]", "[['budget',2*N],['phrase','a'*N,'en'],['phrase','b'*N,'en'],['flush']]", "[['budget',100],['phrase','hello'*N,'en-US'],['phrase','hi','en-GB'],['break'],['phrase','x','en-GB'],['flush']]", "[['phrase','a','en'],['break'],['phrase','b','en'],['phrase','non','fr'],['cancel','fr'],['flush']]", "[['budget',1],['phrase','oversize'*N,'en'],['flush']]", "[['budget',0],['phrase','','en'],['phrase',' ','en'],['flush']]", "[['flush'],['break'],['flush']]"]
expected = {1: [[[['en', 'a b'], ['en', 'c']], 0, 3], [[['en', 'a'], ['en', 'b']], 0, 2], [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 2: [[[['en', 'aa bb'], ['en', 'c']], 0, 5], [[['en', 'aa'], ['en', 'bb']], 0, 4], [[['en-US', 'hellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 3: [[[['en', 'aaa bbb'], ['en', 'c']], 0, 7], [[['en', 'aaa'], ['en', 'bbb']], 0, 6], [[['en-US', 'hellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 4: [[[['en', 'aaaa bbbb'], ['en', 'c']], 0, 9], [[['en', 'aaaa'], ['en', 'bbbb']], 0, 8], [[['en-US', 'hellohellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 5: [[[['en', 'aaaaa bbbbb'], ['en', 'c']], 0, 11], [[['en', 'aaaaa'], ['en', 'bbbbb']], 0, 10], [[['en-US', 'hellohellohellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]]}[N]
for i, expression in enumerate(fixtures):
check("trace-"+str(i+1), solve(eval(expression)), expected[i])
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 |
|---|---|---|---|
| trace-1 | [[['en', 'a b'], ['en', 'c']], 0, 3] | [[['en', 'a b'], ['en', 'c']], 0, 3] | Passed |
| trace-2 | [[['en', 'a'], ['en', 'b']], 0, 2] | [[['en', 'a'], ['en', 'b']], 0, 2] | Passed |
| trace-3 | [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100] | [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100] | Passed |
| trace-4 | [[['en', 'a'], ['en', 'b']], 0, 10] | [[['en', 'a'], ['en', 'b']], 0, 10] | Passed |
| trace-5 | [[['en', 'oversize']], 0, 1] | [[['en', 'oversize']], 0, 1] | Passed |
| trace-6 | [[['en', ''], ['en', ' ']], 0, 1] | [[['en', ' ']], 0, 1] | Failed |
| trace-7 | [[], 0, 10] | [[], 0, 10] | Passed |
SHA-256 / 15c9233e9a5a737affc4de23ffc853cd030b3895c3813d1767c7cd0a235f8bed
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
budget=10; q=[]; out=[]
for e in events:
if e[0]=='budget': budget=max(1,e[1])
elif e[0]=='phrase':
if e[1].strip(): q.append([e[2],e[1].strip()])
elif e[0]=='break': q.append(None)
elif e[0]=='cancel': q=[x for x in q if x is None or x[0]!=e[1]]
elif e[0]=='flush':
current=None
for row in q:
if row is None:
if current is not None: out.append(current); current=None
continue
if current is not None and current[0]==row[0] and len(current[1])+1+len(row[1])<=budget:
current[1]+=' '+row[1]
else:
if current is not None: out.append(current)
current=list(row)
if current is not None: out.append(current)
q.clear()
return [out,len(q),budget]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = ["[['budget',2*N+1],['phrase','a'*N,'en'],['phrase','b'*N,'en'],['phrase','c','en'],['flush']]", "[['budget',2*N],['phrase','a'*N,'en'],['phrase','b'*N,'en'],['flush']]", "[['budget',100],['phrase','hello'*N,'en-US'],['phrase','hi','en-GB'],['break'],['phrase','x','en-GB'],['flush']]", "[['phrase','a','en'],['break'],['phrase','b','en'],['phrase','non','fr'],['cancel','fr'],['flush']]", "[['budget',1],['phrase','oversize'*N,'en'],['flush']]", "[['budget',0],['phrase','','en'],['phrase',' ','en'],['flush']]", "[['flush'],['break'],['flush']]"]
expected = {1: [[[['en', 'a b'], ['en', 'c']], 0, 3], [[['en', 'a'], ['en', 'b']], 0, 2], [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 2: [[[['en', 'aa bb'], ['en', 'c']], 0, 5], [[['en', 'aa'], ['en', 'bb']], 0, 4], [[['en-US', 'hellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 3: [[[['en', 'aaa bbb'], ['en', 'c']], 0, 7], [[['en', 'aaa'], ['en', 'bbb']], 0, 6], [[['en-US', 'hellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 4: [[[['en', 'aaaa bbbb'], ['en', 'c']], 0, 9], [[['en', 'aaaa'], ['en', 'bbbb']], 0, 8], [[['en-US', 'hellohellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 5: [[[['en', 'aaaaa bbbbb'], ['en', 'c']], 0, 11], [[['en', 'aaaaa'], ['en', 'bbbbb']], 0, 10], [[['en-US', 'hellohellohellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]]}[N]
for i, expression in enumerate(fixtures):
check("trace-"+str(i+1), solve(eval(expression)), expected[i])
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 |
|---|---|---|---|
| trace-1 | [[['en', 'a b'], ['en', 'c']], 0, 3] | [[['en', 'a b'], ['en', 'c']], 0, 3] | Passed |
| trace-2 | [[['en', 'a'], ['en', 'b']], 0, 2] | [[['en', 'a'], ['en', 'b']], 0, 2] | Passed |
| trace-3 | [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100] | [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100] | Passed |
| trace-4 | [[['en', 'a'], ['en', 'b']], 0, 10] | [[['en', 'a'], ['en', 'b']], 0, 10] | Passed |
| trace-5 | [[['en', 'oversize']], 0, 1] | [[['en', 'oversize']], 0, 1] | Passed |
| trace-6 | [[], 0, 1] | [[['en', ' ']], 0, 1] | Failed |
| trace-7 | [[], 0, 10] | [[], 0, 10] | Passed |
SHA-256 / a4fb6c2a1b38803d0d0abd15b6ac9d8545a5d74cdd3e3f71eeb85e0eeaaa375b
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
budget=10; q=[]; out=[]
for e in events:
if e[0]=='budget': budget=max(1,e[1])
elif e[0]=='phrase':
if e[1]: q.append([e[2],e[1]])
elif e[0]=='break': q.append(None)
elif e[0]=='cancel': q=[x for x in q if x is None or x[0]!=e[1]]
elif e[0]=='flush':
current=None
for row in q:
if row is None:
if current is not None: out.append(current); current=None
continue
if current is not None and current[0]==row[0] and len(current[1])+1+len(row[1])<=budget:
current[1]+=' '+row[1]
else:
if current is not None: out.append(current)
current=list(row)
if current is not None: out.append(current)
q.clear()
return [out,len(q),budget]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = ["[['budget',2*N+1],['phrase','a'*N,'en'],['phrase','b'*N,'en'],['phrase','c','en'],['flush']]", "[['budget',2*N],['phrase','a'*N,'en'],['phrase','b'*N,'en'],['flush']]", "[['budget',100],['phrase','hello'*N,'en-US'],['phrase','hi','en-GB'],['break'],['phrase','x','en-GB'],['flush']]", "[['phrase','a','en'],['break'],['phrase','b','en'],['phrase','non','fr'],['cancel','fr'],['flush']]", "[['budget',1],['phrase','oversize'*N,'en'],['flush']]", "[['budget',0],['phrase','','en'],['phrase',' ','en'],['flush']]", "[['flush'],['break'],['flush']]"]
expected = {1: [[[['en', 'a b'], ['en', 'c']], 0, 3], [[['en', 'a'], ['en', 'b']], 0, 2], [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 2: [[[['en', 'aa bb'], ['en', 'c']], 0, 5], [[['en', 'aa'], ['en', 'bb']], 0, 4], [[['en-US', 'hellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 3: [[[['en', 'aaa bbb'], ['en', 'c']], 0, 7], [[['en', 'aaa'], ['en', 'bbb']], 0, 6], [[['en-US', 'hellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 4: [[[['en', 'aaaa bbbb'], ['en', 'c']], 0, 9], [[['en', 'aaaa'], ['en', 'bbbb']], 0, 8], [[['en-US', 'hellohellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]], 5: [[[['en', 'aaaaa bbbbb'], ['en', 'c']], 0, 11], [[['en', 'aaaaa'], ['en', 'bbbbb']], 0, 10], [[['en-US', 'hellohellohellohellohello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100], [[['en', 'a'], ['en', 'b']], 0, 10], [[['en', 'oversizeoversizeoversizeoversizeoversize']], 0, 1], [[['en', ' ']], 0, 1], [[], 0, 10]]}[N]
for i, expression in enumerate(fixtures):
check("trace-"+str(i+1), solve(eval(expression)), expected[i])
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 |
|---|---|---|---|
| trace-1 | [[['en', 'a b'], ['en', 'c']], 0, 3] | [[['en', 'a b'], ['en', 'c']], 0, 3] | Passed |
| trace-2 | [[['en', 'a'], ['en', 'b']], 0, 2] | [[['en', 'a'], ['en', 'b']], 0, 2] | Passed |
| trace-3 | [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100] | [[['en-US', 'hello'], ['en-GB', 'hi'], ['en-GB', 'x']], 0, 100] | Passed |
| trace-4 | [[['en', 'a'], ['en', 'b']], 0, 10] | [[['en', 'a'], ['en', 'b']], 0, 10] | Passed |
| trace-5 | [[['en', 'oversize']], 0, 1] | [[['en', 'oversize']], 0, 1] | Passed |
| trace-6 | [[['en', ' ']], 0, 1] | [[['en', ' ']], 0, 1] | Passed |
| trace-7 | [[], 0, 10] | [[], 0, 10] | Passed |
SHA-256 / da1ca7355cf76ead042847dbf73dcd40fe8d18850f7faa4140491419650630dc
Verification & scope
Stipulated bounded policy, not a browser, speech engine, platform API, or standards conformance claim. 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:40:28.906679+00:00.
Case digest / 95603caf6e913643b00fc37c7c72a249687c9b0132eaefde307862df750e496c