FAILURE MAP
← Case archive

FA-34191 / Notification interfaces / Open access

Notification inbox reconnect recovery: connection-lost from live · case 01

The connection-lost event leaves a notification in empty instead of offline-cached.

Verified by executionVariant 1 · 39 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Transport loss clears readable cached notifications.

VERIFIED REPAIR

Commit the live / connection-lost transition to offline-cached; preserve the other explicitly stipulated transitions.

Unsuccessful approach: Replacing the cache with a spinner prevents offline inspection.

Case contract

Notification inbox reconnect recovery is a bounded visual-notification workflow with mutable policy state {'cached': ['old'], 'cursor': 8, 'preview': 'old', 'fresh': False}. Its default transition relation is {('live', 'connection-lost'): 'offline-cached', ('offline-cached', 'connection-restored'): 'reconciling', ('reconciling', 'snapshot-current'): 'live', ('reconciling', 'snapshot-failed'): 'offline-error', ('offline-error', 'retry-refresh'): 'reconciling', ('reconciling', 'connection-lost'): 'offline-cached', ('offline-cached', 'open-cached-item'): 'offline-preview', ('offline-preview', 'close-preview'): 'offline-cached', ('offline-preview', 'connection-restored'): 'reconciling-preview', ('reconciling-preview', 'snapshot-current'): 'live-preview'}; 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.

Why this case matters

