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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-a-visible', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-visible', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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-a-response event leaves a notification in account-a-visible instead of account-b-loading.

Notification surface account switch is a bounded visual-notification workflow with mutable policy state {'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False}. Its default transition relation is {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}; 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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-a-visible', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-visible', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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 retry-b-load event leaves a notification in account-a-visible instead of account-b-loading.

Notification surface account switch is a bounded visual-notification workflow with mutable policy state {'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False}. Its default transition relation is {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}; 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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'signed-out', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'account-a-visible', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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 sign-out event leaves a notification in signed-out instead of scrubbing-b.

Notification surface account switch is a bounded visual-notification workflow with mutable policy state {'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False}. Its default transition relation is {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}; 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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'account-b-visible', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'account-b-loading', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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 scrub-complete event leaves a notification in account-b-visible instead of signed-out.

Notification surface account switch is a bounded visual-notification workflow with mutable policy state {'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False}. Its default transition relation is {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}; 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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'account-b-visible', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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 = {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'account-b-loading', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}
    data = json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})) if payload is None else {**json.loads(json.dumps({'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False})), **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 == 'b-inbox-loaded' and arg.get('owner',data['target']) != data['target']: event = 'unknown-event'
            if event == 'b-inbox-loaded' and not data['scrubbed'] and arg.get('require_scrub',False): event = 'unknown-event'
            if event == 'switch-back-to-a': data['target'] = 'a'
            state = table.get((state, event), state)
            if state.startswith('scrubbing'):
                data['rows'] = []
                data['scrubbed'] = False
            if event == 'scrub-complete': data['scrubbed'] = True
            if state == 'account-b-visible':
                data['owner'] = 'b'
                data['rows'] = arg.get('rows',['b-notice'])[:]
            if state == 'signed-out':
                data['owner'] = None
                data['rows'] = []
    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('account-a-visible / switch-to-b', solve('account-a-visible', [('switch-to-b', N)], N), 'scrubbing-a')
check('scrubbing-a / scrub-complete', solve('scrubbing-a', [('scrub-complete', N)], N), 'account-b-loading')
check('account-b-loading / b-inbox-loaded', solve('account-b-loading', [('b-inbox-loaded', N)], N), 'account-b-visible')
check('account-b-loading / b-inbox-failed', solve('account-b-loading', [('b-inbox-failed', N)], N), 'switch-error')
check('account-b-loading / late-a-response', solve('account-b-loading', [('late-a-response', N)], N), 'account-b-loading')
check('switch-error / retry-b-load', solve('switch-error', [('retry-b-load', N)], N), 'account-b-loading')
check('account-b-visible / sign-out', solve('account-b-visible', [('sign-out', N)], N), 'scrubbing-b')
check('scrubbing-b / scrub-complete', solve('scrubbing-b', [('scrub-complete', N)], N), 'signed-out')
check('signed-out / late-b-response', solve('signed-out', [('late-b-response', N)], N), 'signed-out')
check('scrubbing-a / switch-back-to-a', solve('scrubbing-a', [('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('older notification incarnation', solve('account-a-visible', [('switch-to-b', N - 1)], N), 'account-a-visible')
check('future notification incarnation', solve('account-a-visible', [('switch-to-b', N + 1)], N), 'account-a-visible')
check('unknown event is inert', solve('account-a-visible', [('unknown-event', N)], N), 'account-a-visible')
check('empty delivery batch', solve('account-a-visible', [], N), 'account-a-visible')
check('N stale deliveries before current delivery', solve('account-a-visible', [('switch-to-b', N - 1)] * N + [('switch-to-b', N)], N), 'scrubbing-a')
check('trace switch-to-b then scrub-complete', solve('account-a-visible', [('switch-to-b', N), ('scrub-complete', N)], N), 'account-b-loading')
check('trace switch-to-b then switch-back-to-a', solve('account-a-visible', [('switch-to-b', N), ('switch-back-to-a', N)], N), 'scrubbing-for-a')
check('trace scrub-complete then b-inbox-loaded', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace scrub-complete then b-inbox-failed', solve('scrubbing-a', [('scrub-complete', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace scrub-complete then late-a-response', solve('scrubbing-a', [('scrub-complete', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace b-inbox-loaded then sign-out', solve('account-b-loading', [('b-inbox-loaded', N), ('sign-out', N)], N), 'scrubbing-b')
check('trace b-inbox-failed then retry-b-load', solve('account-b-loading', [('b-inbox-failed', N), ('retry-b-load', N)], N), 'account-b-loading')
check('trace late-a-response then b-inbox-loaded', solve('account-b-loading', [('late-a-response', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace late-a-response then b-inbox-failed', solve('account-b-loading', [('late-a-response', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace late-a-response then late-a-response', solve('account-b-loading', [('late-a-response', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace retry-b-load then b-inbox-loaded', solve('switch-error', [('retry-b-load', N), ('b-inbox-loaded', N)], N), 'account-b-visible')
check('trace retry-b-load then b-inbox-failed', solve('switch-error', [('retry-b-load', N), ('b-inbox-failed', N)], N), 'switch-error')
check('trace retry-b-load then late-a-response', solve('switch-error', [('retry-b-load', N), ('late-a-response', N)], N), 'account-b-loading')
check('trace sign-out then scrub-complete', solve('account-b-visible', [('sign-out', N), ('scrub-complete', N)], N), 'signed-out')
check('trace scrub-complete then late-b-response', solve('scrubbing-b', [('scrub-complete', N), ('late-b-response', N)], N), 'signed-out')
check('trace late-b-response then late-b-response', solve('signed-out', [('late-b-response', N), ('late-b-response', N)], N), 'signed-out')
check('domain state regression 1: rows', solve('account-a-visible', [('switch-to-b', N, {})], N, {}, 'rows'), {'phase': 'scrubbing-a', 'value': []})
check('domain state regression 2: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'owner': 'a'})], N, {}, 'rows'), {'phase': 'account-b-loading', 'value': ['a-notice']})
check('domain state regression 3: owner', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {}, 'owner'), {'phase': 'account-b-loading', 'value': 'a'})
check('domain state regression 4: rows', solve('account-b-loading', [('b-inbox-loaded', N, {'require_scrub': True})], N, {'scrubbed': True, 'rows': []}, 'rows'), {'phase': 'account-b-visible', 'value': ['b-notice']})
check('domain state regression 5: owner', solve('scrubbing-b', [('scrub-complete', N, {})], N, {'owner': 'b'}, 'owner'), {'phase': 'signed-out', 'value': None})
check('domain state regression 6: target', solve('scrubbing-a', [('switch-back-to-a', N, {})], N, {}, 'target'), {'phase': 'scrubbing-for-a', 'value': 'a'})
check('domain state regression 7: rows', solve('account-a-visible', [('switch-to-b', N, {}), ('scrub-complete', N, {}), ('b-inbox-loaded', N, {'require_scrub': True, 'rows': ['b']}), ('sign-out', N, {}), ('scrub-complete', N, {}), ('late-b-response', N, {})], N, {}, 'rows'), {'phase': 'signed-out', 'value': []})
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-b-response event leaves a notification in account-b-visible instead of signed-out.

Notification surface account switch is a bounded visual-notification workflow with mutable policy state {'owner': 'a', 'rows': ['a-notice'], 'target': 'b', 'scrubbed': False}. Its default transition relation is {('account-a-visible', 'switch-to-b'): 'scrubbing-a', ('scrubbing-a', 'scrub-complete'): 'account-b-loading', ('account-b-loading', 'b-inbox-loaded'): 'account-b-visible', ('account-b-loading', 'b-inbox-failed'): 'switch-error', ('account-b-loading', 'late-a-response'): 'account-b-loading', ('switch-error', 'retry-b-load'): 'account-b-loading', ('account-b-visible', 'sign-out'): 'scrubbing-b', ('scrubbing-b', 'scrub-complete'): 'signed-out', ('signed-out', 'late-b-response'): 'signed-out', ('scrubbing-a', 'switch-back-to-a'): 'scrubbing-for-a'}; 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