FA-21191 / Assistive announcements / Open access
New notice escalates relative to startup instead of creation · case 01
The announcement trace violates the stated escalation-ladder contract.
ROOT CAUSE
Fault site: if e[0]=='open': notices[e[1]]=[e[2],0,now+2] is implemented as if e[0]=='open': notices[e[1]]=[e[2],0,2]
VERIFIED REPAIR
Restore the stated transition: if e[0]=='open': notices[e[1]]=[e[2],0,now+2]
Unsuccessful approach: The attempted repair substitutes if e[0]=='open': notices.setdefault(e[1],[e[2],0,now+2]) and still violates a regression oracle.
Case contract
Unacknowledged notices have [text,level,next-due]. Open replaces notice at level0 due after2 ticks. Tick uses monotonic clock and emits at most one escalation per notice when due; levels1 and2 schedule another2 ticks, level3 is final and has no future due. Ack removes notice. Snooze adds delay to existing deadline, not now. Edit text preserves escalation level. Reset-level sets level0 and next due now+2. Report [id,text,level] speech and pending state.
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):
now=0; notices={}; out=[]
for e in events:
if e[0]=='open': notices[e[1]]=[e[2],0,2]
elif e[0]=='ack': notices.pop(e[1],None)
elif e[0]=='edit' and e[1] in notices: notices[e[1]][0]=e[2]
elif e[0]=='snooze' and e[1] in notices:
if notices[e[1]][2] is not None: notices[e[1]][2]+=e[2]
elif e[0]=='reset' and e[1] in notices: notices[e[1]][1:]=[0,now+2]
elif e[0]=='tick':
now=max(now,e[1])
for ident,t in notices.items():
if t[2] is None or t[2]>now: continue
t[1]+=1
out.append([ident,t[0],t[1]])
t[2]=now+2 if t[1]<3 else None
return [out,now,[[k]+v for k,v in notices.items()]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = ["[['open','a','alarm'*N],['tick',2],['tick',4],['tick',6],['tick',8]]", "[['tick',N+3],['open','a','fresh'],['open','a','replace'*N]]", "[['open','a','x'*N],['tick',2],['snooze','a',N]]", "[['open','a','old'],['tick',2],['edit','a','new'*N],['snooze','a',N],['tick',N+4]]", "[['open','a','a'*N],['open','b','b'],['ack','a'],['tick',N+4]]", "[['open','a','a'*N],['tick',3],['reset','a'],['tick',1]]", "[['open','a','a'*N],['tick',N+10]]", '[]']
expected = {1: [[[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]], [[], 4, [['a', 'replace', 0, 6]]], [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]], [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]], [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]], [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]], [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]], [[], 0, []]], 2: [[[['a', 'alarmalarm', 1], ['a', 'alarmalarm', 2], ['a', 'alarmalarm', 3]], 8, [['a', 'alarmalarm', 3, None]]], [[], 5, [['a', 'replacereplace', 0, 7]]], [[['a', 'xx', 1]], 2, [['a', 'xx', 1, 6]]], [[['a', 'old', 1], ['a', 'newnew', 2]], 6, [['a', 'newnew', 2, 8]]], [[['b', 'b', 1]], 6, [['b', 'b', 1, 8]]], [[['a', 'aa', 1]], 3, [['a', 'aa', 0, 5]]], [[['a', 'aa', 1]], 12, [['a', 'aa', 1, 14]]], [[], 0, []]], 3: [[[['a', 'alarmalarmalarm', 1], ['a', 'alarmalarmalarm', 2], ['a', 'alarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarm', 3, None]]], [[], 6, [['a', 'replacereplacereplace', 0, 8]]], [[['a', 'xxx', 1]], 2, [['a', 'xxx', 1, 7]]], [[['a', 'old', 1], ['a', 'newnewnew', 2]], 7, [['a', 'newnewnew', 2, 9]]], [[['b', 'b', 1]], 7, [['b', 'b', 1, 9]]], [[['a', 'aaa', 1]], 3, [['a', 'aaa', 0, 5]]], [[['a', 'aaa', 1]], 13, [['a', 'aaa', 1, 15]]], [[], 0, []]], 4: [[[['a', 'alarmalarmalarmalarm', 1], ['a', 'alarmalarmalarmalarm', 2], ['a', 'alarmalarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarmalarm', 3, None]]], [[], 7, [['a', 'replacereplacereplacereplace', 0, 9]]], [[['a', 'xxxx', 1]], 2, [['a', 'xxxx', 1, 8]]], [[['a', 'old', 1], ['a', 'newnewnewnew', 2]], 8, [['a', 'newnewnewnew', 2, 10]]], [[['b', 'b', 1]], 8, [['b', 'b', 1, 10]]], [[['a', 'aaaa', 1]], 3, [['a', 'aaaa', 0, 5]]], [[['a', 'aaaa', 1]], 14, [['a', 'aaaa', 1, 16]]], [[], 0, []]], 5: [[[['a', 'alarmalarmalarmalarmalarm', 1], ['a', 'alarmalarmalarmalarmalarm', 2], ['a', 'alarmalarmalarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarmalarmalarm', 3, None]]], [[], 8, [['a', 'replacereplacereplacereplacereplace', 0, 10]]], [[['a', 'xxxxx', 1]], 2, [['a', 'xxxxx', 1, 9]]], [[['a', 'old', 1], ['a', 'newnewnewnewnew', 2]], 9, [['a', 'newnewnewnewnew', 2, 11]]], [[['b', 'b', 1]], 9, [['b', 'b', 1, 11]]], [[['a', 'aaaaa', 1]], 3, [['a', 'aaaaa', 0, 5]]], [[['a', 'aaaaa', 1]], 15, [['a', 'aaaaa', 1, 17]]], [[], 0, []]]}[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 | [[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]] | [[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]] | Passed |
| trace-2 | [[], 4, [['a', 'replace', 0, 2]]] | [[], 4, [['a', 'replace', 0, 6]]] | Failed |
| trace-3 | [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]] | [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]] | Passed |
| trace-4 | [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]] | [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]] | Passed |
| trace-5 | [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]] | [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]] | Passed |
| trace-6 | [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]] | [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]] | Passed |
| trace-7 | [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]] | [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]] | Passed |
| trace-8 | [[], 0, []] | [[], 0, []] | Passed |
SHA-256 / 7102b8247cfca9f5865864c14859c46ce9879298d5ea9ac0dc58431b42aefde9
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
now=0; notices={}; out=[]
for e in events:
if e[0]=='open': notices.setdefault(e[1],[e[2],0,now+2])
elif e[0]=='ack': notices.pop(e[1],None)
elif e[0]=='edit' and e[1] in notices: notices[e[1]][0]=e[2]
elif e[0]=='snooze' and e[1] in notices:
if notices[e[1]][2] is not None: notices[e[1]][2]+=e[2]
elif e[0]=='reset' and e[1] in notices: notices[e[1]][1:]=[0,now+2]
elif e[0]=='tick':
now=max(now,e[1])
for ident,t in notices.items():
if t[2] is None or t[2]>now: continue
t[1]+=1
out.append([ident,t[0],t[1]])
t[2]=now+2 if t[1]<3 else None
return [out,now,[[k]+v for k,v in notices.items()]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = ["[['open','a','alarm'*N],['tick',2],['tick',4],['tick',6],['tick',8]]", "[['tick',N+3],['open','a','fresh'],['open','a','replace'*N]]", "[['open','a','x'*N],['tick',2],['snooze','a',N]]", "[['open','a','old'],['tick',2],['edit','a','new'*N],['snooze','a',N],['tick',N+4]]", "[['open','a','a'*N],['open','b','b'],['ack','a'],['tick',N+4]]", "[['open','a','a'*N],['tick',3],['reset','a'],['tick',1]]", "[['open','a','a'*N],['tick',N+10]]", '[]']
expected = {1: [[[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]], [[], 4, [['a', 'replace', 0, 6]]], [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]], [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]], [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]], [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]], [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]], [[], 0, []]], 2: [[[['a', 'alarmalarm', 1], ['a', 'alarmalarm', 2], ['a', 'alarmalarm', 3]], 8, [['a', 'alarmalarm', 3, None]]], [[], 5, [['a', 'replacereplace', 0, 7]]], [[['a', 'xx', 1]], 2, [['a', 'xx', 1, 6]]], [[['a', 'old', 1], ['a', 'newnew', 2]], 6, [['a', 'newnew', 2, 8]]], [[['b', 'b', 1]], 6, [['b', 'b', 1, 8]]], [[['a', 'aa', 1]], 3, [['a', 'aa', 0, 5]]], [[['a', 'aa', 1]], 12, [['a', 'aa', 1, 14]]], [[], 0, []]], 3: [[[['a', 'alarmalarmalarm', 1], ['a', 'alarmalarmalarm', 2], ['a', 'alarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarm', 3, None]]], [[], 6, [['a', 'replacereplacereplace', 0, 8]]], [[['a', 'xxx', 1]], 2, [['a', 'xxx', 1, 7]]], [[['a', 'old', 1], ['a', 'newnewnew', 2]], 7, [['a', 'newnewnew', 2, 9]]], [[['b', 'b', 1]], 7, [['b', 'b', 1, 9]]], [[['a', 'aaa', 1]], 3, [['a', 'aaa', 0, 5]]], [[['a', 'aaa', 1]], 13, [['a', 'aaa', 1, 15]]], [[], 0, []]], 4: [[[['a', 'alarmalarmalarmalarm', 1], ['a', 'alarmalarmalarmalarm', 2], ['a', 'alarmalarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarmalarm', 3, None]]], [[], 7, [['a', 'replacereplacereplacereplace', 0, 9]]], [[['a', 'xxxx', 1]], 2, [['a', 'xxxx', 1, 8]]], [[['a', 'old', 1], ['a', 'newnewnewnew', 2]], 8, [['a', 'newnewnewnew', 2, 10]]], [[['b', 'b', 1]], 8, [['b', 'b', 1, 10]]], [[['a', 'aaaa', 1]], 3, [['a', 'aaaa', 0, 5]]], [[['a', 'aaaa', 1]], 14, [['a', 'aaaa', 1, 16]]], [[], 0, []]], 5: [[[['a', 'alarmalarmalarmalarmalarm', 1], ['a', 'alarmalarmalarmalarmalarm', 2], ['a', 'alarmalarmalarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarmalarmalarm', 3, None]]], [[], 8, [['a', 'replacereplacereplacereplacereplace', 0, 10]]], [[['a', 'xxxxx', 1]], 2, [['a', 'xxxxx', 1, 9]]], [[['a', 'old', 1], ['a', 'newnewnewnewnew', 2]], 9, [['a', 'newnewnewnewnew', 2, 11]]], [[['b', 'b', 1]], 9, [['b', 'b', 1, 11]]], [[['a', 'aaaaa', 1]], 3, [['a', 'aaaaa', 0, 5]]], [[['a', 'aaaaa', 1]], 15, [['a', 'aaaaa', 1, 17]]], [[], 0, []]]}[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 | [[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]] | [[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]] | Passed |
| trace-2 | [[], 4, [['a', 'fresh', 0, 6]]] | [[], 4, [['a', 'replace', 0, 6]]] | Failed |
| trace-3 | [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]] | [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]] | Passed |
| trace-4 | [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]] | [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]] | Passed |
| trace-5 | [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]] | [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]] | Passed |
| trace-6 | [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]] | [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]] | Passed |
| trace-7 | [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]] | [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]] | Passed |
| trace-8 | [[], 0, []] | [[], 0, []] | Passed |
SHA-256 / 4aec45751633730bec1bafd0213d5c5a93d3359af8d573c33243976de7f7575c
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
now=0; notices={}; out=[]
for e in events:
if e[0]=='open': notices[e[1]]=[e[2],0,now+2]
elif e[0]=='ack': notices.pop(e[1],None)
elif e[0]=='edit' and e[1] in notices: notices[e[1]][0]=e[2]
elif e[0]=='snooze' and e[1] in notices:
if notices[e[1]][2] is not None: notices[e[1]][2]+=e[2]
elif e[0]=='reset' and e[1] in notices: notices[e[1]][1:]=[0,now+2]
elif e[0]=='tick':
now=max(now,e[1])
for ident,t in notices.items():
if t[2] is None or t[2]>now: continue
t[1]+=1
out.append([ident,t[0],t[1]])
t[2]=now+2 if t[1]<3 else None
return [out,now,[[k]+v for k,v in notices.items()]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = ["[['open','a','alarm'*N],['tick',2],['tick',4],['tick',6],['tick',8]]", "[['tick',N+3],['open','a','fresh'],['open','a','replace'*N]]", "[['open','a','x'*N],['tick',2],['snooze','a',N]]", "[['open','a','old'],['tick',2],['edit','a','new'*N],['snooze','a',N],['tick',N+4]]", "[['open','a','a'*N],['open','b','b'],['ack','a'],['tick',N+4]]", "[['open','a','a'*N],['tick',3],['reset','a'],['tick',1]]", "[['open','a','a'*N],['tick',N+10]]", '[]']
expected = {1: [[[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]], [[], 4, [['a', 'replace', 0, 6]]], [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]], [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]], [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]], [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]], [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]], [[], 0, []]], 2: [[[['a', 'alarmalarm', 1], ['a', 'alarmalarm', 2], ['a', 'alarmalarm', 3]], 8, [['a', 'alarmalarm', 3, None]]], [[], 5, [['a', 'replacereplace', 0, 7]]], [[['a', 'xx', 1]], 2, [['a', 'xx', 1, 6]]], [[['a', 'old', 1], ['a', 'newnew', 2]], 6, [['a', 'newnew', 2, 8]]], [[['b', 'b', 1]], 6, [['b', 'b', 1, 8]]], [[['a', 'aa', 1]], 3, [['a', 'aa', 0, 5]]], [[['a', 'aa', 1]], 12, [['a', 'aa', 1, 14]]], [[], 0, []]], 3: [[[['a', 'alarmalarmalarm', 1], ['a', 'alarmalarmalarm', 2], ['a', 'alarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarm', 3, None]]], [[], 6, [['a', 'replacereplacereplace', 0, 8]]], [[['a', 'xxx', 1]], 2, [['a', 'xxx', 1, 7]]], [[['a', 'old', 1], ['a', 'newnewnew', 2]], 7, [['a', 'newnewnew', 2, 9]]], [[['b', 'b', 1]], 7, [['b', 'b', 1, 9]]], [[['a', 'aaa', 1]], 3, [['a', 'aaa', 0, 5]]], [[['a', 'aaa', 1]], 13, [['a', 'aaa', 1, 15]]], [[], 0, []]], 4: [[[['a', 'alarmalarmalarmalarm', 1], ['a', 'alarmalarmalarmalarm', 2], ['a', 'alarmalarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarmalarm', 3, None]]], [[], 7, [['a', 'replacereplacereplacereplace', 0, 9]]], [[['a', 'xxxx', 1]], 2, [['a', 'xxxx', 1, 8]]], [[['a', 'old', 1], ['a', 'newnewnewnew', 2]], 8, [['a', 'newnewnewnew', 2, 10]]], [[['b', 'b', 1]], 8, [['b', 'b', 1, 10]]], [[['a', 'aaaa', 1]], 3, [['a', 'aaaa', 0, 5]]], [[['a', 'aaaa', 1]], 14, [['a', 'aaaa', 1, 16]]], [[], 0, []]], 5: [[[['a', 'alarmalarmalarmalarmalarm', 1], ['a', 'alarmalarmalarmalarmalarm', 2], ['a', 'alarmalarmalarmalarmalarm', 3]], 8, [['a', 'alarmalarmalarmalarmalarm', 3, None]]], [[], 8, [['a', 'replacereplacereplacereplacereplace', 0, 10]]], [[['a', 'xxxxx', 1]], 2, [['a', 'xxxxx', 1, 9]]], [[['a', 'old', 1], ['a', 'newnewnewnewnew', 2]], 9, [['a', 'newnewnewnewnew', 2, 11]]], [[['b', 'b', 1]], 9, [['b', 'b', 1, 11]]], [[['a', 'aaaaa', 1]], 3, [['a', 'aaaaa', 0, 5]]], [[['a', 'aaaaa', 1]], 15, [['a', 'aaaaa', 1, 17]]], [[], 0, []]]}[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 | [[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]] | [[['a', 'alarm', 1], ['a', 'alarm', 2], ['a', 'alarm', 3]], 8, [['a', 'alarm', 3, None]]] | Passed |
| trace-2 | [[], 4, [['a', 'replace', 0, 6]]] | [[], 4, [['a', 'replace', 0, 6]]] | Passed |
| trace-3 | [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]] | [[['a', 'x', 1]], 2, [['a', 'x', 1, 5]]] | Passed |
| trace-4 | [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]] | [[['a', 'old', 1], ['a', 'new', 2]], 5, [['a', 'new', 2, 7]]] | Passed |
| trace-5 | [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]] | [[['b', 'b', 1]], 5, [['b', 'b', 1, 7]]] | Passed |
| trace-6 | [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]] | [[['a', 'a', 1]], 3, [['a', 'a', 0, 5]]] | Passed |
| trace-7 | [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]] | [[['a', 'a', 1]], 11, [['a', 'a', 1, 13]]] | Passed |
| trace-8 | [[], 0, []] | [[], 0, []] | Passed |
SHA-256 / 622ef744892a2aef67383903e50c5ca960ac5ad33711a39c857fed09d98a3208
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:26.262824+00:00.
Case digest / 1ea9c3e950fe7db7216030cc06d60acdb3d4aa118152c45523d5358a930c6ca8