Visual notification lifecycle ordering can leave an inbox or toast showing the wrong actionable state even when transport succeeds.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('live', 'connection-lost'): 'empty', ('offline-cached', 'connection-restored'): 'reconciling', ('reconciling', 'snapshot-current'): 'live', ('reconciling', 'snapshot-failed'): 'offline-error', ('offline-error', 'retry-refresh'): 'reconciling', ('reconciling', 'connection-lost'): 'offline-cached', ('offline-cached', 'open-cached-item'): 'offline-preview', ('offline-preview', 'close-preview'): 'offline-cached', ('offline-preview', 'connection-restored'): 'reconciling-preview', ('reconciling-preview', 'snapshot-current'): 'live-preview'}
    data = json.loads(json.dumps({'cached': ['old'], 'cursor': 8, 'preview': 'old', 'fresh': False})) if payload is None else {**json.loads(json.dumps({'cached': ['old'], 'cursor': 8, 'preview': 'old', 'fresh': 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 == 'snapshot-current':
                if arg.get('cursor',data['cursor']) < data['cursor']: event = 'unknown-event'
                else:
                    data['cursor'] = arg.get('cursor',data['cursor'])
                    data['cached'] = arg.get('items',data['cached'])[:]
            if event == 'connection-lost': data['fresh'] = False
            state = table.get((state, event), state)
            if state in ('live','live-preview'): data['fresh'] = True
            if state == 'live-preview' and data['preview'] not in data['cached']: data['preview'] = None
            if state == 'empty': data['cached'] = []
    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('live / connection-lost', solve('live', [('connection-lost', N)], N), 'offline-cached')
check('offline-cached / connection-restored', solve('offline-cached', [('connection-restored', N)], N), 'reconciling')
check('reconciling / snapshot-current', solve('reconciling', [('snapshot-current', N)], N), 'live')
check('reconciling / snapshot-failed', solve('reconciling', [('snapshot-failed', N)], N), 'offline-error')
check('offline-error / retry-refresh', solve('offline-error', [('retry-refresh', N)], N), 'reconciling')
check('reconciling / connection-lost', solve('reconciling', [('connection-lost', N)], N), 'offline-cached')
check('offline-cached / open-cached-item', solve('offline-cached', [('open-cached-item', N)], N), 'offline-preview')
check('offline-preview / close-preview', solve('offline-preview', [('close-preview', N)], N), 'offline-cached')
check('offline-preview / connection-restored', solve('offline-preview', [('connection-restored', N)], N), 'reconciling-preview')
check('reconciling-preview / snapshot-current', solve('reconciling-preview', [('snapshot-current', N)], N), 'live-preview')
check('older notification incarnation', solve('live', [('connection-lost', N - 1)], N), 'live')
check('future notification incarnation', solve('live', [('connection-lost', N + 1)], N), 'live')
check('unknown event is inert', solve('live', [('unknown-event', N)], N), 'live')
check('empty delivery batch', solve('live', [], N), 'live')
check('N stale deliveries before current delivery', solve('live', [('connection-lost', N - 1)] * N + [('connection-lost', N)], N), 'offline-cached')
check('trace connection-lost then connection-restored', solve('live', [('connection-lost', N), ('connection-restored', N)], N), 'reconciling')
check('trace connection-lost then open-cached-item', solve('live', [('connection-lost', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace connection-restored then snapshot-current', solve('offline-cached', [('connection-restored', N), ('snapshot-current', N)], N), 'live')
check('trace connection-restored then snapshot-failed', solve('offline-cached', [('connection-restored', N), ('snapshot-failed', N)], N), 'offline-error')
check('trace connection-restored then connection-lost', solve('offline-cached', [('connection-restored', N), ('connection-lost', N)], N), 'offline-cached')
check('trace snapshot-current then connection-lost', solve('reconciling', [('snapshot-current', N), ('connection-lost', N)], N), 'offline-cached')
check('trace snapshot-failed then retry-refresh', solve('reconciling', [('snapshot-failed', N), ('retry-refresh', N)], N), 'reconciling')
check('trace retry-refresh then snapshot-current', solve('offline-error', [('retry-refresh', N), ('snapshot-current', N)], N), 'live')
check('trace retry-refresh then snapshot-failed', solve('offline-error', [('retry-refresh', N), ('snapshot-failed', N)], N), 'offline-error')
check('trace retry-refresh then connection-lost', solve('offline-error', [('retry-refresh', N), ('connection-lost', N)], N), 'offline-cached')
check('trace connection-lost then connection-restored', solve('reconciling', [('connection-lost', N), ('connection-restored', N)], N), 'reconciling')
check('trace connection-lost then open-cached-item', solve('reconciling', [('connection-lost', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace open-cached-item then close-preview', solve('offline-cached', [('open-cached-item', N), ('close-preview', N)], N), 'offline-cached')
check('trace open-cached-item then connection-restored', solve('offline-cached', [('open-cached-item', N), ('connection-restored', N)], N), 'reconciling-preview')
check('trace close-preview then connection-restored', solve('offline-preview', [('close-preview', N), ('connection-restored', N)], N), 'reconciling')
check('trace close-preview then open-cached-item', solve('offline-preview', [('close-preview', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace connection-restored then snapshot-current', solve('offline-preview', [('connection-restored', N), ('snapshot-current', N)], N), 'live-preview')
check('domain state regression 1: cached', solve('reconciling', [('snapshot-current', N, {'cursor': 7, 'items': ['stale']})], N, {}, 'cached'), {'phase': 'reconciling', 'value': ['old']})
check('domain state regression 2: cached', solve('reconciling', [('snapshot-current', N, {'cursor': 9, 'items': ['new']})], N, {}, 'cached'), {'phase': 'live', 'value': ['new']})
check('domain state regression 3: cached', solve('live', [('connection-lost', N, {})], N, {'fresh': True}, 'cached'), {'phase': 'offline-cached', 'value': ['old']})
check('domain state regression 4: preview', solve('reconciling-preview', [('snapshot-current', N, {'items': ['new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': None})
check('domain state regression 5: preview', solve('reconciling-preview', [('snapshot-current', N, {'items': ['old', 'new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': 'old'})
check('domain state regression 6: fresh', solve('reconciling', [('snapshot-failed', N, {})], N, {}, 'fresh'), {'phase': 'offline-error', 'value': False})
check('domain state regression 7: preview', solve('offline-preview', [('connection-restored', N, {}), ('snapshot-current', N, {'cursor': 9, 'items': ['new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': None})
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
live / connection-lostemptyoffline-cachedFailed
offline-cached / connection-restoredreconcilingreconcilingPassed
reconciling / snapshot-currentlivelivePassed
reconciling / snapshot-failedoffline-erroroffline-errorPassed
offline-error / retry-refreshreconcilingreconcilingPassed
reconciling / connection-lostoffline-cachedoffline-cachedPassed
offline-cached / open-cached-itemoffline-previewoffline-previewPassed
offline-preview / close-previewoffline-cachedoffline-cachedPassed
offline-preview / connection-restoredreconciling-previewreconciling-previewPassed
reconciling-preview / snapshot-currentlive-previewlive-previewPassed
older notification incarnationlivelivePassed
future notification incarnationlivelivePassed
unknown event is inertlivelivePassed
empty delivery batchlivelivePassed
N stale deliveries before current deliveryemptyoffline-cachedFailed
trace connection-lost then connection-restoredemptyreconcilingFailed
trace connection-lost then open-cached-itememptyoffline-previewFailed
trace connection-restored then snapshot-currentlivelivePassed
trace connection-restored then snapshot-failedoffline-erroroffline-errorPassed
trace connection-restored then connection-lostoffline-cachedoffline-cachedPassed
trace snapshot-current then connection-lostemptyoffline-cachedFailed
trace snapshot-failed then retry-refreshreconcilingreconcilingPassed
trace retry-refresh then snapshot-currentlivelivePassed
trace retry-refresh then snapshot-failedoffline-erroroffline-errorPassed
trace retry-refresh then connection-lostoffline-cachedoffline-cachedPassed
trace connection-lost then connection-restoredreconcilingreconcilingPassed
trace connection-lost then open-cached-itemoffline-previewoffline-previewPassed
trace open-cached-item then close-previewoffline-cachedoffline-cachedPassed
trace open-cached-item then connection-restoredreconciling-previewreconciling-previewPassed
trace close-preview then connection-restoredreconcilingreconcilingPassed
trace close-preview then open-cached-itemoffline-previewoffline-previewPassed
trace connection-restored then snapshot-currentlive-previewlive-previewPassed
domain state regression 1: cached{'phase': 'reconciling', 'value': ['old']}{'phase': 'reconciling', 'value': ['old']}Passed
domain state regression 2: cached{'phase': 'live', 'value': ['new']}{'phase': 'live', 'value': ['new']}Passed
domain state regression 3: cached{'phase': 'empty', 'value': []}{'phase': 'offline-cached', 'value': ['old']}Failed
domain state regression 4: preview{'phase': 'live-preview', 'value': None}{'phase': 'live-preview', 'value': None}Passed
domain state regression 5: preview{'phase': 'live-preview', 'value': 'old'}{'phase': 'live-preview', 'value': 'old'}Passed
domain state regression 6: fresh{'phase': 'offline-error', 'value': False}{'phase': 'offline-error', 'value': False}Passed
domain state regression 7: preview{'phase': 'live-preview', 'value': None}{'phase': 'live-preview', 'value': None}Passed

SHA-256 / aab025ed71b7d8c5cbf603aa94c78358cb583b129a5562d114d7b5f007341c4a

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('live', 'connection-lost'): 'loading', ('offline-cached', 'connection-restored'): 'reconciling', ('reconciling', 'snapshot-current'): 'live', ('reconciling', 'snapshot-failed'): 'offline-error', ('offline-error', 'retry-refresh'): 'reconciling', ('reconciling', 'connection-lost'): 'offline-cached', ('offline-cached', 'open-cached-item'): 'offline-preview', ('offline-preview', 'close-preview'): 'offline-cached', ('offline-preview', 'connection-restored'): 'reconciling-preview', ('reconciling-preview', 'snapshot-current'): 'live-preview'}
    data = json.loads(json.dumps({'cached': ['old'], 'cursor': 8, 'preview': 'old', 'fresh': False})) if payload is None else {**json.loads(json.dumps({'cached': ['old'], 'cursor': 8, 'preview': 'old', 'fresh': 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 == 'snapshot-current':
                if arg.get('cursor',data['cursor']) < data['cursor']: event = 'unknown-event'
                else:
                    data['cursor'] = arg.get('cursor',data['cursor'])
                    data['cached'] = arg.get('items',data['cached'])[:]
            if event == 'connection-lost': data['fresh'] = False
            state = table.get((state, event), state)
            if state in ('live','live-preview'): data['fresh'] = True
            if state == 'live-preview' and data['preview'] not in data['cached']: data['preview'] = None
            if state == 'empty': data['cached'] = []
    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('live / connection-lost', solve('live', [('connection-lost', N)], N), 'offline-cached')
check('offline-cached / connection-restored', solve('offline-cached', [('connection-restored', N)], N), 'reconciling')
check('reconciling / snapshot-current', solve('reconciling', [('snapshot-current', N)], N), 'live')
check('reconciling / snapshot-failed', solve('reconciling', [('snapshot-failed', N)], N), 'offline-error')
check('offline-error / retry-refresh', solve('offline-error', [('retry-refresh', N)], N), 'reconciling')
check('reconciling / connection-lost', solve('reconciling', [('connection-lost', N)], N), 'offline-cached')
check('offline-cached / open-cached-item', solve('offline-cached', [('open-cached-item', N)], N), 'offline-preview')
check('offline-preview / close-preview', solve('offline-preview', [('close-preview', N)], N), 'offline-cached')
check('offline-preview / connection-restored', solve('offline-preview', [('connection-restored', N)], N), 'reconciling-preview')
check('reconciling-preview / snapshot-current', solve('reconciling-preview', [('snapshot-current', N)], N), 'live-preview')
check('older notification incarnation', solve('live', [('connection-lost', N - 1)], N), 'live')
check('future notification incarnation', solve('live', [('connection-lost', N + 1)], N), 'live')
check('unknown event is inert', solve('live', [('unknown-event', N)], N), 'live')
check('empty delivery batch', solve('live', [], N), 'live')
check('N stale deliveries before current delivery', solve('live', [('connection-lost', N - 1)] * N + [('connection-lost', N)], N), 'offline-cached')
check('trace connection-lost then connection-restored', solve('live', [('connection-lost', N), ('connection-restored', N)], N), 'reconciling')
check('trace connection-lost then open-cached-item', solve('live', [('connection-lost', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace connection-restored then snapshot-current', solve('offline-cached', [('connection-restored', N), ('snapshot-current', N)], N), 'live')
check('trace connection-restored then snapshot-failed', solve('offline-cached', [('connection-restored', N), ('snapshot-failed', N)], N), 'offline-error')
check('trace connection-restored then connection-lost', solve('offline-cached', [('connection-restored', N), ('connection-lost', N)], N), 'offline-cached')
check('trace snapshot-current then connection-lost', solve('reconciling', [('snapshot-current', N), ('connection-lost', N)], N), 'offline-cached')
check('trace snapshot-failed then retry-refresh', solve('reconciling', [('snapshot-failed', N), ('retry-refresh', N)], N), 'reconciling')
check('trace retry-refresh then snapshot-current', solve('offline-error', [('retry-refresh', N), ('snapshot-current', N)], N), 'live')
check('trace retry-refresh then snapshot-failed', solve('offline-error', [('retry-refresh', N), ('snapshot-failed', N)], N), 'offline-error')
check('trace retry-refresh then connection-lost', solve('offline-error', [('retry-refresh', N), ('connection-lost', N)], N), 'offline-cached')
check('trace connection-lost then connection-restored', solve('reconciling', [('connection-lost', N), ('connection-restored', N)], N), 'reconciling')
check('trace connection-lost then open-cached-item', solve('reconciling', [('connection-lost', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace open-cached-item then close-preview', solve('offline-cached', [('open-cached-item', N), ('close-preview', N)], N), 'offline-cached')
check('trace open-cached-item then connection-restored', solve('offline-cached', [('open-cached-item', N), ('connection-restored', N)], N), 'reconciling-preview')
check('trace close-preview then connection-restored', solve('offline-preview', [('close-preview', N), ('connection-restored', N)], N), 'reconciling')
check('trace close-preview then open-cached-item', solve('offline-preview', [('close-preview', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace connection-restored then snapshot-current', solve('offline-preview', [('connection-restored', N), ('snapshot-current', N)], N), 'live-preview')
check('domain state regression 1: cached', solve('reconciling', [('snapshot-current', N, {'cursor': 7, 'items': ['stale']})], N, {}, 'cached'), {'phase': 'reconciling', 'value': ['old']})
check('domain state regression 2: cached', solve('reconciling', [('snapshot-current', N, {'cursor': 9, 'items': ['new']})], N, {}, 'cached'), {'phase': 'live', 'value': ['new']})
check('domain state regression 3: cached', solve('live', [('connection-lost', N, {})], N, {'fresh': True}, 'cached'), {'phase': 'offline-cached', 'value': ['old']})
check('domain state regression 4: preview', solve('reconciling-preview', [('snapshot-current', N, {'items': ['new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': None})
check('domain state regression 5: preview', solve('reconciling-preview', [('snapshot-current', N, {'items': ['old', 'new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': 'old'})
check('domain state regression 6: fresh', solve('reconciling', [('snapshot-failed', N, {})], N, {}, 'fresh'), {'phase': 'offline-error', 'value': False})
check('domain state regression 7: preview', solve('offline-preview', [('connection-restored', N, {}), ('snapshot-current', N, {'cursor': 9, 'items': ['new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': None})
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
live / connection-lostloadingoffline-cachedFailed
offline-cached / connection-restoredreconcilingreconcilingPassed
reconciling / snapshot-currentlivelivePassed
reconciling / snapshot-failedoffline-erroroffline-errorPassed
offline-error / retry-refreshreconcilingreconcilingPassed
reconciling / connection-lostoffline-cachedoffline-cachedPassed
offline-cached / open-cached-itemoffline-previewoffline-previewPassed
offline-preview / close-previewoffline-cachedoffline-cachedPassed
offline-preview / connection-restoredreconciling-previewreconciling-previewPassed
reconciling-preview / snapshot-currentlive-previewlive-previewPassed
older notification incarnationlivelivePassed
future notification incarnationlivelivePassed
unknown event is inertlivelivePassed
empty delivery batchlivelivePassed
N stale deliveries before current deliveryloadingoffline-cachedFailed
trace connection-lost then connection-restoredloadingreconcilingFailed
trace connection-lost then open-cached-itemloadingoffline-previewFailed
trace connection-restored then snapshot-currentlivelivePassed
trace connection-restored then snapshot-failedoffline-erroroffline-errorPassed
trace connection-restored then connection-lostoffline-cachedoffline-cachedPassed
trace snapshot-current then connection-lostloadingoffline-cachedFailed
trace snapshot-failed then retry-refreshreconcilingreconcilingPassed
trace retry-refresh then snapshot-currentlivelivePassed
trace retry-refresh then snapshot-failedoffline-erroroffline-errorPassed
trace retry-refresh then connection-lostoffline-cachedoffline-cachedPassed
trace connection-lost then connection-restoredreconcilingreconcilingPassed
trace connection-lost then open-cached-itemoffline-previewoffline-previewPassed
trace open-cached-item then close-previewoffline-cachedoffline-cachedPassed
trace open-cached-item then connection-restoredreconciling-previewreconciling-previewPassed
trace close-preview then connection-restoredreconcilingreconcilingPassed
trace close-preview then open-cached-itemoffline-previewoffline-previewPassed
trace connection-restored then snapshot-currentlive-previewlive-previewPassed
domain state regression 1: cached{'phase': 'reconciling', 'value': ['old']}{'phase': 'reconciling', 'value': ['old']}Passed
domain state regression 2: cached{'phase': 'live', 'value': ['new']}{'phase': 'live', 'value': ['new']}Passed
domain state regression 3: cached{'phase': 'loading', 'value': ['old']}{'phase': 'offline-cached', 'value': ['old']}Failed
domain state regression 4: preview{'phase': 'live-preview', 'value': None}{'phase': 'live-preview', 'value': None}Passed
domain state regression 5: preview{'phase': 'live-preview', 'value': 'old'}{'phase': 'live-preview', 'value': 'old'}Passed
domain state regression 6: fresh{'phase': 'offline-error', 'value': False}{'phase': 'offline-error', 'value': False}Passed
domain state regression 7: preview{'phase': 'live-preview', 'value': None}{'phase': 'live-preview', 'value': None}Passed

SHA-256 / ce831e97a88d6340ad3d9ce2ed879a439a67f7035b40d0262bfa9d93a0b4ce94

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(initial, events, generation, payload=None, observe=None):
    table = {('live', 'connection-lost'): 'offline-cached', ('offline-cached', 'connection-restored'): 'reconciling', ('reconciling', 'snapshot-current'): 'live', ('reconciling', 'snapshot-failed'): 'offline-error', ('offline-error', 'retry-refresh'): 'reconciling', ('reconciling', 'connection-lost'): 'offline-cached', ('offline-cached', 'open-cached-item'): 'offline-preview', ('offline-preview', 'close-preview'): 'offline-cached', ('offline-preview', 'connection-restored'): 'reconciling-preview', ('reconciling-preview', 'snapshot-current'): 'live-preview'}
    data = json.loads(json.dumps({'cached': ['old'], 'cursor': 8, 'preview': 'old', 'fresh': False})) if payload is None else {**json.loads(json.dumps({'cached': ['old'], 'cursor': 8, 'preview': 'old', 'fresh': 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 == 'snapshot-current':
                if arg.get('cursor',data['cursor']) < data['cursor']: event = 'unknown-event'
                else:
                    data['cursor'] = arg.get('cursor',data['cursor'])
                    data['cached'] = arg.get('items',data['cached'])[:]
            if event == 'connection-lost': data['fresh'] = False
            state = table.get((state, event), state)
            if state in ('live','live-preview'): data['fresh'] = True
            if state == 'live-preview' and data['preview'] not in data['cached']: data['preview'] = None
            if state == 'empty': data['cached'] = []
    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('live / connection-lost', solve('live', [('connection-lost', N)], N), 'offline-cached')
check('offline-cached / connection-restored', solve('offline-cached', [('connection-restored', N)], N), 'reconciling')
check('reconciling / snapshot-current', solve('reconciling', [('snapshot-current', N)], N), 'live')
check('reconciling / snapshot-failed', solve('reconciling', [('snapshot-failed', N)], N), 'offline-error')
check('offline-error / retry-refresh', solve('offline-error', [('retry-refresh', N)], N), 'reconciling')
check('reconciling / connection-lost', solve('reconciling', [('connection-lost', N)], N), 'offline-cached')
check('offline-cached / open-cached-item', solve('offline-cached', [('open-cached-item', N)], N), 'offline-preview')
check('offline-preview / close-preview', solve('offline-preview', [('close-preview', N)], N), 'offline-cached')
check('offline-preview / connection-restored', solve('offline-preview', [('connection-restored', N)], N), 'reconciling-preview')
check('reconciling-preview / snapshot-current', solve('reconciling-preview', [('snapshot-current', N)], N), 'live-preview')
check('older notification incarnation', solve('live', [('connection-lost', N - 1)], N), 'live')
check('future notification incarnation', solve('live', [('connection-lost', N + 1)], N), 'live')
check('unknown event is inert', solve('live', [('unknown-event', N)], N), 'live')
check('empty delivery batch', solve('live', [], N), 'live')
check('N stale deliveries before current delivery', solve('live', [('connection-lost', N - 1)] * N + [('connection-lost', N)], N), 'offline-cached')
check('trace connection-lost then connection-restored', solve('live', [('connection-lost', N), ('connection-restored', N)], N), 'reconciling')
check('trace connection-lost then open-cached-item', solve('live', [('connection-lost', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace connection-restored then snapshot-current', solve('offline-cached', [('connection-restored', N), ('snapshot-current', N)], N), 'live')
check('trace connection-restored then snapshot-failed', solve('offline-cached', [('connection-restored', N), ('snapshot-failed', N)], N), 'offline-error')
check('trace connection-restored then connection-lost', solve('offline-cached', [('connection-restored', N), ('connection-lost', N)], N), 'offline-cached')
check('trace snapshot-current then connection-lost', solve('reconciling', [('snapshot-current', N), ('connection-lost', N)], N), 'offline-cached')
check('trace snapshot-failed then retry-refresh', solve('reconciling', [('snapshot-failed', N), ('retry-refresh', N)], N), 'reconciling')
check('trace retry-refresh then snapshot-current', solve('offline-error', [('retry-refresh', N), ('snapshot-current', N)], N), 'live')
check('trace retry-refresh then snapshot-failed', solve('offline-error', [('retry-refresh', N), ('snapshot-failed', N)], N), 'offline-error')
check('trace retry-refresh then connection-lost', solve('offline-error', [('retry-refresh', N), ('connection-lost', N)], N), 'offline-cached')
check('trace connection-lost then connection-restored', solve('reconciling', [('connection-lost', N), ('connection-restored', N)], N), 'reconciling')
check('trace connection-lost then open-cached-item', solve('reconciling', [('connection-lost', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace open-cached-item then close-preview', solve('offline-cached', [('open-cached-item', N), ('close-preview', N)], N), 'offline-cached')
check('trace open-cached-item then connection-restored', solve('offline-cached', [('open-cached-item', N), ('connection-restored', N)], N), 'reconciling-preview')
check('trace close-preview then connection-restored', solve('offline-preview', [('close-preview', N), ('connection-restored', N)], N), 'reconciling')
check('trace close-preview then open-cached-item', solve('offline-preview', [('close-preview', N), ('open-cached-item', N)], N), 'offline-preview')
check('trace connection-restored then snapshot-current', solve('offline-preview', [('connection-restored', N), ('snapshot-current', N)], N), 'live-preview')
check('domain state regression 1: cached', solve('reconciling', [('snapshot-current', N, {'cursor': 7, 'items': ['stale']})], N, {}, 'cached'), {'phase': 'reconciling', 'value': ['old']})
check('domain state regression 2: cached', solve('reconciling', [('snapshot-current', N, {'cursor': 9, 'items': ['new']})], N, {}, 'cached'), {'phase': 'live', 'value': ['new']})
check('domain state regression 3: cached', solve('live', [('connection-lost', N, {})], N, {'fresh': True}, 'cached'), {'phase': 'offline-cached', 'value': ['old']})
check('domain state regression 4: preview', solve('reconciling-preview', [('snapshot-current', N, {'items': ['new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': None})
check('domain state regression 5: preview', solve('reconciling-preview', [('snapshot-current', N, {'items': ['old', 'new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': 'old'})
check('domain state regression 6: fresh', solve('reconciling', [('snapshot-failed', N, {})], N, {}, 'fresh'), {'phase': 'offline-error', 'value': False})
check('domain state regression 7: preview', solve('offline-preview', [('connection-restored', N, {}), ('snapshot-current', N, {'cursor': 9, 'items': ['new']})], N, {}, 'preview'), {'phase': 'live-preview', 'value': None})
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
live / connection-lostoffline-cachedoffline-cachedPassed
offline-cached / connection-restoredreconcilingreconcilingPassed
reconciling / snapshot-currentlivelivePassed
reconciling / snapshot-failedoffline-erroroffline-errorPassed
offline-error / retry-refreshreconcilingreconcilingPassed
reconciling / connection-lostoffline-cachedoffline-cachedPassed
offline-cached / open-cached-itemoffline-previewoffline-previewPassed
offline-preview / close-previewoffline-cachedoffline-cachedPassed
offline-preview / connection-restoredreconciling-previewreconciling-previewPassed
reconciling-preview / snapshot-currentlive-previewlive-previewPassed
older notification incarnationlivelivePassed
future notification incarnationlivelivePassed
unknown event is inertlivelivePassed
empty delivery batchlivelivePassed
N stale deliveries before current deliveryoffline-cachedoffline-cachedPassed
trace connection-lost then connection-restoredreconcilingreconcilingPassed
trace connection-lost then open-cached-itemoffline-previewoffline-previewPassed
trace connection-restored then snapshot-currentlivelivePassed
trace connection-restored then snapshot-failedoffline-erroroffline-errorPassed
trace connection-restored then connection-lostoffline-cachedoffline-cachedPassed
trace snapshot-current then connection-lostoffline-cachedoffline-cachedPassed
trace snapshot-failed then retry-refreshreconcilingreconcilingPassed
trace retry-refresh then snapshot-currentlivelivePassed
trace retry-refresh then snapshot-failedoffline-erroroffline-errorPassed
trace retry-refresh then connection-lostoffline-cachedoffline-cachedPassed
trace connection-lost then connection-restoredreconcilingreconcilingPassed
trace connection-lost then open-cached-itemoffline-previewoffline-previewPassed
trace open-cached-item then close-previewoffline-cachedoffline-cachedPassed
trace open-cached-item then connection-restoredreconciling-previewreconciling-previewPassed
trace close-preview then connection-restoredreconcilingreconcilingPassed
trace close-preview then open-cached-itemoffline-previewoffline-previewPassed
trace connection-restored then snapshot-currentlive-previewlive-previewPassed
domain state regression 1: cached{'phase': 'reconciling', 'value': ['old']}{'phase': 'reconciling', 'value': ['old']}Passed
domain state regression 2: cached{'phase': 'live', 'value': ['new']}{'phase': 'live', 'value': ['new']}Passed
domain state regression 3: cached{'phase': 'offline-cached', 'value': ['old']}{'phase': 'offline-cached', 'value': ['old']}Passed
domain state regression 4: preview{'phase': 'live-preview', 'value': None}{'phase': 'live-preview', 'value': None}Passed
domain state regression 5: preview{'phase': 'live-preview', 'value': 'old'}{'phase': 'live-preview', 'value': 'old'}Passed
domain state regression 6: fresh{'phase': 'offline-error', 'value': False}{'phase': 'offline-error', 'value': False}Passed
domain state regression 7: preview{'phase': 'live-preview', 'value': None}{'phase': 'live-preview', 'value': None}Passed

SHA-256 / 86b2728771ed321c6746eacd6bfa2233835858f9a54f2677399812c4b5a22e21

Verification & scope

Stipulated single-notification state and policy model only. Event delivery and acknowledgements are explicit test inputs. No DOM, accessibility announcements, live timers, networking, actual rendering, or production-platform conformance is simulated. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:42:29.487389+00:00.

Case digest / 3ef58047a41cf5524076fabdb3b79a3856af7ddd1115458a58fb3793f3b6db09