# Proof audit pass 1 — Custom snooze time format

Issue: [#19930](https://git.cafe/pingdotgg/t3code/issues/19930).
Read-only audited checkout: `/home/ubuntu/wt/issue-19930`, branch `fix/issue-19930`.
Pinned comparison: [3b95e7831b](https://git.cafe/pingdotgg/t3code/commit/3b95e7831b) → [7267dd9f02](https://git.cafe/pingdotgg/t3code/commit/7267dd9f02).
HEAD was `7267dd9f026fbe78d74dd94f9247658a054f6b96` at initial inspection and final source inspection. A later implementation change invalidates this pass until its diff is reviewed.

Status: proposed proof matrix derived from the entire diff and callers; **no runtime verification, screenshots, recordings, database writes, browser/server use, or checkout edits performed**. No PR exists for this task. Artifact upload is the only external write authorized here.

## Scope and equivalence

The entire diff is one file, `apps/web/src/components/CustomSnoozeDialog.tsx` (+94/−18): native time input replaced by Hour/Minute and optional AM/PM selects; Date/Time becomes a single-column layout at every width; the new component reads `timestampFormat` through `usePrimarySettings` and existing `resolveHour12`.

There are exactly **two new rendered time branches**: two columns for 24-hour; three columns for 12-hour. Explicit format and System default resolving to that format share rendering. Minutes, dialog shell, calendar, error paragraph, footer, and duration mode are shared. Numeric endpoint values do not create new layouts. Do not cross-product callers, every hour, every minute, both source settings, or provider types into extra captures.

Every affected row below must be demonstrated at all four rendering configurations: **1440×900 light, 1440×900 dark, 390×844 light, 390×844 dark**, CSS pixels, 100% zoom, DPR 1. Width 390 is the responsive **web** client, not native mobile. Use the same default font/theme palette across the comparison; name the exact light/dark theme halves in the manifest. Preserve realistic app chrome and dialog padding. Do not crop off dropdown edges, focus rings, errors, or footer.

## Affected fixture matrix

`4/4` means all four width/theme combinations above. Every row requires recording because interaction, focus, format switching, or submitted time is part of its proof. Stills alone cannot satisfy any row. Closed/open checkpoints can be extracted from those recordings without creating additional cases.

| ID | Affected state / branch | Deterministic fixture and action | Required observation | Rendering | Proof / grouping |
| --- | --- | --- | --- | --- | --- |
| R1 | 24-hour closed state; settings resolver; stacked layout | Frozen now 2030-01-15 16:30 UTC; open default +1h with explicit `24-hour` under en-US (12h system). Also open `locale` under a fresh en-GB context (24h system). Record persisted setting and independently resolved runtime locale/hour12 before opening. | Initial time is Hour `17`, Minute `30`, **no period select**, with Date above Time. Forced setting overrides mismatching locale. System default takes the same 24h branch. Compare against baseline ignoring the explicit setting under en-US. | 4/4 | Recording; 24h walkthrough, resolver companion segment. |
| R2 | 12-hour closed state; settings resolver; three-column layout | Same clock; explicit `12-hour` under en-GB (24h system), then `locale` under fresh en-US (12h system). Switch explicit formats across reopen and preserve the same underlying intended target. | Initial time is Hour `05`, Minute `30`, Period `PM`; three controls fit at 390 without clipping. System default takes the same 12h branch. Existing design zero-pads `05`; the issue's example `5:30 PM` does not require removing padding. | 4/4 | Recording; 12h walkthrough, resolver companion segment. |
| R3 | 24-hour Hour popup and keyboard | Set tomorrow first; open Hour by pointer and keyboard; show first `00` and last `23`, choose with Arrow keys and Enter; open with Space, Escape without committing, then Tab onward. | All 24 options reachable; selection and focus visible; `00` and `23` retained; minute unchanged. Popup fits viewport/scrolls; opening or selecting does not submit the form. Escape closes only the open popup and restores trigger focus. | 4/4 | Recording; 24h walkthrough. Baseline records its native picker counterpart; do not expect custom select DOM on base. |
| R4 | 12-hour Hour and AM/PM popups and keyboard | Open Hour and show `12, 01 … 11`; select `12`/`11` with keyboard. Open period, select AM/PM by pointer and keyboard; Escape a pending choice; Tab through Hour → Minute → AM or PM. | All 12 hour options and both period options reachable. Choosing hour preserves period and minute; changing period preserves the hour modulo 12 and minute. Trigger names are Hour, Minute, AM or PM under Time group; focus and values remain visible. No accidental submit. | 4/4 | Recording; 12h walkthrough. |
| R5 | Shared Minute popup; min/max minute | Open Minute in one representative format per configuration; show `00` and `59` via scrolling/keyboard, commit both; cancel another pending choice. Exercise it once in the other format within that walkthrough, without duplicating the entire endpoint sequence. | All 60 options reachable, including offscreen endpoints; no five-minute restriction. `00`/`59` retained and zero-padded. Hour/period unchanged; keyboard focus returns correctly; popup remains usable at narrow width. | 4/4 | Recording; shared path, embedded in format walkthroughs. |
| R6 | Noon/midnight conversion and confirmation | On 2030-01-16 select 12:00 AM, 12:00 PM, 11:59 AM, 11:59 PM; exercise both hour-choice and period-choice routes to 12. Include 24h `00:00`, `12:00`, `23:59`. Confirm each boundary target with fresh/reset synthetic thread state; correlate recorded choice with command receipt/persisted projection in transcript. | UTC fixture yields respectively `2030-01-16T00:00:00.000Z`, `12:00:00.000Z`, `11:59:00.000Z`, `23:59:00.000Z`. Midnight stays on selected date. Visible value alone is insufficient: prove submitted ISO target, with date prefix retained for every transcript line. 24h equivalents agree. | 4/4 | Recording **plus payload/projection transcript**; both format walkthroughs; endpoints reuse R3–R5 actions. |
| R7 | Changed Date anchor/layout; Date ↔ Duration remount | Open calendar from full-width Date; choose Jan 16 and close. Set 17:59 (05:59 PM); switch to Duration, set 45 minutes; return to Date and time; switch back to Duration and submit. | Calendar opens within viewport and selecting closes it. Returning preserves date/time including minute/period; duration retains amount/unit. Successful duration is confirmation-now +45m (frozen clock: `2030-01-15T17:15:00.000Z`). Re-entering Date mounts settings-aware controls correctly. | 4/4 | Recording; shared transition path embedded in each format walkthrough. Duration layout itself is unchanged, but the transition and new Date layout are affected. |
| R8 | New controls clear validation; nested cancel and reopen | On Jan 15 choose 16:29 (past). Submit to show date error. Change Hour, Minute, and (12h) AM/PM separately, reintroducing error between changes; change date to future and confirm. Separately cancel by Cancel button, Escape with popup closed, and backdrop/close gesture supported by existing dialog; with popup open, Escape once must close popup first. Reopen after cancelling edits. | Error text `Choose a valid date and time in the future.` is visible and each changed control clears it. Invalid target does not resolve/mutate; valid target resolves once. Cancel paths return null with no snooze command, and reopening uses fresh +1h default, not cancelled edits. Preserve caller focus. | 4/4 | Recording plus command/no-command transcript; shared shell path, both format walkthroughs only where controls differ. |

**Count:** 8 affected rows × 4 render configurations = **32 required row/configuration checks**, consolidated into **8 before/after walkthrough pairs (16 final video assets)**: 24h and 12h branches × four configurations × base/head. Each clip covers several rows; this is not 32 screenshots or 64 per-row videos. Matching System default and explicit-format paths are labelled segments within the corresponding branch asset, not extra standalone captures. Use labelled concatenation if different fresh locale contexts require separate raw recordings; retain source clips and timestamps in the manifest. There may be more raw clips than the 16 final assets. No additional still assets are required; labelled before/after poster frames may be extracted for presentation.

The 24h walkthrough covers R1/R3/R5/R6/R7/R8; the 12h walkthrough covers R2/R4/R5/R6/R7/R8. Shared rows R5/R7/R8 need the full behavioral sequence in one branch per rendering configuration; the second branch only needs its distinct control/mount behavior. R6 covers both representations. Baseline clips establish native control behavior and former side-by-side desktop layout; custom-select-specific expectations are marked N/A on base, never silently reported as passing. Record base in the same browser/environment as head; record observed locale behavior rather than forcing a claimed failure if this browser does not reproduce it.

## Caller / surface ledger (no matrix multiplication)

| Entry point / surface | Source and scope decision | Required evidence later |
| --- | --- | --- |
| Sidebar row snooze button → Custom… | `SidebarThreadRow.tsx` `SnoozeMenuButton` calls `requestCustomSnooze`; same singleton host. | Use as canonical opening route if available; otherwise use sidebar context route. One route-to-dialog segment, not all eight rows again. |
| Sidebar row context menu → Snooze → Custom… | `Sidebar.tsx` `handleThreadContextMenu`; identical request and dialog; applies result through `attemptSnooze`. | One reachability/cancel check; no extra width/theme cross-product. |
| Bulk selected-thread context menu → Snooze (2) → Custom… | `Sidebar.tsx` `handleMultiSelectContextMenu`; same dialog, one choice applied to all selected threads. | Seed two eligible stopped threads; one reachability/cancel and one same-target application check. Record target IDs and identical resulting snoozedUntil. No duplicated dialog visual matrix. |
| Thread header actions → Snooze → Custom… | `ChatHeader.tsx` uses `useThreadActionMenu.ts`; identical dialog and `snoozeThread` path. | One reachability/cancel check; can share a 1440-light walkthrough segment. |
| Settings / command palette / keybinding | Settings supplies `timestampFormat`; complete source search found no additional `requestCustomSnooze` caller in palette/keybinding/settings. | Show format-setting provenance. No invented direct dialog entrypoint to test. |
| Desktop Electron | Same web component and root host; resolver can read `desktopBridge.getSystemLocale()` at module initialization. Issue explicitly includes desktop. | **CANNOT VERIFY DESKTOP** here: Electron unavailable on Linux in this task. Web widths do not prove Electron locale bridging, native context menus, focus, or IPC. Carry this limitation into final proof; later Electron pass should exercise explicit overrides plus both resolved System defaults. |
| Native mobile iOS / Android | Separate unchanged `CustomSnoozeSheet*` components and `customSnoozeDate`; no diff. | Unaffected; no native screenshots, simulator, or mobile redesign requested. |
| Hosted web, local web, remote/relay/tunnel | Same web host/control; time remains client-local and output ISO; no transport/contracts/server changes. `timestampFormat` is client-owned and merged by settings hook. | Canonical local real app is the required integrated capture. Locale/settings resolution must be evidenced; do not claim remote/tunnel runtime verification. No extra transport capture matrix for this component-only change. |
| Providers / agents / scheduler | No provider, service, MCP, scheduler, orchestration, or contract edits. Snooze control is provider-independent. | Unaffected; do not start provider turns or agents to create proof data. |

All caller checks can fit in the canonical 1440-light walkthroughs and the accompanying runtime transcript. They add no standalone capture assets. The unmodified menu differences are not additional CustomSnoozeDialog visual states.

## Unaffected or bounded regression cases

| Case | Decision and reason |
| --- | --- |
| Duration zero/negative/nonfinite/empty validation | Duration inputs, submit resolver and `Enter a positive duration.` error are unchanged. No independent four-configuration row. A zero-duration error → valid amount recovery can be included in R7 without another asset. |
| Invalid manually typed time / missing required native input | Native input is removed; new selects only emit valid enumerated HH:mm from valid initial state. This is a changed input mechanism, covered by R3–R6 and past-time validation R8. Do not fabricate impossible text values through a screenshot-only mock. |
| DST gap, leap date, rollover validation | `resolveCustomSnooze` and shared tests unchanged; new controls still feed local `HH:mm`. UTC fixture intentionally separates conversion proof from unchanged DST behavior. Existing resolver tests cover nonexistent local time; no extra DST visual row required for exact issue scope. |
| Unsnooze, queued turns, approvals, permissions, network failure toast, bulk partial failure | Gates/mutations/toasts unchanged; seed eligible stopped threads with operation grant. Cancel and emitted target checks cover integration at the changed boundary. No fault injection or unrelated orchestration work required. |
| Format changes while the dialog is mounted | The selector is reactive, but Settings normally requires closing the dialog. Capture format changes across reopen through actual Settings; a synthetic harness may additionally change real settings while mounted and prove target preservation. Not an additional visual branch or a reason to expose test controls in product UI. |

## Reproducible fixture / seed contract for the evidence agent

The evidence agent should later commit a minimal reusable **synthetic seeding/fixture implementation**, not this temporary audit note or PR-only images. No fixture implementation was written by this read-only audit. The proof remains incomplete until that implementation and runtime artifacts exist.

1. Use the lead-owned existing development server on port **5744**, session **91446**, and this worktree's isolated `.t3`. Coordinate all server lifecycle and state reset with the lead; do not launch a second server. Never write or point a server at `~/.t3/userdata`. No environment credentials, startup URLs, auth tokens, or customer content in a committed seed or uploaded manifest.
2. Make the seed idempotent and explicitly scoped to the isolated worktree home/origin. Use supported app/RPC orchestration commands with deterministic synthetic IDs/marker where accepted; look up and reuse by marker otherwise. Do not hand-edit event-sourced projection tables. Seed the existing default server project with two eligible stopped threads, e.g. `Proof 19930 — primary` and `Proof 19930 — bulk peer`; no messages/turns/provider process, queued work, approvals, or pending user/subagent requests. Keep the current empty `New thread` intact unless the lead approves its use. Grant normal thread-operation permission in the isolated session.
3. Provide reset/cleanup for **only** those synthetic fixtures: clear their snooze through supported commands between confirmations; restore settings changed for capture. Bulk needs two threads; current one empty stopped thread alone cannot demonstrate it. Save actual scoped thread IDs, project/environment IDs and reset commands in a local manifest; sanitize any published transcript.
4. Make clock control reproducible in the evidence workflow: fixed browser Date `2030-01-15T16:30:00.000Z`, timezone `UTC`, future date Jan 16. Freeze Date used by initialization and confirmation, not all animation/network timers. The real server need not be time-frozen for this future target. If using a different fixture clock, regenerate all expected ISO targets and include the exact clock in metadata. Do not use sleeps as state synchronization; wait for the actual dialog, command response or projection milestone.
5. Use **fresh browser contexts/pages before app module import** with en-US and en-GB runtime locales; record `Intl.DateTimeFormat(undefined, {hour:'numeric', minute:'2-digit'}).resolvedOptions()` locale, hourCycle/hour12 and timeZone in the transcript. Expected defaults: en-US → 12h; en-GB → 24h, but assert the runtime result rather than trusting the language name. `timestampLocale` and formatter caches are initialized/cached in the module, so changing navigator text or a preference after import does not prove System default.
6. Persist `timestampFormat` via actual Settings or existing client persistence commands (`12-hour`, `24-hour`, `locale`), await hydration, then open through a real caller. Do not seed this client-owned value into server settings or assume it comes from the SQLite seed. Show forced 24h against a 12h runtime and forced 12h against a 24h runtime, plus both System default resolutions. Use actual light/dark settings and confirm effective theme before each capture.
7. Render the production `CustomSnoozeDialogHost`, production selects/calendar/settings hooks and real app styles. A synthetic fixture may deterministically set up state and observe the choice/command boundary; it must not replace the picker or hard-code its visible values. At least one canonical flow must reach the dialog in the real app, not only an isolated component harness. Record any mocked boundary explicitly. Prove actual persisted snooze results for canonical single/bulk flows.
8. Commit the repeatable seed/fixture and runner/recipe where the project convention allows; record that commit and exact rerun command in the evidence manifest. Keep capture files outside the repository. Include base/head SHA, scenario IDs, viewport, DPR, zoom, theme, locale/hour12, timezone/clock, entrypoint, capture timestamps/segments, expected and observed targets, and artifact URLs. A mock image or uncommitted one-off seeding snippet is not the requested reproducible proof.

## Rendering / publication requirements

Use comparable before/after framing and label **Before — 3b95e7831b** and **After — 7267dd9f02** with format, dimensions, theme, and runtime locale. Videos must remain legible at normal playback, show pointer/keyboard focus, open popup scrolling, confirmation/cancel, and observable completion. Do not hide the native baseline popup merely because it differs from the custom one. If the native platform popup is omitted by the capture method, record that limitation and obtain an appropriate whole-window recording later; a DOM screenshot is not proof of its appearance.

Base capture must use the exact pinned source under lead control; never switch/reset this actively reviewed checkout or commandeer the running server. The lead/evidence agent must arrange the baseline environment. If unavailable, mark baseline missing, not simulated. If head changes, update the pinned comparison and re-derive affected branches before recording. Stills may illustrate layout, but they cannot replace R1–R8 recordings or target/no-command transcripts. Upload eventual evidence assets with ghdrop; do not publish to a forge or create a PR as part of this audit.

## FRICTION

- **Observed:** repository AGENTS.md read. Bounded search found no `t3code-ops/docs/EVIDENCE.md`: searched `/home` to depth 5, `/tmp` and `/opt` to depth 5, plus file lists under `/home/ubuntu/Development` and `/home/ubuntu/briefs`. No operations-repo evidence instructions were available to apply; did not clone/search indefinitely.
- **Provided by lead, not independently probed:** live-DB seed previously hit incompatible migrations; current isolated `.t3` contains the default server project and one stopped empty `New thread`. This pass did not access the DB or server. Use synthetic supported-command seeding; do not retry migrations against live data.
- **Required follow-up:** reproducible fixture/seed is not yet committed; bulk requires a second eligible stopped thread; clock and locale contexts need deterministic setup; payload/projection observation is needed because appearance cannot prove noon/midnight conversion.
- **Cannot verify:** Electron desktop in this Linux audit environment. Native mobile is unchanged, not a failed verification.
- **Ownership:** existing server 5744/session 91446 belongs to lead; no browser/server/capture use was authorized for this audit. Baseline capture setup also remains lead-owned.
- **Concurrency:** implementation reviews may change HEAD. This pass is pinned, not approval of a future commit; re-audit changed code before relying on the matrix.
- **Not a result claim:** all 32 checks and 16 planned video assets remain pending. This document is an evidence plan, not proof that the implementation passes.
