FAILURE MAP
← Case archive

FA-34041 / Notification interfaces / Open access

Notification snooze presentation: open-snooze from visible · case 01

The open-snooze event leaves a notification in hidden instead of choosing.

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

ROOT CAUSE

Opening the duration chooser hides the notification immediately.

THE FAILURE

Opening the duration chooser hides the notification immediately.

Unsuccessful approach: Declaring it scheduled before choosing a time fabricates a reminder.

Case contract

Notification snooze presentation is a bounded visual-notification workflow with mutable policy state {'now': 10, 'wake': 30, 'scheduled': False, 'resurfaced': 0}. Its default transition relation is {('visible', 'open-snooze'): 'choosing', ('choosing', 'cancel-chooser'): 'visible', ('choosing', 'confirm-future'): 'scheduling', ('scheduling', 'persisted'): 'scheduled', ('scheduling', 'persist-failed'): 'snooze-error', ('scheduled', 'wake-time'): 'resurfaced', ('scheduled', 'cancel-snooze'): 'cancel-pending', ('cancel-pending', 'cancel-accepted'): 'visible', ('resurfaced', 'wake-replay'): 'resurfaced', ('snooze-error', 'choose-again'): 'choosing'}; 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 = {('visible', 'open-snooze'): 'hidden', ('choosing', 'cancel-chooser'): 'visible', ('choosing', 'confirm-future'): 'scheduling', ('scheduling', 'persisted'): 'scheduled', ('scheduling', 'persist-failed'): 'snooze-error', ('scheduled', 'wake-time'): 'resurfaced', ('scheduled', 'cancel-snooze'): 'cancel-pending', ('cancel-pending', 'cancel-accepted'): 'visible', ('resurfaced', 'wake-replay'): 'resurfaced', ('snooze-error', 'choose-again'): 'choosing'}
    data = json.loads(json.dumps({'now': 10, 'wake': 30, 'scheduled': False, 'resurfaced': 0})) if payload is None else {**json.loads(json.dumps({'now': 10, 'wake': 30, 'scheduled': False, 'resurfaced': 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
            data['now'] = max(data['now'], arg.get('now',data['now']))
            if event == 'confirm-future':
                wake = arg.get('wake',data['wake'])
                if wake <= data['now']: event = 'unknown-event'
                else: data['wake'] = wake
            if event == 'wake-time' and data['now'] < data['wake'] and 'now' in arg: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'scheduled': data['scheduled'] = True
            if state in ('visible','resurfaced'): data['scheduled'] = False
            if state == 'resurfaced' and previous != 'resurfaced': data['resurfaced'] += 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('visible / open-snooze', solve('visible', [('open-snooze', N)], N), 'choosing')
check('choosing / cancel-chooser', solve('choosing', [('cancel-chooser', N)], N), 'visible')
check('choosing / confirm-future', solve('choosing', [('confirm-future', N)], N), 'scheduling')
check('scheduling / persisted', solve('scheduling', [('persisted', N)], N), 'scheduled')
check('scheduling / persist-failed', solve('scheduling', [('persist-failed', N)], N), 'snooze-error')
check('scheduled / wake-time', solve('scheduled', [('wake-time', N)], N), 'resurfaced')
check('scheduled / cancel-snooze', solve('scheduled', [('cancel-snooze', N)], N), 'cancel-pending')
check('cancel-pending / cancel-accepted', solve('cancel-pending', [('cancel-accepted', N)], N), 'visible')
check('resurfaced / wake-replay', solve('resurfaced', [('wake-replay', N)], N), 'resurfaced')
check('snooze-error / choose-again', solve('snooze-error', [('choose-again', N)], N), 'choosing')
check('older notification incarnation', solve('visible', [('open-snooze', N - 1)], N), 'visible')
check('future notification incarnation', solve('visible', [('open-snooze', N + 1)], N), 'visible')
check('unknown event is inert', solve('visible', [('unknown-event', N)], N), 'visible')
check('empty delivery batch', solve('visible', [], N), 'visible')
check('N stale deliveries before current delivery', solve('visible', [('open-snooze', N - 1)] * N + [('open-snooze', N)], N), 'choosing')
check('trace open-snooze then cancel-chooser', solve('visible', [('open-snooze', N), ('cancel-chooser', N)], N), 'visible')
check('trace open-snooze then confirm-future', solve('visible', [('open-snooze', N), ('confirm-future', N)], N), 'scheduling')
check('trace cancel-chooser then open-snooze', solve('choosing', [('cancel-chooser', N), ('open-snooze', N)], N), 'choosing')
check('trace confirm-future then persisted', solve('choosing', [('confirm-future', N), ('persisted', N)], N), 'scheduled')
check('trace confirm-future then persist-failed', solve('choosing', [('confirm-future', N), ('persist-failed', N)], N), 'snooze-error')
check('trace persisted then wake-time', solve('scheduling', [('persisted', N), ('wake-time', N)], N), 'resurfaced')
check('trace persisted then cancel-snooze', solve('scheduling', [('persisted', N), ('cancel-snooze', N)], N), 'cancel-pending')
check('trace persist-failed then choose-again', solve('scheduling', [('persist-failed', N), ('choose-again', N)], N), 'choosing')
check('trace wake-time then wake-replay', solve('scheduled', [('wake-time', N), ('wake-replay', N)], N), 'resurfaced')
check('trace cancel-snooze then cancel-accepted', solve('scheduled', [('cancel-snooze', N), ('cancel-accepted', N)], N), 'visible')
check('trace cancel-accepted then open-snooze', solve('cancel-pending', [('cancel-accepted', N), ('open-snooze', N)], N), 'choosing')
check('trace wake-replay then wake-replay', solve('resurfaced', [('wake-replay', N), ('wake-replay', N)], N), 'resurfaced')
check('trace choose-again then cancel-chooser', solve('snooze-error', [('choose-again', N), ('cancel-chooser', N)], N), 'visible')
check('trace choose-again then confirm-future', solve('snooze-error', [('choose-again', N), ('confirm-future', N)], N), 'scheduling')
check('domain state regression 1: wake', solve('choosing', [('confirm-future', N, {'wake': 10})], N, {}, 'wake'), {'phase': 'choosing', 'value': 30})
check('domain state regression 2: wake', solve('choosing', [('confirm-future', N, {'wake': 50})], N, {}, 'wake'), {'phase': 'scheduling', 'value': 50})
check('domain state regression 3: scheduled', solve('scheduled', [('wake-time', N, {'now': 29})], N, {'scheduled': True}, 'scheduled'), {'phase': 'scheduled', 'value': True})
check('domain state regression 4: resurfaced', solve('scheduled', [('wake-time', N, {'now': 30})], N, {'scheduled': True}, 'resurfaced'), {'phase': 'resurfaced', 'value': 1})
check('domain state regression 5: resurfaced', solve('resurfaced', [('wake-replay', N, {})], N, {'resurfaced': 1}, 'resurfaced'), {'phase': 'resurfaced', 'value': 1})
check('domain state regression 6: scheduled', solve('cancel-pending', [('cancel-accepted', N, {})], N, {'scheduled': True}, 'scheduled'), {'phase': 'visible', 'value': False})
check('domain state regression 7: resurfaced', solve('choosing', [('confirm-future', N, {'wake': 40}), ('persisted', N, {}), ('wake-time', N, {'now': 39}), ('wake-time', N, {'now': 40}), ('wake-replay', N, {})], N, {}, 'resurfaced'), {'phase': 'resurfaced', 'value': 1})
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
visible / open-snoozehiddenchoosingFailed
choosing / cancel-chooservisiblevisiblePassed
choosing / confirm-futureschedulingschedulingPassed
scheduling / persistedscheduledscheduledPassed
scheduling / persist-failedsnooze-errorsnooze-errorPassed
scheduled / wake-timeresurfacedresurfacedPassed
scheduled / cancel-snoozecancel-pendingcancel-pendingPassed
cancel-pending / cancel-acceptedvisiblevisiblePassed
resurfaced / wake-replayresurfacedresurfacedPassed
snooze-error / choose-againchoosingchoosingPassed
older notification incarnationvisiblevisiblePassed
future notification incarnationvisiblevisiblePassed
unknown event is inertvisiblevisiblePassed
empty delivery batchvisiblevisiblePassed
N stale deliveries before current deliveryhiddenchoosingFailed
trace open-snooze then cancel-chooserhiddenvisibleFailed
trace open-snooze then confirm-futurehiddenschedulingFailed
trace cancel-chooser then open-snoozehiddenchoosingFailed
trace confirm-future then persistedscheduledscheduledPassed
trace confirm-future then persist-failedsnooze-errorsnooze-errorPassed
trace persisted then wake-timeresurfacedresurfacedPassed
trace persisted then cancel-snoozecancel-pendingcancel-pendingPassed
trace persist-failed then choose-againchoosingchoosingPassed
trace wake-time then wake-replayresurfacedresurfacedPassed
trace cancel-snooze then cancel-acceptedvisiblevisiblePassed
trace cancel-accepted then open-snoozehiddenchoosingFailed
trace wake-replay then wake-replayresurfacedresurfacedPassed
trace choose-again then cancel-chooservisiblevisiblePassed
trace choose-again then confirm-futureschedulingschedulingPassed
domain state regression 1: wake{'phase': 'choosing', 'value': 30}{'phase': 'choosing', 'value': 30}Passed
domain state regression 2: wake{'phase': 'scheduling', 'value': 50}{'phase': 'scheduling', 'value': 50}Passed
domain state regression 3: scheduled{'phase': 'scheduled', 'value': True}{'phase': 'scheduled', 'value': True}Passed
domain state regression 4: resurfaced{'phase': 'resurfaced', 'value': 1}{'phase': 'resurfaced', 'value': 1}Passed
domain state regression 5: resurfaced{'phase': 'resurfaced', 'value': 1}{'phase': 'resurfaced', 'value': 1}Passed
domain state regression 6: scheduled{'phase': 'visible', 'value': False}{'phase': 'visible', 'value': False}Passed
domain state regression 7: resurfaced{'phase': 'resurfaced', 'value': 1}{'phase': 'resurfaced', 'value': 1}Passed

SHA-256 / 8d9b9dbbc1938e300d6f4ed20fcf99ede4ddea5c57b4632330761c13ea119dbf

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 = {('visible', 'open-snooze'): 'scheduled', ('choosing', 'cancel-chooser'): 'visible', ('choosing', 'confirm-future'): 'scheduling', ('scheduling', 'persisted'): 'scheduled', ('scheduling', 'persist-failed'): 'snooze-error', ('scheduled', 'wake-time'): 'resurfaced', ('scheduled', 'cancel-snooze'): 'cancel-pending', ('cancel-pending', 'cancel-accepted'): 'visible', ('resurfaced', 'wake-replay'): 'resurfaced', ('snooze-error', 'choose-again'): 'choosing'}
    data = json.loads(json.dumps({'now': 10, 'wake': 30, 'scheduled': False, 'resurfaced': 0})) if payload is None else {**json.loads(json.dumps({'now': 10, 'wake': 30, 'scheduled': False, 'resurfaced': 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
            data['now'] = max(data['now'], arg.get('now',data['now']))
            if event == 'confirm-future':
                wake = arg.get('wake',data['wake'])
                if wake <= data['now']: event = 'unknown-event'
                else: data['wake'] = wake
            if event == 'wake-time' and data['now'] < data['wake'] and 'now' in arg: event = 'unknown-event'
            state = table.get((state, event), state)
            if state == 'scheduled': data['scheduled'] = True
            if state in ('visible','resurfaced'): data['scheduled'] = False
            if state == 'resurfaced' and previous != 'resurfaced': data['resurfaced'] += 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('visible / open-snooze', solve('visible', [('open-snooze', N)], N), 'choosing')
check('choosing / cancel-chooser', solve('choosing', [('cancel-chooser', N)], N), 'visible')
check('choosing / confirm-future', solve('choosing', [('confirm-future', N)], N), 'scheduling')
check('scheduling / persisted', solve('scheduling', [('persisted', N)], N), 'scheduled')
check('scheduling / persist-failed', solve('scheduling', [('persist-failed', N)], N), 'snooze-error')
check('scheduled / wake-time', solve('scheduled', [('wake-time', N)], N), 'resurfaced')
check('scheduled / cancel-snooze', solve('scheduled', [('cancel-snooze', N)], N), 'cancel-pending')
check('cancel-pending / cancel-accepted', solve('cancel-pending', [('cancel-accepted', N)], N), 'visible')
check('resurfaced / wake-replay', solve('resurfaced', [('wake-replay', N)], N), 'resurfaced')
check('snooze-error / choose-again', solve('snooze-error', [('choose-again', N)], N), 'choosing')
check('older notification incarnation', solve('visible', [('open-snooze', N - 1)], N), 'visible')
check('future notification incarnation', solve('visible', [('open-snooze', N + 1)], N), 'visible')
check('unknown event is inert', solve('visible', [('unknown-event', N)], N), 'visible')
check('empty delivery batch', solve('visible', [], N), 'visible')
check('N stale deliveries before current delivery', solve('visible', [('open-snooze', N - 1)] * N + [('open-snooze', N)], N), 'choosing')
check('trace open-snooze then cancel-chooser', solve('visible', [('open-snooze', N), ('cancel-chooser', N)], N), 'visible')
check('trace open-snooze then confirm-future', solve('visible', [('open-snooze', N), ('confirm-future', N)], N), 'scheduling')
check('trace cancel-chooser then open-snooze', solve('choosing', [('cancel-chooser', N), ('open-snooze', N)], N), 'choosing')
check('trace confirm-future then persisted', solve('choosing', [('confirm-future', N), ('persisted', N)], N), 'scheduled')
check('trace confirm-future then persist-failed', solve('choosing', [('confirm-future', N), ('persist-failed', N)], N), 'snooze-error')
check('trace persisted then wake-time', solve('scheduling', [('persisted', N), ('wake-time', N)], N), 'resurfaced')
check('trace persisted then cancel-snooze', solve('scheduling', [('persisted', N), ('cancel-snooze', N)], N), 'cancel-pending')
check('trace persist-failed then choose-again', solve('scheduling', [('persist-failed', N), ('choose-again', N)], N), 'choosing')
check('trace wake-time then wake-replay', solve('scheduled', [('wake-time', N), ('wake-replay', N)], N), 'resurfaced')
check('trace cancel-snooze then cancel-accepted', solve('scheduled', [('cancel-snooze', N), ('cancel-accepted', N)], N), 'visible')
check('trace cancel-accepted then open-snooze', solve('cancel-pending', [('cancel-accepted', N), ('open-snooze', N)], N), 'choosing')
check('trace wake-replay then wake-replay', solve('resurfaced', [('wake-replay', N), ('wake-replay', N)], N), 'resurfaced')
check('trace choose-again then cancel-chooser', solve('snooze-error', [('choose-again', N), ('cancel-chooser', N)], N), 'visible')
check('trace choose-again then confirm-future', solve('snooze-error', [('choose-again', N), ('confirm-future', N)], N), 'scheduling')
check('domain state regression 1: wake', solve('choosing', [('confirm-future', N, {'wake': 10})], N, {}, 'wake'), {'phase': 'choosing', 'value': 30})
check('domain state regression 2: wake', solve('choosing', [('confirm-future', N, {'wake': 50})], N, {}, 'wake'), {'phase': 'scheduling', 'value': 50})
check('domain state regression 3: scheduled', solve('scheduled', [('wake-time', N, {'now': 29})], N, {'scheduled': True}, 'scheduled'), {'phase': 'scheduled', 'value': True})
check('domain state regression 4: resurfaced', solve('scheduled', [('wake-time', N, {'now': 30})], N, {'scheduled': True}, 'resurfaced'), {'phase': 'resurfaced', 'value': 1})
check('domain state regression 5: resurfaced', solve('resurfaced', [('wake-replay', N, {})], N, {'resurfaced': 1}, 'resurfaced'), {'phase': 'resurfaced', 'value': 1})
check('domain state regression 6: scheduled', solve('cancel-pending', [('cancel-accepted', N, {})], N, {'scheduled': True}, 'scheduled'), {'phase': 'visible', 'value': False})
check('domain state regression 7: resurfaced', solve('choosing', [('confirm-future', N, {'wake': 40}), ('persisted', N, {}), ('wake-time', N, {'now': 39}), ('wake-time', N, {'now': 40}), ('wake-replay', N, {})], N, {}, 'resurfaced'), {'phase': 'resurfaced', 'value': 1})
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
visible / open-snoozescheduledchoosingFailed
choosing / cancel-chooservisiblevisiblePassed
choosing / confirm-futureschedulingschedulingPassed
scheduling / persistedscheduledscheduledPassed
scheduling / persist-failedsnooze-errorsnooze-errorPassed
scheduled / wake-timeresurfacedresurfacedPassed
scheduled / cancel-snoozecancel-pendingcancel-pendingPassed
cancel-pending / cancel-acceptedvisiblevisiblePassed
resurfaced / wake-replayresurfacedresurfacedPassed
snooze-error / choose-againchoosingchoosingPassed
older notification incarnationvisiblevisiblePassed
future notification incarnationvisiblevisiblePassed
unknown event is inertvisiblevisiblePassed
empty delivery batchvisiblevisiblePassed
N stale deliveries before current deliveryscheduledchoosingFailed
trace open-snooze then cancel-chooserscheduledvisibleFailed
trace open-snooze then confirm-futurescheduledschedulingFailed
trace cancel-chooser then open-snoozescheduledchoosingFailed
trace confirm-future then persistedscheduledscheduledPassed
trace confirm-future then persist-failedsnooze-errorsnooze-errorPassed
trace persisted then wake-timeresurfacedresurfacedPassed
trace persisted then cancel-snoozecancel-pendingcancel-pendingPassed
trace persist-failed then choose-againchoosingchoosingPassed
trace wake-time then wake-replayresurfacedresurfacedPassed
trace cancel-snooze then cancel-acceptedvisiblevisiblePassed
trace cancel-accepted then open-snoozescheduledchoosingFailed
trace wake-replay then wake-replayresurfacedresurfacedPassed
trace choose-again then cancel-chooservisiblevisiblePassed
trace choose-again then confirm-futureschedulingschedulingPassed
domain state regression 1: wake{'phase': 'choosing', 'value': 30}{'phase': 'choosing', 'value': 30}Passed
domain state regression 2: wake{'phase': 'scheduling', 'value': 50}{'phase': 'scheduling', 'value': 50}Passed
domain state regression 3: scheduled{'phase': 'scheduled', 'value': True}{'phase': 'scheduled', 'value': True}Passed
domain state regression 4: resurfaced{'phase': 'resurfaced', 'value': 1}{'phase': 'resurfaced', 'value': 1}Passed
domain state regression 5: resurfaced{'phase': 'resurfaced', 'value': 1}{'phase': 'resurfaced', 'value': 1}Passed
domain state regression 6: scheduled{'phase': 'visible', 'value': False}{'phase': 'visible', 'value': False}Passed
domain state regression 7: resurfaced{'phase': 'resurfaced', 'value': 1}{'phase': 'resurfaced', 'value': 1}Passed

SHA-256 / bde1d22ce4defdb151e6b701282f1573af37cd59d1f3e25052197587f35fdd08

HELD IN THE MEMBER ARCHIVE

The verified repair and its recorded checks are member-only.

This mechanism has 36 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.

Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.

Member access is invitation-based. Sign in with your invited account to inspect the repair.

Sign in to the archive ↗

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:28.493093+00:00.

Case digest / b17e14082e37775a2ad2b72b4510d1a559de03cf69c19745ec2c5630308a9ebc