broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'paused', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'complete'}
    data = json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})) if payload is None else {**json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('work-complete','work-failed','late-progress') and arg.get('job',data['job']) != data['job']: event = 'unknown-event'
            if event == 'late-progress' and state != 'complete': data['done'] = min(data['total'],max(data['done'],arg.get('done',data['done'])))
            if event == 'work-complete' and 'done' in arg and arg['done'] < data['total']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'complete': data['done'] = data['total']
            if state == 'paused': data['paused_at'] = data['done']
            if state == 'running': data['paused_at'] = None
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('queued / worker-start', solve('queued', [('worker-start', N)], N), 'running')
check('running / request-pause', solve('running', [('request-pause', N)], N), 'pause-pending')
check('pause-pending / pause-accepted', solve('pause-pending', [('pause-accepted', N)], N), 'paused')
check('pause-pending / pause-rejected', solve('pause-pending', [('pause-rejected', N)], N), 'running')
check('paused / resume-click', solve('paused', [('resume-click', N)], N), 'resume-pending')
check('resume-pending / resume-accepted', solve('resume-pending', [('resume-accepted', N)], N), 'running')
check('running / work-complete', solve('running', [('work-complete', N)], N), 'complete')
check('running / work-failed', solve('running', [('work-failed', N)], N), 'failed')
check('complete / late-progress', solve('complete', [('late-progress', N)], N), 'complete')
check('paused / work-complete', solve('paused', [('work-complete', N)], N), 'complete')
check('older notification incarnation', solve('queued', [('worker-start', N - 1)], N), 'queued')
check('future notification incarnation', solve('queued', [('worker-start', N + 1)], N), 'queued')
check('unknown event is inert', solve('queued', [('unknown-event', N)], N), 'queued')
check('empty delivery batch', solve('queued', [], N), 'queued')
check('N stale deliveries before current delivery', solve('queued', [('worker-start', N - 1)] * N + [('worker-start', N)], N), 'running')
check('trace worker-start then request-pause', solve('queued', [('worker-start', N), ('request-pause', N)], N), 'pause-pending')
check('trace worker-start then work-complete', solve('queued', [('worker-start', N), ('work-complete', N)], N), 'complete')
check('trace worker-start then work-failed', solve('queued', [('worker-start', N), ('work-failed', N)], N), 'failed')
check('trace request-pause then pause-accepted', solve('running', [('request-pause', N), ('pause-accepted', N)], N), 'paused')
check('trace request-pause then pause-rejected', solve('running', [('request-pause', N), ('pause-rejected', N)], N), 'running')
check('trace pause-accepted then resume-click', solve('pause-pending', [('pause-accepted', N), ('resume-click', N)], N), 'resume-pending')
check('trace pause-accepted then work-complete', solve('pause-pending', [('pause-accepted', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then request-pause', solve('pause-pending', [('pause-rejected', N), ('request-pause', N)], N), 'pause-pending')
check('trace pause-rejected then work-complete', solve('pause-pending', [('pause-rejected', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then work-failed', solve('pause-pending', [('pause-rejected', N), ('work-failed', N)], N), 'failed')
check('trace resume-click then resume-accepted', solve('paused', [('resume-click', N), ('resume-accepted', N)], N), 'running')
check('trace resume-accepted then request-pause', solve('resume-pending', [('resume-accepted', N), ('request-pause', N)], N), 'pause-pending')
check('trace resume-accepted then work-complete', solve('resume-pending', [('resume-accepted', N), ('work-complete', N)], N), 'complete')
check('trace resume-accepted then work-failed', solve('resume-pending', [('resume-accepted', N), ('work-failed', N)], N), 'failed')
check('trace work-complete then late-progress', solve('running', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('trace late-progress then late-progress', solve('complete', [('late-progress', N), ('late-progress', N)], N), 'complete')
check('trace work-complete then late-progress', solve('paused', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('domain state regression 1: done', solve('running', [('work-complete', N, {'job': 1})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 2: done', solve('running', [('work-complete', N, {'done': 9})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 3: done', solve('running', [('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 4: paused_at', solve('pause-pending', [('pause-accepted', N, {})], N, {}, 'paused_at'), {'phase': 'paused', 'value': 3})
check('domain state regression 5: paused_at', solve('resume-pending', [('resume-accepted', N, {})], N, {'paused_at': 3}, 'paused_at'), {'phase': 'running', 'value': None})
check('domain state regression 6: done', solve('complete', [('late-progress', N, {'done': 2})], N, {'done': 10}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 7: done', solve('running', [('request-pause', N, {}), ('pause-accepted', N, {}), ('resume-click', N, {}), ('resume-accepted', N, {}), ('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'queued', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'complete'}
    data = json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})) if payload is None else {**json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('work-complete','work-failed','late-progress') and arg.get('job',data['job']) != data['job']: event = 'unknown-event'
            if event == 'late-progress' and state != 'complete': data['done'] = min(data['total'],max(data['done'],arg.get('done',data['done'])))
            if event == 'work-complete' and 'done' in arg and arg['done'] < data['total']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'complete': data['done'] = data['total']
            if state == 'paused': data['paused_at'] = data['done']
            if state == 'running': data['paused_at'] = None
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('queued / worker-start', solve('queued', [('worker-start', N)], N), 'running')
check('running / request-pause', solve('running', [('request-pause', N)], N), 'pause-pending')
check('pause-pending / pause-accepted', solve('pause-pending', [('pause-accepted', N)], N), 'paused')
check('pause-pending / pause-rejected', solve('pause-pending', [('pause-rejected', N)], N), 'running')
check('paused / resume-click', solve('paused', [('resume-click', N)], N), 'resume-pending')
check('resume-pending / resume-accepted', solve('resume-pending', [('resume-accepted', N)], N), 'running')
check('running / work-complete', solve('running', [('work-complete', N)], N), 'complete')
check('running / work-failed', solve('running', [('work-failed', N)], N), 'failed')
check('complete / late-progress', solve('complete', [('late-progress', N)], N), 'complete')
check('paused / work-complete', solve('paused', [('work-complete', N)], N), 'complete')
check('older notification incarnation', solve('queued', [('worker-start', N - 1)], N), 'queued')
check('future notification incarnation', solve('queued', [('worker-start', N + 1)], N), 'queued')
check('unknown event is inert', solve('queued', [('unknown-event', N)], N), 'queued')
check('empty delivery batch', solve('queued', [], N), 'queued')
check('N stale deliveries before current delivery', solve('queued', [('worker-start', N - 1)] * N + [('worker-start', N)], N), 'running')
check('trace worker-start then request-pause', solve('queued', [('worker-start', N), ('request-pause', N)], N), 'pause-pending')
check('trace worker-start then work-complete', solve('queued', [('worker-start', N), ('work-complete', N)], N), 'complete')
check('trace worker-start then work-failed', solve('queued', [('worker-start', N), ('work-failed', N)], N), 'failed')
check('trace request-pause then pause-accepted', solve('running', [('request-pause', N), ('pause-accepted', N)], N), 'paused')
check('trace request-pause then pause-rejected', solve('running', [('request-pause', N), ('pause-rejected', N)], N), 'running')
check('trace pause-accepted then resume-click', solve('pause-pending', [('pause-accepted', N), ('resume-click', N)], N), 'resume-pending')
check('trace pause-accepted then work-complete', solve('pause-pending', [('pause-accepted', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then request-pause', solve('pause-pending', [('pause-rejected', N), ('request-pause', N)], N), 'pause-pending')
check('trace pause-rejected then work-complete', solve('pause-pending', [('pause-rejected', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then work-failed', solve('pause-pending', [('pause-rejected', N), ('work-failed', N)], N), 'failed')
check('trace resume-click then resume-accepted', solve('paused', [('resume-click', N), ('resume-accepted', N)], N), 'running')
check('trace resume-accepted then request-pause', solve('resume-pending', [('resume-accepted', N), ('request-pause', N)], N), 'pause-pending')
check('trace resume-accepted then work-complete', solve('resume-pending', [('resume-accepted', N), ('work-complete', N)], N), 'complete')
check('trace resume-accepted then work-failed', solve('resume-pending', [('resume-accepted', N), ('work-failed', N)], N), 'failed')
check('trace work-complete then late-progress', solve('running', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('trace late-progress then late-progress', solve('complete', [('late-progress', N), ('late-progress', N)], N), 'complete')
check('trace work-complete then late-progress', solve('paused', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('domain state regression 1: done', solve('running', [('work-complete', N, {'job': 1})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 2: done', solve('running', [('work-complete', N, {'done': 9})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 3: done', solve('running', [('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 4: paused_at', solve('pause-pending', [('pause-accepted', N, {})], N, {}, 'paused_at'), {'phase': 'paused', 'value': 3})
check('domain state regression 5: paused_at', solve('resume-pending', [('resume-accepted', N, {})], N, {'paused_at': 3}, 'paused_at'), {'phase': 'running', 'value': None})
check('domain state regression 6: done', solve('complete', [('late-progress', N, {'done': 2})], N, {'done': 10}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 7: done', solve('running', [('request-pause', N, {}), ('pause-accepted', N, {}), ('resume-click', N, {}), ('resume-accepted', N, {}), ('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
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)

prompt:
The work-complete event leaves a notification in paused instead of complete.

Long-running notification progress is a bounded visual-notification workflow with mutable policy state {'done': 3, 'total': 10, 'job': 2, 'paused_at': None}. Its default transition relation is {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'complete'}; domain inputs can suppress or redirect transitions and update policy fields, as specified in solve. Different-generation events are inert. Batches apply in order. Optional observe returns the selected policy field alongside the phase.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'complete', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'complete'}
    data = json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})) if payload is None else {**json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('work-complete','work-failed','late-progress') and arg.get('job',data['job']) != data['job']: event = 'unknown-event'
            if event == 'late-progress' and state != 'complete': data['done'] = min(data['total'],max(data['done'],arg.get('done',data['done'])))
            if event == 'work-complete' and 'done' in arg and arg['done'] < data['total']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'complete': data['done'] = data['total']
            if state == 'paused': data['paused_at'] = data['done']
            if state == 'running': data['paused_at'] = None
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('queued / worker-start', solve('queued', [('worker-start', N)], N), 'running')
check('running / request-pause', solve('running', [('request-pause', N)], N), 'pause-pending')
check('pause-pending / pause-accepted', solve('pause-pending', [('pause-accepted', N)], N), 'paused')
check('pause-pending / pause-rejected', solve('pause-pending', [('pause-rejected', N)], N), 'running')
check('paused / resume-click', solve('paused', [('resume-click', N)], N), 'resume-pending')
check('resume-pending / resume-accepted', solve('resume-pending', [('resume-accepted', N)], N), 'running')
check('running / work-complete', solve('running', [('work-complete', N)], N), 'complete')
check('running / work-failed', solve('running', [('work-failed', N)], N), 'failed')
check('complete / late-progress', solve('complete', [('late-progress', N)], N), 'complete')
check('paused / work-complete', solve('paused', [('work-complete', N)], N), 'complete')
check('older notification incarnation', solve('queued', [('worker-start', N - 1)], N), 'queued')
check('future notification incarnation', solve('queued', [('worker-start', N + 1)], N), 'queued')
check('unknown event is inert', solve('queued', [('unknown-event', N)], N), 'queued')
check('empty delivery batch', solve('queued', [], N), 'queued')
check('N stale deliveries before current delivery', solve('queued', [('worker-start', N - 1)] * N + [('worker-start', N)], N), 'running')
check('trace worker-start then request-pause', solve('queued', [('worker-start', N), ('request-pause', N)], N), 'pause-pending')
check('trace worker-start then work-complete', solve('queued', [('worker-start', N), ('work-complete', N)], N), 'complete')
check('trace worker-start then work-failed', solve('queued', [('worker-start', N), ('work-failed', N)], N), 'failed')
check('trace request-pause then pause-accepted', solve('running', [('request-pause', N), ('pause-accepted', N)], N), 'paused')
check('trace request-pause then pause-rejected', solve('running', [('request-pause', N), ('pause-rejected', N)], N), 'running')
check('trace pause-accepted then resume-click', solve('pause-pending', [('pause-accepted', N), ('resume-click', N)], N), 'resume-pending')
check('trace pause-accepted then work-complete', solve('pause-pending', [('pause-accepted', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then request-pause', solve('pause-pending', [('pause-rejected', N), ('request-pause', N)], N), 'pause-pending')
check('trace pause-rejected then work-complete', solve('pause-pending', [('pause-rejected', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then work-failed', solve('pause-pending', [('pause-rejected', N), ('work-failed', N)], N), 'failed')
check('trace resume-click then resume-accepted', solve('paused', [('resume-click', N), ('resume-accepted', N)], N), 'running')
check('trace resume-accepted then request-pause', solve('resume-pending', [('resume-accepted', N), ('request-pause', N)], N), 'pause-pending')
check('trace resume-accepted then work-complete', solve('resume-pending', [('resume-accepted', N), ('work-complete', N)], N), 'complete')
check('trace resume-accepted then work-failed', solve('resume-pending', [('resume-accepted', N), ('work-failed', N)], N), 'failed')
check('trace work-complete then late-progress', solve('running', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('trace late-progress then late-progress', solve('complete', [('late-progress', N), ('late-progress', N)], N), 'complete')
check('trace work-complete then late-progress', solve('paused', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('domain state regression 1: done', solve('running', [('work-complete', N, {'job': 1})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 2: done', solve('running', [('work-complete', N, {'done': 9})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 3: done', solve('running', [('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 4: paused_at', solve('pause-pending', [('pause-accepted', N, {})], N, {}, 'paused_at'), {'phase': 'paused', 'value': 3})
check('domain state regression 5: paused_at', solve('resume-pending', [('resume-accepted', N, {})], N, {'paused_at': 3}, 'paused_at'), {'phase': 'running', 'value': None})
check('domain state regression 6: done', solve('complete', [('late-progress', N, {'done': 2})], N, {'done': 10}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 7: done', solve('running', [('request-pause', N, {}), ('pause-accepted', N, {}), ('resume-click', N, {}), ('resume-accepted', N, {}), ('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
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)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'paused', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'complete'}
    data = json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})) if payload is None else {**json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('work-complete','work-failed','late-progress') and arg.get('job',data['job']) != data['job']: event = 'unknown-event'
            if event == 'late-progress' and state != 'complete': data['done'] = min(data['total'],max(data['done'],arg.get('done',data['done'])))
            if event == 'work-complete' and 'done' in arg and arg['done'] < data['total']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'complete': data['done'] = data['total']
            if state == 'paused': data['paused_at'] = data['done']
            if state == 'running': data['paused_at'] = None
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('queued / worker-start', solve('queued', [('worker-start', N)], N), 'running')
check('running / request-pause', solve('running', [('request-pause', N)], N), 'pause-pending')
check('pause-pending / pause-accepted', solve('pause-pending', [('pause-accepted', N)], N), 'paused')
check('pause-pending / pause-rejected', solve('pause-pending', [('pause-rejected', N)], N), 'running')
check('paused / resume-click', solve('paused', [('resume-click', N)], N), 'resume-pending')
check('resume-pending / resume-accepted', solve('resume-pending', [('resume-accepted', N)], N), 'running')
check('running / work-complete', solve('running', [('work-complete', N)], N), 'complete')
check('running / work-failed', solve('running', [('work-failed', N)], N), 'failed')
check('complete / late-progress', solve('complete', [('late-progress', N)], N), 'complete')
check('paused / work-complete', solve('paused', [('work-complete', N)], N), 'complete')
check('older notification incarnation', solve('queued', [('worker-start', N - 1)], N), 'queued')
check('future notification incarnation', solve('queued', [('worker-start', N + 1)], N), 'queued')
check('unknown event is inert', solve('queued', [('unknown-event', N)], N), 'queued')
check('empty delivery batch', solve('queued', [], N), 'queued')
check('N stale deliveries before current delivery', solve('queued', [('worker-start', N - 1)] * N + [('worker-start', N)], N), 'running')
check('trace worker-start then request-pause', solve('queued', [('worker-start', N), ('request-pause', N)], N), 'pause-pending')
check('trace worker-start then work-complete', solve('queued', [('worker-start', N), ('work-complete', N)], N), 'complete')
check('trace worker-start then work-failed', solve('queued', [('worker-start', N), ('work-failed', N)], N), 'failed')
check('trace request-pause then pause-accepted', solve('running', [('request-pause', N), ('pause-accepted', N)], N), 'paused')
check('trace request-pause then pause-rejected', solve('running', [('request-pause', N), ('pause-rejected', N)], N), 'running')
check('trace pause-accepted then resume-click', solve('pause-pending', [('pause-accepted', N), ('resume-click', N)], N), 'resume-pending')
check('trace pause-accepted then work-complete', solve('pause-pending', [('pause-accepted', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then request-pause', solve('pause-pending', [('pause-rejected', N), ('request-pause', N)], N), 'pause-pending')
check('trace pause-rejected then work-complete', solve('pause-pending', [('pause-rejected', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then work-failed', solve('pause-pending', [('pause-rejected', N), ('work-failed', N)], N), 'failed')
check('trace resume-click then resume-accepted', solve('paused', [('resume-click', N), ('resume-accepted', N)], N), 'running')
check('trace resume-accepted then request-pause', solve('resume-pending', [('resume-accepted', N), ('request-pause', N)], N), 'pause-pending')
check('trace resume-accepted then work-complete', solve('resume-pending', [('resume-accepted', N), ('work-complete', N)], N), 'complete')
check('trace resume-accepted then work-failed', solve('resume-pending', [('resume-accepted', N), ('work-failed', N)], N), 'failed')
check('trace work-complete then late-progress', solve('running', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('trace late-progress then late-progress', solve('complete', [('late-progress', N), ('late-progress', N)], N), 'complete')
check('trace work-complete then late-progress', solve('paused', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('domain state regression 1: done', solve('running', [('work-complete', N, {'job': 1})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 2: done', solve('running', [('work-complete', N, {'done': 9})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 3: done', solve('running', [('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 4: paused_at', solve('pause-pending', [('pause-accepted', N, {})], N, {}, 'paused_at'), {'phase': 'paused', 'value': 3})
check('domain state regression 5: paused_at', solve('resume-pending', [('resume-accepted', N, {})], N, {'paused_at': 3}, 'paused_at'), {'phase': 'running', 'value': None})
check('domain state regression 6: done', solve('complete', [('late-progress', N, {'done': 2})], N, {'done': 10}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 7: done', solve('running', [('request-pause', N, {}), ('pause-accepted', N, {}), ('resume-click', N, {}), ('resume-accepted', N, {}), ('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
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)

prompt:
The work-failed event leaves a notification in complete instead of failed.

Long-running notification progress is a bounded visual-notification workflow with mutable policy state {'done': 3, 'total': 10, 'job': 2, 'paused_at': None}. Its default transition relation is {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'complete'}; domain inputs can suppress or redirect transitions and update policy fields, as specified in solve. Different-generation events are inert. Batches apply in order. Optional observe returns the selected policy field alongside the phase.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'running', ('paused', 'work-complete'): 'complete'}
    data = json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})) if payload is None else {**json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('work-complete','work-failed','late-progress') and arg.get('job',data['job']) != data['job']: event = 'unknown-event'
            if event == 'late-progress' and state != 'complete': data['done'] = min(data['total'],max(data['done'],arg.get('done',data['done'])))
            if event == 'work-complete' and 'done' in arg and arg['done'] < data['total']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'complete': data['done'] = data['total']
            if state == 'paused': data['paused_at'] = data['done']
            if state == 'running': data['paused_at'] = None
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('queued / worker-start', solve('queued', [('worker-start', N)], N), 'running')
check('running / request-pause', solve('running', [('request-pause', N)], N), 'pause-pending')
check('pause-pending / pause-accepted', solve('pause-pending', [('pause-accepted', N)], N), 'paused')
check('pause-pending / pause-rejected', solve('pause-pending', [('pause-rejected', N)], N), 'running')
check('paused / resume-click', solve('paused', [('resume-click', N)], N), 'resume-pending')
check('resume-pending / resume-accepted', solve('resume-pending', [('resume-accepted', N)], N), 'running')
check('running / work-complete', solve('running', [('work-complete', N)], N), 'complete')
check('running / work-failed', solve('running', [('work-failed', N)], N), 'failed')
check('complete / late-progress', solve('complete', [('late-progress', N)], N), 'complete')
check('paused / work-complete', solve('paused', [('work-complete', N)], N), 'complete')
check('older notification incarnation', solve('queued', [('worker-start', N - 1)], N), 'queued')
check('future notification incarnation', solve('queued', [('worker-start', N + 1)], N), 'queued')
check('unknown event is inert', solve('queued', [('unknown-event', N)], N), 'queued')
check('empty delivery batch', solve('queued', [], N), 'queued')
check('N stale deliveries before current delivery', solve('queued', [('worker-start', N - 1)] * N + [('worker-start', N)], N), 'running')
check('trace worker-start then request-pause', solve('queued', [('worker-start', N), ('request-pause', N)], N), 'pause-pending')
check('trace worker-start then work-complete', solve('queued', [('worker-start', N), ('work-complete', N)], N), 'complete')
check('trace worker-start then work-failed', solve('queued', [('worker-start', N), ('work-failed', N)], N), 'failed')
check('trace request-pause then pause-accepted', solve('running', [('request-pause', N), ('pause-accepted', N)], N), 'paused')
check('trace request-pause then pause-rejected', solve('running', [('request-pause', N), ('pause-rejected', N)], N), 'running')
check('trace pause-accepted then resume-click', solve('pause-pending', [('pause-accepted', N), ('resume-click', N)], N), 'resume-pending')
check('trace pause-accepted then work-complete', solve('pause-pending', [('pause-accepted', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then request-pause', solve('pause-pending', [('pause-rejected', N), ('request-pause', N)], N), 'pause-pending')
check('trace pause-rejected then work-complete', solve('pause-pending', [('pause-rejected', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then work-failed', solve('pause-pending', [('pause-rejected', N), ('work-failed', N)], N), 'failed')
check('trace resume-click then resume-accepted', solve('paused', [('resume-click', N), ('resume-accepted', N)], N), 'running')
check('trace resume-accepted then request-pause', solve('resume-pending', [('resume-accepted', N), ('request-pause', N)], N), 'pause-pending')
check('trace resume-accepted then work-complete', solve('resume-pending', [('resume-accepted', N), ('work-complete', N)], N), 'complete')
check('trace resume-accepted then work-failed', solve('resume-pending', [('resume-accepted', N), ('work-failed', N)], N), 'failed')
check('trace work-complete then late-progress', solve('running', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('trace late-progress then late-progress', solve('complete', [('late-progress', N), ('late-progress', N)], N), 'complete')
check('trace work-complete then late-progress', solve('paused', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('domain state regression 1: done', solve('running', [('work-complete', N, {'job': 1})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 2: done', solve('running', [('work-complete', N, {'done': 9})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 3: done', solve('running', [('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 4: paused_at', solve('pause-pending', [('pause-accepted', N, {})], N, {}, 'paused_at'), {'phase': 'paused', 'value': 3})
check('domain state regression 5: paused_at', solve('resume-pending', [('resume-accepted', N, {})], N, {'paused_at': 3}, 'paused_at'), {'phase': 'running', 'value': None})
check('domain state regression 6: done', solve('complete', [('late-progress', N, {'done': 2})], N, {'done': 10}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 7: done', solve('running', [('request-pause', N, {}), ('pause-accepted', N, {}), ('resume-click', N, {}), ('resume-accepted', N, {}), ('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'queued', ('paused', 'work-complete'): 'complete'}
    data = json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})) if payload is None else {**json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('work-complete','work-failed','late-progress') and arg.get('job',data['job']) != data['job']: event = 'unknown-event'
            if event == 'late-progress' and state != 'complete': data['done'] = min(data['total'],max(data['done'],arg.get('done',data['done'])))
            if event == 'work-complete' and 'done' in arg and arg['done'] < data['total']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'complete': data['done'] = data['total']
            if state == 'paused': data['paused_at'] = data['done']
            if state == 'running': data['paused_at'] = None
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('queued / worker-start', solve('queued', [('worker-start', N)], N), 'running')
check('running / request-pause', solve('running', [('request-pause', N)], N), 'pause-pending')
check('pause-pending / pause-accepted', solve('pause-pending', [('pause-accepted', N)], N), 'paused')
check('pause-pending / pause-rejected', solve('pause-pending', [('pause-rejected', N)], N), 'running')
check('paused / resume-click', solve('paused', [('resume-click', N)], N), 'resume-pending')
check('resume-pending / resume-accepted', solve('resume-pending', [('resume-accepted', N)], N), 'running')
check('running / work-complete', solve('running', [('work-complete', N)], N), 'complete')
check('running / work-failed', solve('running', [('work-failed', N)], N), 'failed')
check('complete / late-progress', solve('complete', [('late-progress', N)], N), 'complete')
check('paused / work-complete', solve('paused', [('work-complete', N)], N), 'complete')
check('older notification incarnation', solve('queued', [('worker-start', N - 1)], N), 'queued')
check('future notification incarnation', solve('queued', [('worker-start', N + 1)], N), 'queued')
check('unknown event is inert', solve('queued', [('unknown-event', N)], N), 'queued')
check('empty delivery batch', solve('queued', [], N), 'queued')
check('N stale deliveries before current delivery', solve('queued', [('worker-start', N - 1)] * N + [('worker-start', N)], N), 'running')
check('trace worker-start then request-pause', solve('queued', [('worker-start', N), ('request-pause', N)], N), 'pause-pending')
check('trace worker-start then work-complete', solve('queued', [('worker-start', N), ('work-complete', N)], N), 'complete')
check('trace worker-start then work-failed', solve('queued', [('worker-start', N), ('work-failed', N)], N), 'failed')
check('trace request-pause then pause-accepted', solve('running', [('request-pause', N), ('pause-accepted', N)], N), 'paused')
check('trace request-pause then pause-rejected', solve('running', [('request-pause', N), ('pause-rejected', N)], N), 'running')
check('trace pause-accepted then resume-click', solve('pause-pending', [('pause-accepted', N), ('resume-click', N)], N), 'resume-pending')
check('trace pause-accepted then work-complete', solve('pause-pending', [('pause-accepted', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then request-pause', solve('pause-pending', [('pause-rejected', N), ('request-pause', N)], N), 'pause-pending')
check('trace pause-rejected then work-complete', solve('pause-pending', [('pause-rejected', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then work-failed', solve('pause-pending', [('pause-rejected', N), ('work-failed', N)], N), 'failed')
check('trace resume-click then resume-accepted', solve('paused', [('resume-click', N), ('resume-accepted', N)], N), 'running')
check('trace resume-accepted then request-pause', solve('resume-pending', [('resume-accepted', N), ('request-pause', N)], N), 'pause-pending')
check('trace resume-accepted then work-complete', solve('resume-pending', [('resume-accepted', N), ('work-complete', N)], N), 'complete')
check('trace resume-accepted then work-failed', solve('resume-pending', [('resume-accepted', N), ('work-failed', N)], N), 'failed')
check('trace work-complete then late-progress', solve('running', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('trace late-progress then late-progress', solve('complete', [('late-progress', N), ('late-progress', N)], N), 'complete')
check('trace work-complete then late-progress', solve('paused', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('domain state regression 1: done', solve('running', [('work-complete', N, {'job': 1})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 2: done', solve('running', [('work-complete', N, {'done': 9})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 3: done', solve('running', [('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 4: paused_at', solve('pause-pending', [('pause-accepted', N, {})], N, {}, 'paused_at'), {'phase': 'paused', 'value': 3})
check('domain state regression 5: paused_at', solve('resume-pending', [('resume-accepted', N, {})], N, {'paused_at': 3}, 'paused_at'), {'phase': 'running', 'value': None})
check('domain state regression 6: done', solve('complete', [('late-progress', N, {'done': 2})], N, {'done': 10}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 7: done', solve('running', [('request-pause', N, {}), ('pause-accepted', N, {}), ('resume-click', N, {}), ('resume-accepted', N, {}), ('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
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)

prompt:
The late-progress event leaves a notification in running instead of complete.

Long-running notification progress is a bounded visual-notification workflow with mutable policy state {'done': 3, 'total': 10, 'job': 2, 'paused_at': None}. Its default transition relation is {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'complete'}; domain inputs can suppress or redirect transitions and update policy fields, as specified in solve. Different-generation events are inert. Batches apply in order. Optional observe returns the selected policy field alongside the phase.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'paused'}
    data = json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})) if payload is None else {**json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('work-complete','work-failed','late-progress') and arg.get('job',data['job']) != data['job']: event = 'unknown-event'
            if event == 'late-progress' and state != 'complete': data['done'] = min(data['total'],max(data['done'],arg.get('done',data['done'])))
            if event == 'work-complete' and 'done' in arg and arg['done'] < data['total']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'complete': data['done'] = data['total']
            if state == 'paused': data['paused_at'] = data['done']
            if state == 'running': data['paused_at'] = None
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('queued / worker-start', solve('queued', [('worker-start', N)], N), 'running')
check('running / request-pause', solve('running', [('request-pause', N)], N), 'pause-pending')
check('pause-pending / pause-accepted', solve('pause-pending', [('pause-accepted', N)], N), 'paused')
check('pause-pending / pause-rejected', solve('pause-pending', [('pause-rejected', N)], N), 'running')
check('paused / resume-click', solve('paused', [('resume-click', N)], N), 'resume-pending')
check('resume-pending / resume-accepted', solve('resume-pending', [('resume-accepted', N)], N), 'running')
check('running / work-complete', solve('running', [('work-complete', N)], N), 'complete')
check('running / work-failed', solve('running', [('work-failed', N)], N), 'failed')
check('complete / late-progress', solve('complete', [('late-progress', N)], N), 'complete')
check('paused / work-complete', solve('paused', [('work-complete', N)], N), 'complete')
check('older notification incarnation', solve('queued', [('worker-start', N - 1)], N), 'queued')
check('future notification incarnation', solve('queued', [('worker-start', N + 1)], N), 'queued')
check('unknown event is inert', solve('queued', [('unknown-event', N)], N), 'queued')
check('empty delivery batch', solve('queued', [], N), 'queued')
check('N stale deliveries before current delivery', solve('queued', [('worker-start', N - 1)] * N + [('worker-start', N)], N), 'running')
check('trace worker-start then request-pause', solve('queued', [('worker-start', N), ('request-pause', N)], N), 'pause-pending')
check('trace worker-start then work-complete', solve('queued', [('worker-start', N), ('work-complete', N)], N), 'complete')
check('trace worker-start then work-failed', solve('queued', [('worker-start', N), ('work-failed', N)], N), 'failed')
check('trace request-pause then pause-accepted', solve('running', [('request-pause', N), ('pause-accepted', N)], N), 'paused')
check('trace request-pause then pause-rejected', solve('running', [('request-pause', N), ('pause-rejected', N)], N), 'running')
check('trace pause-accepted then resume-click', solve('pause-pending', [('pause-accepted', N), ('resume-click', N)], N), 'resume-pending')
check('trace pause-accepted then work-complete', solve('pause-pending', [('pause-accepted', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then request-pause', solve('pause-pending', [('pause-rejected', N), ('request-pause', N)], N), 'pause-pending')
check('trace pause-rejected then work-complete', solve('pause-pending', [('pause-rejected', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then work-failed', solve('pause-pending', [('pause-rejected', N), ('work-failed', N)], N), 'failed')
check('trace resume-click then resume-accepted', solve('paused', [('resume-click', N), ('resume-accepted', N)], N), 'running')
check('trace resume-accepted then request-pause', solve('resume-pending', [('resume-accepted', N), ('request-pause', N)], N), 'pause-pending')
check('trace resume-accepted then work-complete', solve('resume-pending', [('resume-accepted', N), ('work-complete', N)], N), 'complete')
check('trace resume-accepted then work-failed', solve('resume-pending', [('resume-accepted', N), ('work-failed', N)], N), 'failed')
check('trace work-complete then late-progress', solve('running', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('trace late-progress then late-progress', solve('complete', [('late-progress', N), ('late-progress', N)], N), 'complete')
check('trace work-complete then late-progress', solve('paused', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('domain state regression 1: done', solve('running', [('work-complete', N, {'job': 1})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 2: done', solve('running', [('work-complete', N, {'done': 9})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 3: done', solve('running', [('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 4: paused_at', solve('pause-pending', [('pause-accepted', N, {})], N, {}, 'paused_at'), {'phase': 'paused', 'value': 3})
check('domain state regression 5: paused_at', solve('resume-pending', [('resume-accepted', N, {})], N, {'paused_at': 3}, 'paused_at'), {'phase': 'running', 'value': None})
check('domain state regression 6: done', solve('complete', [('late-progress', N, {'done': 2})], N, {'done': 10}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 7: done', solve('running', [('request-pause', N, {}), ('pause-accepted', N, {}), ('resume-click', N, {}), ('resume-accepted', N, {}), ('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'running'}
    data = json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})) if payload is None else {**json.loads(json.dumps({'done': 3, 'total': 10, 'job': 2, 'paused_at': None})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('work-complete','work-failed','late-progress') and arg.get('job',data['job']) != data['job']: event = 'unknown-event'
            if event == 'late-progress' and state != 'complete': data['done'] = min(data['total'],max(data['done'],arg.get('done',data['done'])))
            if event == 'work-complete' and 'done' in arg and arg['done'] < data['total']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'complete': data['done'] = data['total']
            if state == 'paused': data['paused_at'] = data['done']
            if state == 'running': data['paused_at'] = None
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('queued / worker-start', solve('queued', [('worker-start', N)], N), 'running')
check('running / request-pause', solve('running', [('request-pause', N)], N), 'pause-pending')
check('pause-pending / pause-accepted', solve('pause-pending', [('pause-accepted', N)], N), 'paused')
check('pause-pending / pause-rejected', solve('pause-pending', [('pause-rejected', N)], N), 'running')
check('paused / resume-click', solve('paused', [('resume-click', N)], N), 'resume-pending')
check('resume-pending / resume-accepted', solve('resume-pending', [('resume-accepted', N)], N), 'running')
check('running / work-complete', solve('running', [('work-complete', N)], N), 'complete')
check('running / work-failed', solve('running', [('work-failed', N)], N), 'failed')
check('complete / late-progress', solve('complete', [('late-progress', N)], N), 'complete')
check('paused / work-complete', solve('paused', [('work-complete', N)], N), 'complete')
check('older notification incarnation', solve('queued', [('worker-start', N - 1)], N), 'queued')
check('future notification incarnation', solve('queued', [('worker-start', N + 1)], N), 'queued')
check('unknown event is inert', solve('queued', [('unknown-event', N)], N), 'queued')
check('empty delivery batch', solve('queued', [], N), 'queued')
check('N stale deliveries before current delivery', solve('queued', [('worker-start', N - 1)] * N + [('worker-start', N)], N), 'running')
check('trace worker-start then request-pause', solve('queued', [('worker-start', N), ('request-pause', N)], N), 'pause-pending')
check('trace worker-start then work-complete', solve('queued', [('worker-start', N), ('work-complete', N)], N), 'complete')
check('trace worker-start then work-failed', solve('queued', [('worker-start', N), ('work-failed', N)], N), 'failed')
check('trace request-pause then pause-accepted', solve('running', [('request-pause', N), ('pause-accepted', N)], N), 'paused')
check('trace request-pause then pause-rejected', solve('running', [('request-pause', N), ('pause-rejected', N)], N), 'running')
check('trace pause-accepted then resume-click', solve('pause-pending', [('pause-accepted', N), ('resume-click', N)], N), 'resume-pending')
check('trace pause-accepted then work-complete', solve('pause-pending', [('pause-accepted', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then request-pause', solve('pause-pending', [('pause-rejected', N), ('request-pause', N)], N), 'pause-pending')
check('trace pause-rejected then work-complete', solve('pause-pending', [('pause-rejected', N), ('work-complete', N)], N), 'complete')
check('trace pause-rejected then work-failed', solve('pause-pending', [('pause-rejected', N), ('work-failed', N)], N), 'failed')
check('trace resume-click then resume-accepted', solve('paused', [('resume-click', N), ('resume-accepted', N)], N), 'running')
check('trace resume-accepted then request-pause', solve('resume-pending', [('resume-accepted', N), ('request-pause', N)], N), 'pause-pending')
check('trace resume-accepted then work-complete', solve('resume-pending', [('resume-accepted', N), ('work-complete', N)], N), 'complete')
check('trace resume-accepted then work-failed', solve('resume-pending', [('resume-accepted', N), ('work-failed', N)], N), 'failed')
check('trace work-complete then late-progress', solve('running', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('trace late-progress then late-progress', solve('complete', [('late-progress', N), ('late-progress', N)], N), 'complete')
check('trace work-complete then late-progress', solve('paused', [('work-complete', N), ('late-progress', N)], N), 'complete')
check('domain state regression 1: done', solve('running', [('work-complete', N, {'job': 1})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 2: done', solve('running', [('work-complete', N, {'done': 9})], N, {}, 'done'), {'phase': 'running', 'value': 3})
check('domain state regression 3: done', solve('running', [('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 4: paused_at', solve('pause-pending', [('pause-accepted', N, {})], N, {}, 'paused_at'), {'phase': 'paused', 'value': 3})
check('domain state regression 5: paused_at', solve('resume-pending', [('resume-accepted', N, {})], N, {'paused_at': 3}, 'paused_at'), {'phase': 'running', 'value': None})
check('domain state regression 6: done', solve('complete', [('late-progress', N, {'done': 2})], N, {'done': 10}, 'done'), {'phase': 'complete', 'value': 10})
check('domain state regression 7: done', solve('running', [('request-pause', N, {}), ('pause-accepted', N, {}), ('resume-click', N, {}), ('resume-accepted', N, {}), ('work-complete', N, {'done': 10})], N, {}, 'done'), {'phase': 'complete', 'value': 10})
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)

prompt:
The work-complete event leaves a notification in paused instead of complete.

Long-running notification progress is a bounded visual-notification workflow with mutable policy state {'done': 3, 'total': 10, 'job': 2, 'paused_at': None}. Its default transition relation is {('queued', 'worker-start'): 'running', ('running', 'request-pause'): 'pause-pending', ('pause-pending', 'pause-accepted'): 'paused', ('pause-pending', 'pause-rejected'): 'running', ('paused', 'resume-click'): 'resume-pending', ('resume-pending', 'resume-accepted'): 'running', ('running', 'work-complete'): 'complete', ('running', 'work-failed'): 'failed', ('complete', 'late-progress'): 'complete', ('paused', 'work-complete'): 'complete'}; domain inputs can suppress or redirect transitions and update policy fields, as specified in solve. Different-generation events are inert. Batches apply in order. Optional observe returns the selected policy field alongside the phase.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('banner', 'retain-in-inbox'): 'inbox-only', ('saving', 'save-success'): 'both', ('saving', 'save-failure'): 'save-error', ('both', 'banner-exposure-end'): 'inbox-only', ('save-error', 'retry-retention'): 'saving', ('saving', 'banner-exposure-end'): 'saving-without-banner', ('saving-without-banner', 'save-success'): 'inbox-only', ('saving-without-banner', 'save-failure'): 'recovery-banner', ('inbox-only', 'show-banner-again'): 'repromoting', ('repromoting', 'banner-mounted'): 'both'}
    data = json.loads(json.dumps({'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2})) if payload is None else {**json.loads(json.dumps({'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('save-success','save-failure') and arg.get('revision',data['save_revision']) != data['save_revision']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state in ('both','inbox-only') and data['item'] not in data['inbox']: data['inbox'].append(data['item'])
            data['banner'] = state in ('banner','both','saving','save-error','recovery-banner')
            if state == 'gone': data['inbox'] = [x for x in data['inbox'] if x != data['item']]
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('banner / retain-in-inbox', solve('banner', [('retain-in-inbox', N)], N), 'saving')
check('saving / save-success', solve('saving', [('save-success', N)], N), 'both')
check('saving / save-failure', solve('saving', [('save-failure', N)], N), 'save-error')
check('both / banner-exposure-end', solve('both', [('banner-exposure-end', N)], N), 'inbox-only')
check('save-error / retry-retention', solve('save-error', [('retry-retention', N)], N), 'saving')
check('saving / banner-exposure-end', solve('saving', [('banner-exposure-end', N)], N), 'saving-without-banner')
check('saving-without-banner / save-success', solve('saving-without-banner', [('save-success', N)], N), 'inbox-only')
check('saving-without-banner / save-failure', solve('saving-without-banner', [('save-failure', N)], N), 'recovery-banner')
check('inbox-only / show-banner-again', solve('inbox-only', [('show-banner-again', N)], N), 'repromoting')
check('repromoting / banner-mounted', solve('repromoting', [('banner-mounted', N)], N), 'both')
check('older notification incarnation', solve('banner', [('retain-in-inbox', N - 1)], N), 'banner')
check('future notification incarnation', solve('banner', [('retain-in-inbox', N + 1)], N), 'banner')
check('unknown event is inert', solve('banner', [('unknown-event', N)], N), 'banner')
check('empty delivery batch', solve('banner', [], N), 'banner')
check('N stale deliveries before current delivery', solve('banner', [('retain-in-inbox', N - 1)] * N + [('retain-in-inbox', N)], N), 'saving')
check('trace retain-in-inbox then save-success', solve('banner', [('retain-in-inbox', N), ('save-success', N)], N), 'both')
check('trace retain-in-inbox then save-failure', solve('banner', [('retain-in-inbox', N), ('save-failure', N)], N), 'save-error')
check('trace retain-in-inbox then banner-exposure-end', solve('banner', [('retain-in-inbox', N), ('banner-exposure-end', N)], N), 'saving-without-banner')
check('trace save-success then banner-exposure-end', solve('saving', [('save-success', N), ('banner-exposure-end', N)], N), 'inbox-only')
check('trace save-failure then retry-retention', solve('saving', [('save-failure', N), ('retry-retention', N)], N), 'saving')
check('trace banner-exposure-end then show-banner-again', solve('both', [('banner-exposure-end', N), ('show-banner-again', N)], N), 'repromoting')
check('trace retry-retention then save-success', solve('save-error', [('retry-retention', N), ('save-success', N)], N), 'both')
check('trace retry-retention then save-failure', solve('save-error', [('retry-retention', N), ('save-failure', N)], N), 'save-error')
check('trace retry-retention then banner-exposure-end', solve('save-error', [('retry-retention', N), ('banner-exposure-end', N)], N), 'saving-without-banner')
check('trace banner-exposure-end then save-success', solve('saving', [('banner-exposure-end', N), ('save-success', N)], N), 'inbox-only')
check('trace banner-exposure-end then save-failure', solve('saving', [('banner-exposure-end', N), ('save-failure', N)], N), 'recovery-banner')
check('trace save-success then show-banner-again', solve('saving-without-banner', [('save-success', N), ('show-banner-again', N)], N), 'repromoting')
check('trace show-banner-again then banner-mounted', solve('inbox-only', [('show-banner-again', N), ('banner-mounted', N)], N), 'both')
check('trace banner-mounted then banner-exposure-end', solve('repromoting', [('banner-mounted', N), ('banner-exposure-end', N)], N), 'inbox-only')
check('domain state regression 1: inbox', solve('saving', [('save-success', N, {'revision': 1})], N, {}, 'inbox'), {'phase': 'saving', 'value': []})
check('domain state regression 2: inbox', solve('saving', [('save-success', N, {'revision': 2})], N, {'inbox': ['other']}, 'inbox'), {'phase': 'both', 'value': ['other', 'n']})
check('domain state regression 3: inbox', solve('both', [('banner-exposure-end', N, {})], N, {'inbox': ['n']}, 'inbox'), {'phase': 'inbox-only', 'value': ['n']})
check('domain state regression 4: banner', solve('both', [('banner-exposure-end', N, {})], N, {'inbox': ['n']}, 'banner'), {'phase': 'inbox-only', 'value': False})
check('domain state regression 5: banner', solve('saving-without-banner', [('save-failure', N, {})], N, {'banner': False}, 'banner'), {'phase': 'recovery-banner', 'value': True})
check('domain state regression 6: banner', solve('saving-without-banner', [('save-success', N, {})], N, {'banner': False}, 'banner'), {'phase': 'inbox-only', 'value': False})
check('domain state regression 7: banner', solve('banner', [('retain-in-inbox', N, {}), ('banner-exposure-end', N, {}), ('save-success', N, {})], N, {}, 'banner'), {'phase': 'inbox-only', 'value': False})
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('banner', 'retain-in-inbox'): 'both', ('saving', 'save-success'): 'both', ('saving', 'save-failure'): 'save-error', ('both', 'banner-exposure-end'): 'inbox-only', ('save-error', 'retry-retention'): 'saving', ('saving', 'banner-exposure-end'): 'saving-without-banner', ('saving-without-banner', 'save-success'): 'inbox-only', ('saving-without-banner', 'save-failure'): 'recovery-banner', ('inbox-only', 'show-banner-again'): 'repromoting', ('repromoting', 'banner-mounted'): 'both'}
    data = json.loads(json.dumps({'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2})) if payload is None else {**json.loads(json.dumps({'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('save-success','save-failure') and arg.get('revision',data['save_revision']) != data['save_revision']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state in ('both','inbox-only') and data['item'] not in data['inbox']: data['inbox'].append(data['item'])
            data['banner'] = state in ('banner','both','saving','save-error','recovery-banner')
            if state == 'gone': data['inbox'] = [x for x in data['inbox'] if x != data['item']]
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('banner / retain-in-inbox', solve('banner', [('retain-in-inbox', N)], N), 'saving')
check('saving / save-success', solve('saving', [('save-success', N)], N), 'both')
check('saving / save-failure', solve('saving', [('save-failure', N)], N), 'save-error')
check('both / banner-exposure-end', solve('both', [('banner-exposure-end', N)], N), 'inbox-only')
check('save-error / retry-retention', solve('save-error', [('retry-retention', N)], N), 'saving')
check('saving / banner-exposure-end', solve('saving', [('banner-exposure-end', N)], N), 'saving-without-banner')
check('saving-without-banner / save-success', solve('saving-without-banner', [('save-success', N)], N), 'inbox-only')
check('saving-without-banner / save-failure', solve('saving-without-banner', [('save-failure', N)], N), 'recovery-banner')
check('inbox-only / show-banner-again', solve('inbox-only', [('show-banner-again', N)], N), 'repromoting')
check('repromoting / banner-mounted', solve('repromoting', [('banner-mounted', N)], N), 'both')
check('older notification incarnation', solve('banner', [('retain-in-inbox', N - 1)], N), 'banner')
check('future notification incarnation', solve('banner', [('retain-in-inbox', N + 1)], N), 'banner')
check('unknown event is inert', solve('banner', [('unknown-event', N)], N), 'banner')
check('empty delivery batch', solve('banner', [], N), 'banner')
check('N stale deliveries before current delivery', solve('banner', [('retain-in-inbox', N - 1)] * N + [('retain-in-inbox', N)], N), 'saving')
check('trace retain-in-inbox then save-success', solve('banner', [('retain-in-inbox', N), ('save-success', N)], N), 'both')
check('trace retain-in-inbox then save-failure', solve('banner', [('retain-in-inbox', N), ('save-failure', N)], N), 'save-error')
check('trace retain-in-inbox then banner-exposure-end', solve('banner', [('retain-in-inbox', N), ('banner-exposure-end', N)], N), 'saving-without-banner')
check('trace save-success then banner-exposure-end', solve('saving', [('save-success', N), ('banner-exposure-end', N)], N), 'inbox-only')
check('trace save-failure then retry-retention', solve('saving', [('save-failure', N), ('retry-retention', N)], N), 'saving')
check('trace banner-exposure-end then show-banner-again', solve('both', [('banner-exposure-end', N), ('show-banner-again', N)], N), 'repromoting')
check('trace retry-retention then save-success', solve('save-error', [('retry-retention', N), ('save-success', N)], N), 'both')
check('trace retry-retention then save-failure', solve('save-error', [('retry-retention', N), ('save-failure', N)], N), 'save-error')
check('trace retry-retention then banner-exposure-end', solve('save-error', [('retry-retention', N), ('banner-exposure-end', N)], N), 'saving-without-banner')
check('trace banner-exposure-end then save-success', solve('saving', [('banner-exposure-end', N), ('save-success', N)], N), 'inbox-only')
check('trace banner-exposure-end then save-failure', solve('saving', [('banner-exposure-end', N), ('save-failure', N)], N), 'recovery-banner')
check('trace save-success then show-banner-again', solve('saving-without-banner', [('save-success', N), ('show-banner-again', N)], N), 'repromoting')
check('trace show-banner-again then banner-mounted', solve('inbox-only', [('show-banner-again', N), ('banner-mounted', N)], N), 'both')
check('trace banner-mounted then banner-exposure-end', solve('repromoting', [('banner-mounted', N), ('banner-exposure-end', N)], N), 'inbox-only')
check('domain state regression 1: inbox', solve('saving', [('save-success', N, {'revision': 1})], N, {}, 'inbox'), {'phase': 'saving', 'value': []})
check('domain state regression 2: inbox', solve('saving', [('save-success', N, {'revision': 2})], N, {'inbox': ['other']}, 'inbox'), {'phase': 'both', 'value': ['other', 'n']})
check('domain state regression 3: inbox', solve('both', [('banner-exposure-end', N, {})], N, {'inbox': ['n']}, 'inbox'), {'phase': 'inbox-only', 'value': ['n']})
check('domain state regression 4: banner', solve('both', [('banner-exposure-end', N, {})], N, {'inbox': ['n']}, 'banner'), {'phase': 'inbox-only', 'value': False})
check('domain state regression 5: banner', solve('saving-without-banner', [('save-failure', N, {})], N, {'banner': False}, 'banner'), {'phase': 'recovery-banner', 'value': True})
check('domain state regression 6: banner', solve('saving-without-banner', [('save-success', N, {})], N, {'banner': False}, 'banner'), {'phase': 'inbox-only', 'value': False})
check('domain state regression 7: banner', solve('banner', [('retain-in-inbox', N, {}), ('banner-exposure-end', N, {}), ('save-success', N, {})], N, {}, 'banner'), {'phase': 'inbox-only', 'value': False})
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)

prompt:
The retain-in-inbox event leaves a notification in inbox-only instead of saving.

Banner to inbox promotion is a bounded visual-notification workflow with mutable policy state {'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2}. Its default transition relation is {('banner', 'retain-in-inbox'): 'saving', ('saving', 'save-success'): 'both', ('saving', 'save-failure'): 'save-error', ('both', 'banner-exposure-end'): 'inbox-only', ('save-error', 'retry-retention'): 'saving', ('saving', 'banner-exposure-end'): 'saving-without-banner', ('saving-without-banner', 'save-success'): 'inbox-only', ('saving-without-banner', 'save-failure'): 'recovery-banner', ('inbox-only', 'show-banner-again'): 'repromoting', ('repromoting', 'banner-mounted'): 'both'}; domain inputs can suppress or redirect transitions and update policy fields, as specified in solve. Different-generation events are inert. Batches apply in order. Optional observe returns the selected policy field alongside the phase.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('banner', 'retain-in-inbox'): 'saving', ('saving', 'save-success'): 'banner', ('saving', 'save-failure'): 'save-error', ('both', 'banner-exposure-end'): 'inbox-only', ('save-error', 'retry-retention'): 'saving', ('saving', 'banner-exposure-end'): 'saving-without-banner', ('saving-without-banner', 'save-success'): 'inbox-only', ('saving-without-banner', 'save-failure'): 'recovery-banner', ('inbox-only', 'show-banner-again'): 'repromoting', ('repromoting', 'banner-mounted'): 'both'}
    data = json.loads(json.dumps({'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2})) if payload is None else {**json.loads(json.dumps({'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('save-success','save-failure') and arg.get('revision',data['save_revision']) != data['save_revision']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state in ('both','inbox-only') and data['item'] not in data['inbox']: data['inbox'].append(data['item'])
            data['banner'] = state in ('banner','both','saving','save-error','recovery-banner')
            if state == 'gone': data['inbox'] = [x for x in data['inbox'] if x != data['item']]
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('banner / retain-in-inbox', solve('banner', [('retain-in-inbox', N)], N), 'saving')
check('saving / save-success', solve('saving', [('save-success', N)], N), 'both')
check('saving / save-failure', solve('saving', [('save-failure', N)], N), 'save-error')
check('both / banner-exposure-end', solve('both', [('banner-exposure-end', N)], N), 'inbox-only')
check('save-error / retry-retention', solve('save-error', [('retry-retention', N)], N), 'saving')
check('saving / banner-exposure-end', solve('saving', [('banner-exposure-end', N)], N), 'saving-without-banner')
check('saving-without-banner / save-success', solve('saving-without-banner', [('save-success', N)], N), 'inbox-only')
check('saving-without-banner / save-failure', solve('saving-without-banner', [('save-failure', N)], N), 'recovery-banner')
check('inbox-only / show-banner-again', solve('inbox-only', [('show-banner-again', N)], N), 'repromoting')
check('repromoting / banner-mounted', solve('repromoting', [('banner-mounted', N)], N), 'both')
check('older notification incarnation', solve('banner', [('retain-in-inbox', N - 1)], N), 'banner')
check('future notification incarnation', solve('banner', [('retain-in-inbox', N + 1)], N), 'banner')
check('unknown event is inert', solve('banner', [('unknown-event', N)], N), 'banner')
check('empty delivery batch', solve('banner', [], N), 'banner')
check('N stale deliveries before current delivery', solve('banner', [('retain-in-inbox', N - 1)] * N + [('retain-in-inbox', N)], N), 'saving')
check('trace retain-in-inbox then save-success', solve('banner', [('retain-in-inbox', N), ('save-success', N)], N), 'both')
check('trace retain-in-inbox then save-failure', solve('banner', [('retain-in-inbox', N), ('save-failure', N)], N), 'save-error')
check('trace retain-in-inbox then banner-exposure-end', solve('banner', [('retain-in-inbox', N), ('banner-exposure-end', N)], N), 'saving-without-banner')
check('trace save-success then banner-exposure-end', solve('saving', [('save-success', N), ('banner-exposure-end', N)], N), 'inbox-only')
check('trace save-failure then retry-retention', solve('saving', [('save-failure', N), ('retry-retention', N)], N), 'saving')
check('trace banner-exposure-end then show-banner-again', solve('both', [('banner-exposure-end', N), ('show-banner-again', N)], N), 'repromoting')
check('trace retry-retention then save-success', solve('save-error', [('retry-retention', N), ('save-success', N)], N), 'both')
check('trace retry-retention then save-failure', solve('save-error', [('retry-retention', N), ('save-failure', N)], N), 'save-error')
check('trace retry-retention then banner-exposure-end', solve('save-error', [('retry-retention', N), ('banner-exposure-end', N)], N), 'saving-without-banner')
check('trace banner-exposure-end then save-success', solve('saving', [('banner-exposure-end', N), ('save-success', N)], N), 'inbox-only')
check('trace banner-exposure-end then save-failure', solve('saving', [('banner-exposure-end', N), ('save-failure', N)], N), 'recovery-banner')
check('trace save-success then show-banner-again', solve('saving-without-banner', [('save-success', N), ('show-banner-again', N)], N), 'repromoting')
check('trace show-banner-again then banner-mounted', solve('inbox-only', [('show-banner-again', N), ('banner-mounted', N)], N), 'both')
check('trace banner-mounted then banner-exposure-end', solve('repromoting', [('banner-mounted', N), ('banner-exposure-end', N)], N), 'inbox-only')
check('domain state regression 1: inbox', solve('saving', [('save-success', N, {'revision': 1})], N, {}, 'inbox'), {'phase': 'saving', 'value': []})
check('domain state regression 2: inbox', solve('saving', [('save-success', N, {'revision': 2})], N, {'inbox': ['other']}, 'inbox'), {'phase': 'both', 'value': ['other', 'n']})
check('domain state regression 3: inbox', solve('both', [('banner-exposure-end', N, {})], N, {'inbox': ['n']}, 'inbox'), {'phase': 'inbox-only', 'value': ['n']})
check('domain state regression 4: banner', solve('both', [('banner-exposure-end', N, {})], N, {'inbox': ['n']}, 'banner'), {'phase': 'inbox-only', 'value': False})
check('domain state regression 5: banner', solve('saving-without-banner', [('save-failure', N, {})], N, {'banner': False}, 'banner'), {'phase': 'recovery-banner', 'value': True})
check('domain state regression 6: banner', solve('saving-without-banner', [('save-success', N, {})], N, {'banner': False}, 'banner'), {'phase': 'inbox-only', 'value': False})
check('domain state regression 7: banner', solve('banner', [('retain-in-inbox', N, {}), ('banner-exposure-end', N, {}), ('save-success', N, {})], N, {}, 'banner'), {'phase': 'inbox-only', 'value': False})
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('banner', 'retain-in-inbox'): 'saving', ('saving', 'save-success'): 'inbox-only', ('saving', 'save-failure'): 'save-error', ('both', 'banner-exposure-end'): 'inbox-only', ('save-error', 'retry-retention'): 'saving', ('saving', 'banner-exposure-end'): 'saving-without-banner', ('saving-without-banner', 'save-success'): 'inbox-only', ('saving-without-banner', 'save-failure'): 'recovery-banner', ('inbox-only', 'show-banner-again'): 'repromoting', ('repromoting', 'banner-mounted'): 'both'}
    data = json.loads(json.dumps({'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2})) if payload is None else {**json.loads(json.dumps({'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2})), **json.loads(json.dumps(payload))}
    state = initial
    for delivery in events:
        event, event_generation = delivery[:2]
        arg = delivery[2] if len(delivery) > 2 else {}
        if event_generation == generation:
            previous = state
            if event in ('save-success','save-failure') and arg.get('revision',data['save_revision']) != data['save_revision']: event = 'unknown-event'
            state = table.get((state, event), state)
            if state in ('both','inbox-only') and data['item'] not in data['inbox']: data['inbox'].append(data['item'])
            data['banner'] = state in ('banner','both','saving','save-error','recovery-banner')
            if state == 'gone': data['inbox'] = [x for x in data['inbox'] if x != data['item']]
    return {'phase': state, 'value': data[observe]} if observe else state
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('banner / retain-in-inbox', solve('banner', [('retain-in-inbox', N)], N), 'saving')
check('saving / save-success', solve('saving', [('save-success', N)], N), 'both')
check('saving / save-failure', solve('saving', [('save-failure', N)], N), 'save-error')
check('both / banner-exposure-end', solve('both', [('banner-exposure-end', N)], N), 'inbox-only')
check('save-error / retry-retention', solve('save-error', [('retry-retention', N)], N), 'saving')
check('saving / banner-exposure-end', solve('saving', [('banner-exposure-end', N)], N), 'saving-without-banner')
check('saving-without-banner / save-success', solve('saving-without-banner', [('save-success', N)], N), 'inbox-only')
check('saving-without-banner / save-failure', solve('saving-without-banner', [('save-failure', N)], N), 'recovery-banner')
check('inbox-only / show-banner-again', solve('inbox-only', [('show-banner-again', N)], N), 'repromoting')
check('repromoting / banner-mounted', solve('repromoting', [('banner-mounted', N)], N), 'both')
check('older notification incarnation', solve('banner', [('retain-in-inbox', N - 1)], N), 'banner')
check('future notification incarnation', solve('banner', [('retain-in-inbox', N + 1)], N), 'banner')
check('unknown event is inert', solve('banner', [('unknown-event', N)], N), 'banner')
check('empty delivery batch', solve('banner', [], N), 'banner')
check('N stale deliveries before current delivery', solve('banner', [('retain-in-inbox', N - 1)] * N + [('retain-in-inbox', N)], N), 'saving')
check('trace retain-in-inbox then save-success', solve('banner', [('retain-in-inbox', N), ('save-success', N)], N), 'both')
check('trace retain-in-inbox then save-failure', solve('banner', [('retain-in-inbox', N), ('save-failure', N)], N), 'save-error')
check('trace retain-in-inbox then banner-exposure-end', solve('banner', [('retain-in-inbox', N), ('banner-exposure-end', N)], N), 'saving-without-banner')
check('trace save-success then banner-exposure-end', solve('saving', [('save-success', N), ('banner-exposure-end', N)], N), 'inbox-only')
check('trace save-failure then retry-retention', solve('saving', [('save-failure', N), ('retry-retention', N)], N), 'saving')
check('trace banner-exposure-end then show-banner-again', solve('both', [('banner-exposure-end', N), ('show-banner-again', N)], N), 'repromoting')
check('trace retry-retention then save-success', solve('save-error', [('retry-retention', N), ('save-success', N)], N), 'both')
check('trace retry-retention then save-failure', solve('save-error', [('retry-retention', N), ('save-failure', N)], N), 'save-error')
check('trace retry-retention then banner-exposure-end', solve('save-error', [('retry-retention', N), ('banner-exposure-end', N)], N), 'saving-without-banner')
check('trace banner-exposure-end then save-success', solve('saving', [('banner-exposure-end', N), ('save-success', N)], N), 'inbox-only')
check('trace banner-exposure-end then save-failure', solve('saving', [('banner-exposure-end', N), ('save-failure', N)], N), 'recovery-banner')
check('trace save-success then show-banner-again', solve('saving-without-banner', [('save-success', N), ('show-banner-again', N)], N), 'repromoting')
check('trace show-banner-again then banner-mounted', solve('inbox-only', [('show-banner-again', N), ('banner-mounted', N)], N), 'both')
check('trace banner-mounted then banner-exposure-end', solve('repromoting', [('banner-mounted', N), ('banner-exposure-end', N)], N), 'inbox-only')
check('domain state regression 1: inbox', solve('saving', [('save-success', N, {'revision': 1})], N, {}, 'inbox'), {'phase': 'saving', 'value': []})
check('domain state regression 2: inbox', solve('saving', [('save-success', N, {'revision': 2})], N, {'inbox': ['other']}, 'inbox'), {'phase': 'both', 'value': ['other', 'n']})
check('domain state regression 3: inbox', solve('both', [('banner-exposure-end', N, {})], N, {'inbox': ['n']}, 'inbox'), {'phase': 'inbox-only', 'value': ['n']})
check('domain state regression 4: banner', solve('both', [('banner-exposure-end', N, {})], N, {'inbox': ['n']}, 'banner'), {'phase': 'inbox-only', 'value': False})
check('domain state regression 5: banner', solve('saving-without-banner', [('save-failure', N, {})], N, {'banner': False}, 'banner'), {'phase': 'recovery-banner', 'value': True})
check('domain state regression 6: banner', solve('saving-without-banner', [('save-success', N, {})], N, {'banner': False}, 'banner'), {'phase': 'inbox-only', 'value': False})
check('domain state regression 7: banner', solve('banner', [('retain-in-inbox', N, {}), ('banner-exposure-end', N, {}), ('save-success', N, {})], N, {}, 'banner'), {'phase': 'inbox-only', 'value': False})
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)

prompt:
The save-success event leaves a notification in banner instead of both.

Banner to inbox promotion is a bounded visual-notification workflow with mutable policy state {'banner': True, 'inbox': [], 'item': 'n', 'save_revision': 2}. Its default transition relation is {('banner', 'retain-in-inbox'): 'saving', ('saving', 'save-success'): 'both', ('saving', 'save-failure'): 'save-error', ('both', 'banner-exposure-end'): 'inbox-only', ('save-error', 'retry-retention'): 'saving', ('saving', 'banner-exposure-end'): 'saving-without-banner', ('saving-without-banner', 'save-success'): 'inbox-only', ('saving-without-banner', 'save-failure'): 'recovery-banner', ('inbox-only', 'show-banner-again'): 'repromoting', ('repromoting', 'banner-mounted'): 'both'}; domain inputs can suppress or redirect transitions and update policy fields, as specified in solve. Different-generation events are inert. Batches apply in order. Optional observe returns the selected policy field alongside the phase.

split: open-access