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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'qualifying', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'offscreen', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 report-success event leaves a notification in qualifying instead of counted.

Notification visual impression qualification is a bounded visual-notification workflow with mutable policy state {'exposure': 0, 'required': 4, 'covered': False, 'reports': 0}. Its default transition relation is {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}; 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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'counted', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'qualifying', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 report-failure event leaves a notification in counted instead of report-error.

Notification visual impression qualification is a bounded visual-notification workflow with mutable policy state {'exposure': 0, 'required': 4, 'covered': False, 'reports': 0}. Its default transition relation is {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}; 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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'counted', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'offscreen', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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-report event leaves a notification in counted instead of reporting.

Notification visual impression qualification is a bounded visual-notification workflow with mutable policy state {'exposure': 0, 'required': 4, 'covered': False, 'reports': 0}. Its default transition relation is {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}; 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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'reporting', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'counted', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 covered-by-overlay event leaves a notification in reporting instead of occluded.

Notification visual impression qualification is a bounded visual-notification workflow with mutable policy state {'exposure': 0, 'required': 4, 'covered': False, 'reports': 0}. Its default transition relation is {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}; 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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'counted', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 = {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'reporting', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}
    data = json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})) if payload is None else {**json.loads(json.dumps({'exposure': 0, 'required': 4, 'covered': False, 'reports': 0})), **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 == 'covered-by-overlay': data['covered'] = True
            if event == 'overlay-removed':
                data['covered'] = False
                data['exposure'] = 0
            if event == 'exposure-satisfied':
                if not data['covered']: data['exposure'] += max(0,arg.get('elapsed',data['required']))
                if data['exposure'] < data['required'] or data['covered']: event = 'unknown-event'
            if event == 'leaves-viewport' and state == 'qualifying': data['exposure'] = 0
            state = table.get((state, event), state)
            if state == 'counted' and previous != 'counted': data['reports'] += 1
    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('offscreen / enters-viewport', solve('offscreen', [('enters-viewport', N)], N), 'qualifying')
check('qualifying / exposure-satisfied', solve('qualifying', [('exposure-satisfied', N)], N), 'reporting')
check('qualifying / leaves-viewport', solve('qualifying', [('leaves-viewport', N)], N), 'offscreen')
check('reporting / report-success', solve('reporting', [('report-success', N)], N), 'counted')
check('reporting / report-failure', solve('reporting', [('report-failure', N)], N), 'report-error')
check('report-error / retry-report', solve('report-error', [('retry-report', N)], N), 'reporting')
check('qualifying / covered-by-overlay', solve('qualifying', [('covered-by-overlay', N)], N), 'occluded')
check('occluded / overlay-removed', solve('occluded', [('overlay-removed', N)], N), 'qualifying')
check('counted / reenter-viewport', solve('counted', [('reenter-viewport', N)], N), 'counted')
check('reporting / leaves-viewport', solve('reporting', [('leaves-viewport', N)], N), 'reporting')
check('older notification incarnation', solve('offscreen', [('enters-viewport', N - 1)], N), 'offscreen')
check('future notification incarnation', solve('offscreen', [('enters-viewport', N + 1)], N), 'offscreen')
check('unknown event is inert', solve('offscreen', [('unknown-event', N)], N), 'offscreen')
check('empty delivery batch', solve('offscreen', [], N), 'offscreen')
check('N stale deliveries before current delivery', solve('offscreen', [('enters-viewport', N - 1)] * N + [('enters-viewport', N)], N), 'qualifying')
check('trace enters-viewport then exposure-satisfied', solve('offscreen', [('enters-viewport', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace enters-viewport then leaves-viewport', solve('offscreen', [('enters-viewport', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace enters-viewport then covered-by-overlay', solve('offscreen', [('enters-viewport', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace exposure-satisfied then report-success', solve('qualifying', [('exposure-satisfied', N), ('report-success', N)], N), 'counted')
check('trace exposure-satisfied then report-failure', solve('qualifying', [('exposure-satisfied', N), ('report-failure', N)], N), 'report-error')
check('trace exposure-satisfied then leaves-viewport', solve('qualifying', [('exposure-satisfied', N), ('leaves-viewport', N)], N), 'reporting')
check('trace leaves-viewport then enters-viewport', solve('qualifying', [('leaves-viewport', N), ('enters-viewport', N)], N), 'qualifying')
check('trace report-success then reenter-viewport', solve('reporting', [('report-success', N), ('reenter-viewport', N)], N), 'counted')
check('trace report-failure then retry-report', solve('reporting', [('report-failure', N), ('retry-report', N)], N), 'reporting')
check('trace retry-report then report-success', solve('report-error', [('retry-report', N), ('report-success', N)], N), 'counted')
check('trace retry-report then report-failure', solve('report-error', [('retry-report', N), ('report-failure', N)], N), 'report-error')
check('trace retry-report then leaves-viewport', solve('report-error', [('retry-report', N), ('leaves-viewport', N)], N), 'reporting')
check('trace covered-by-overlay then overlay-removed', solve('qualifying', [('covered-by-overlay', N), ('overlay-removed', N)], N), 'qualifying')
check('trace overlay-removed then exposure-satisfied', solve('occluded', [('overlay-removed', N), ('exposure-satisfied', N)], N), 'reporting')
check('trace overlay-removed then leaves-viewport', solve('occluded', [('overlay-removed', N), ('leaves-viewport', N)], N), 'offscreen')
check('trace overlay-removed then covered-by-overlay', solve('occluded', [('overlay-removed', N), ('covered-by-overlay', N)], N), 'occluded')
check('trace reenter-viewport then reenter-viewport', solve('counted', [('reenter-viewport', N), ('reenter-viewport', N)], N), 'counted')
check('trace leaves-viewport then report-success', solve('reporting', [('leaves-viewport', N), ('report-success', N)], N), 'counted')
check('trace leaves-viewport then report-failure', solve('reporting', [('leaves-viewport', N), ('report-failure', N)], N), 'report-error')
check('trace leaves-viewport then leaves-viewport', solve('reporting', [('leaves-viewport', N), ('leaves-viewport', N)], N), 'reporting')
check('domain state regression 1: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
check('domain state regression 2: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 4})], N, {}, 'exposure'), {'phase': 'reporting', 'value': 4})
check('domain state regression 3: exposure', solve('qualifying', [('exposure-satisfied', N, {'elapsed': 9})], N, {'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 4: exposure', solve('occluded', [('overlay-removed', N, {})], N, {'exposure': 3, 'covered': True}, 'exposure'), {'phase': 'qualifying', 'value': 0})
check('domain state regression 5: exposure', solve('qualifying', [('leaves-viewport', N, {})], N, {'exposure': 3}, 'exposure'), {'phase': 'offscreen', 'value': 0})
check('domain state regression 6: reports', solve('counted', [('reenter-viewport', N, {})], N, {'reports': 1}, 'reports'), {'phase': 'counted', 'value': 1})
check('domain state regression 7: exposure', solve('offscreen', [('enters-viewport', N, {}), ('exposure-satisfied', N, {'elapsed': 3}), ('covered-by-overlay', N, {}), ('overlay-removed', N, {}), ('exposure-satisfied', N, {'elapsed': 3})], N, {}, 'exposure'), {'phase': 'qualifying', 'value': 3})
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 overlay-removed event leaves a notification in counted instead of qualifying.

Notification visual impression qualification is a bounded visual-notification workflow with mutable policy state {'exposure': 0, 'required': 4, 'covered': False, 'reports': 0}. Its default transition relation is {('offscreen', 'enters-viewport'): 'qualifying', ('qualifying', 'exposure-satisfied'): 'reporting', ('qualifying', 'leaves-viewport'): 'offscreen', ('reporting', 'report-success'): 'counted', ('reporting', 'report-failure'): 'report-error', ('report-error', 'retry-report'): 'reporting', ('qualifying', 'covered-by-overlay'): 'occluded', ('occluded', 'overlay-removed'): 'qualifying', ('counted', 'reenter-viewport'): 'counted', ('reporting', 'leaves-viewport'): 'reporting'}; 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