Sign-in: 'use recovery key' replaces 'use a different passkey' #45
Open
opened 2026-10-07 05:27:57 +00:00 by kayg
·
112 comments
No Branch/Tag specified
main
j470b-server-mesh-rejoin
mesh-compat-382
j444b-d381-key-wins-flood
j461b-macos-utun-reader-thread
j475b-remove-host-motion
fix-reconnect-new-link
j481-d380
dev
j479-mesh-soak
fix/j476-host-facts
j475-motion-pill-split
j470-mac-node-join
root-upgrade-d376
j474-review-merge
latency-targets-120hz
nightly-suite-shards
gotatun-pin-j469
macos-utun-reader-thread
fix-flood-echo-stall
wip/j416
motion-fast-ease-out
mesh-addhost-j259
takeover-close-terminals-d368
kbd-instant-followups
fix-trust-key-double-click
nightly-suite-partial-report
appwin-icons-j207
rusqlite-slice1
swipe-content-first-d374
mesh-mtu-381
addhost-instant-open
glass-contrast-d365-mock
glass-contrast-d365
signout-followups-442
fix-startup-toast-red
research-gotatun-matrix-j317
themes-sync-j304
fix-load-flakes
fix-nix-zig-patch
fix-compute01-browser-baseline
ratchet-size-baseline-419
predict-auto-d130
revoke-coverage-d367
nightly-suite-queue-timeout
nightly-browser-suite
fix-rustsec-2026-0459
fonts-ioskeley-obel
log-retention-d375
fix-kbd-no-anim-427
fix-dev-red-specs-2
takeover-proof-305-j205
wip/j410-server-pump
ui-consistency-d372
fix-osc52-clipboard
libghostty-vt-1.0
forget-retired-host-d369
j404-merge-426
fix-setup-lock-race
fix-touch-select-426
revoke-access-report-ui
fix-predictive-echo-specs
fix-selinux-agent-exec
wip/j395-checkpoint2
wip/j395
j391-review-scratch
ui-consistency-j195-deferred-rebased
fix-rustc-paths-421
decisions-wording-341
fix-install-suite-red
fix-dev-rtt-specs
fix-pending-removal-align
fix-privileged-skip
fix-install-suite-404
review-j368
mesh-dns-j254
revoke-access-report-d356b
revoke-privilege-round5
fix-removal-confirm
review-j360
gotatun-rotation-367
deps-refresh-340
review-j354
review-J351
review-j350
addhost-takeover-d359
revoke-report-items-347
revoke-end-sessions-d362
review-j348
size-mesh-ssh-346
size-trim-337
revoke-access-diff-d356
j259-pre-rebase-b06c5a6
j305-ended-at-start-spec
addhost-sudo-consent
fix-layout-real-specs-411
fix-shell-open-411
fix-console-hosts-373
fix-shell-exit
fuzz-host-name-353
fix-host-details-410
macos-filter-j197
research-gotatun-tricks
revoke-p3-j216l
stale-state-pill
revoke-followups-j216k
revoke-progress-j216e
backup/macos01-20261106/lume/j197
backup/macos01-20261106/lume/appwin-icons-j207-stash0
backup/macos01-20261106/claude/stash-0
backup/macos01-20261106/claude/stash-1
backup/macos01-20261106/claude/J80-macos-s1
backup/macos01-20261106/claude/J80
backup/macos01-20261106/claude/J80-slice1-20261102
backup/macos01-20261106/claude/J16b-appwin-on-dev
backup/macos01-20261106/claude/appwin-launch-idle-146
backup/macos01-20261106/claude/J80-s1-run
wip/j259
trust-285-p3c
runtime-lock-j216f
mesh-ssh-p3-j175
tun-proof-p3b
trust-285-p3
terminal-polish-j271
tun-proof-p3
ssh-install-flakes-j216i
fuzz-fixes-j264
trust-285-a
trust-285-b
restart-oversized-fixture-j198
backup/macos01-20261106/lume/appwin-icons-j207
restart-bound-j216h
up-preflight-p3-j198
backup/macos01-20261106/lume/j251
up-preflight-j198
wip/up-preflight-j198-j245-p2
wip/up-preflight-j198-j245-p1
agent-fsync-offloop-j196
wip/up-preflight-j198-j245
settings-offscreen-j231
wip/up-preflight-j198-j226-inspection
wip/j103f
themes-j206
wip/up-preflight-j198-j226
flakes-j216c
backup/macos01-20261106/claude/j197
flakes-j216b
backup/macos01-20261106/claude/j197-red
wip/up-preflight-j198-review
flakes-j216
backup/macos01-20261106/claude/appwin-icons-j207
engineering-j208b
appwin-mock-j209
toast-stack-j165
engineering-j208
decisions-d351
decisions-d350
decisions-d349
appearance-presets-mock-j129
decisions-d348
docs-audit-spec
doc-coverage-baseline-raise
decisions-d347
decisions-d346b
decisions-d346
j88h-profile
ui-consistency-j195-deferred
ui-consistency-j195
engineering-practices-j194
preferred-login-ui-j166
signin-pools-263-j174
macos-node-265-s1
decisions-d345
decisions-d344
proxy-cgroup-j164
verify-quick-fuzz-329
proxy-start-io-j168
timing-flakes-j163
up-263-s1
mcp-events-j147
verify-quick-fuzz-j158
proxy-p3-j159
agent-resource-j157-detect
wip/j103d-final
remote-cancel-hang-j155
proxy-traefik-281-j62d
j149-verify-quick
proxy-traefik-281-j62b
j150-drop-unnamed
wip/j79d-red-r4
wip/j103d-d332
rootless-toast-j142
wip/j103d-head
wip/j103d
j125c-mcp
macos-build-j136
backup/macos01-20261106/claude/j136
wip/j79d-red-cli
wip/j79d-red-server
j121-link-liveness
j118c-tracer-failures
wip/j79c-head
release-desktop-j131
j124c-signed-macos
wip/j79c-red-p3
wip/j79c-red-p23
wip/j79c-red-p22
merge-j128-check
perf-deferred-j128
sidebar-toggle-260
j127-shortcut-changed-dot
j125-mcp
j118-tracer-failures
j126-account-summary
settings-sections-mock-j92
j120-pinch-lock
sidebar-292
backup/macos01-20261106/claude/j120
taste-2026-11-03
row-actions-242-215
backup/macos01-20261106/claude/stash-0-untracked
backup/macos01-20261106/claude/J80-265-s1-run
backup/macos01-20261106/claude/J80-macos-s1-20261102
j112-canvas-commands
ui-no-overshoot-scroll
fix-recovery-restart
backup/macos01-20261106/claude/stash-1-untracked
taste-2026-11-02
size-baseline-ratchet
machine-cards-structure-j108
j109-boot-copy-mockups
fix-dev-red
wip/up-263-s1
j95b-settings-rows
proxy-traefik-281
j95-option-rows
docs-human-j91
docs-keys-palette
fix-flood-1013-270-j38d
mesh-ssh-s1
mesh-ssh-s0
addhost-d291-tunnel
test-stability-load
mesh-relay-220
repro-296
shim-thp-off-24
mesh-pins-258-v2
mesh-dns
signin-d311-merged
docs-pages
ui-size-283
fix-ui-batch-specs
wip/j12b-edge-update
gate-on-arm
fix-rename-sync-293
trust-285-j60b
fix-focus-ring-clip
integ-ui-1101
edge-update-v2
signin-d311
taste-2026-11-01
layout-per-tab-250
ui-approved-splitopt-224
ui-approved-splitopt-224-on-dev
icon-text-centre-282
ui-approved-189-212-216
research-reverse-proxy
transfer-budget-320
review-mesh-pins-258-r2
sidebar-pill-259
review-mesh-relay-220
wip/j12-edge-update-v2
nix-package
status-crash-loop-237
fix-dev-test-failures
fix-fixture-socket-path
wip/mesh-relay-220-pre-dev-advance-rebase
fix-canvas-side-clip
research-head-to-head
frosted-real-256
review-mesh-pins-258
wip/mesh-relay-220-pre-final-rebase
review-layout-per-tab-250-r2
broad-suite-triage
nix-devshell
review-status-crash-loop-237-r3
wip/nix-devshell-pre-p3
taste-frosted-real
wip/code-serve-demo-2026-10-30
wip/code-serve-glass-2026-10-30
wip/code-serve-clusters-2026-10-30
wip/code-merge-release94-dev-2026-10-30
wip/rproxy-delta-scratch-2026-10-30
wip/stale-note-257-staged-2026-10-30
wip/d241-size-staged-2026-10-30
review-broad-suite-207
wip/mesh-pins-258-pre-split
wip/mesh-relay-220-pre-rebase
mesh-measure-220
plan-211-update
review-edge-autoupdate-r3
perf24-reconnect
review-stale-note-r2
release-prod-live
d241-shell-marker
review-mesh-pins-server-258
review-revocation-r3
review-setup-token-r2
review-sync-journal-r3
wip/review-mesh-pins-258-prune-review-1995fee46
frosted-scroll-256
sync-journal-r3
revocation-per-account-wip
review-tokio-asyncfd-0386
review-sync-p3s
wip/stash-8by64-stash0-2026-10-30
mesh-drag-r2
setup-token-data-wip
release-9-4
auth-busy-1013
mesh-view-overlap
sync-p3s
review-auth-busy-wake
review-readd-r8-wip
mesh-drag-bounds
audit-auth-93
app-windows-stream-start
review-authority-cap-r3
app-windows-r7-measure
readd-minimal-r6
readd-minimal-r5
app-windows-r7-soak
readd-minimal-r4
app-windows-r7
app-windows-r6
readd-minimal-r3
readd-minimal-r2
readd-minimal
merge-release8-dev
review-busy-page-liveness-r2
review-busy-page-liveness
mesh-view-trim
review-authority-read-retry-r2
review-remove-uninstall-r2
release-retry-reattach
release-retry
review-remove-uninstall
review-authority-read-retry
app-windows-ship
mesh-autoswitch-p2
mesh-ssh
mesh-relay
mesh-macos-node
screen-and-control
session-labels
review-real-logins-r5
review-real-logins-r4
review-real-logins-r3
shim-memory-r2
review-real-logins-r2
shim-memory
shadow-addhost-instant
shadow-real-logins
shadow-same-session-flood
shadow-prod-perf-fix
hosts-from-server
app-windows-real
app-windows-transport
release-prod-6w
mesh-policy-verify
quiet-close-toast
dev-merge-r4
review-mesh-agent-transport
review-app-windows-transport
settings-roundtrip
review-release-pipeline-r4
mesh-agent-transport
ended-strip-fix
review-audit-ca-update-d244
settings-rows
phone-width
signout-clear
fix-restart-tests
dev-merge-rp
signer-hardening
review-audit-ca-update
terminal-fidelity
review-audit-ca-update-wip
mesh-integrate
review-mesh-agent-transport-515d3712
review-mesh-dataplane-feec1988
mesh-dataplane
signout
research-canvas-node
wip/review-renderer-cost
wip/review-terminal-fidelity
padlock-glyph
review-release-pipeline-2e95b689
phone-polish
sidebar-polish
inbox-generic
review-mesh-dataplane-378d4055
prod-batch
ui-inbox
ui-ca-unlock
ui-machine-sections
review-mesh-dataplane-a5f744fb
tls-session-prod
session-bounds-prod
fix-dead-session
session-bounds
tls-session
palette-polish
shortcuts-d222
research-appmeta
phone-gutter
ui-centre-button
wip/ui-centre-button
wip/tls-session
review-addhost-breakit
ui-platform
renderer-cost
remote-agents
mesh-api
ssh-bootstrap
prod-hotfix2
prod-fixes
review-remote-agents
review-mesh-dataplane
session-life
research-browser
review-mesh-api
research-capture
review-mesh-api-round3
review-mesh-api-round1
gate-stability
review-gate-stability
review-relay-direct
review-mesh-api-findings
proto-sessions
font-picker
proto-addhost
proto-windows
mesh-core
latency-gate
research-bsd
research-discovery
keytray-mods
mock-core
ui-tweaks
fix-motion-sel
fix-motion
integrate2
fix-robust
t-web
t-server
vt-ghostty
fix-snap-echo
t-web-auth
review-vt2
t-agent
lane-protocol
lane-shim
lane-auth
s1-base
s1-contracts
s1-workspace
No results found.
No labels
launch-qa
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
kayg/infraternal#45
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Owner (2026-10-07): instead of "use a different passkey…", the sign-in card offers "use recovery key": a sign-in path with the 24 recovery words. The server already supports recovery (recovery-start with a 24 h delay per contracts/keywrap.md; review-auth3 confirmed recovery replacement works through the verifier and SQLite), but there is no production UI.
Flow:
Motion and typography match onboarding. Needs a mockup review first if it differs materially from the onboarding steps.
Owner decision D113: recovery is immediate when started from a device with a live session; otherwise it waits 24 h. Implementation follows ui-tweaks.
Starting mobile-recovery at base
56bb6f5. D113 is authorized by the owner comment here but absent from this base DECISIONS.md; I will reference the issue without editing owner decisions. Proposed additive keywrap contract: recovery-start accepts optional live cookie, grants delay_seconds=0 only for the same account with a live unlocked session, otherwise 86400, returns ready_at, and supports public username lookup without publishing account IDs. Replacement continues to unwrap and rewrap the original DEK. Will preserve the legacy user_id request and separate auth.ts changes.D113 regression reproduced before the server fix: recovery_http_live_same_account_is_immediate returned delay_seconds=86400, expected 0 (target/recovery-red.log). The fixed HTTP tests now pass for matching live sessions and delayed other-account, expired, pending-unlock and absent sessions (2 tests, 5.59 s). UI entry regression also reproduced: use recovery key button absent (target/recovery-ui-red.log). Browser recovery keeps all crypto/binary handling in existing auth.ts helpers; only 10 additive lines there.
Native production-adapter verification passes both immediate live-session recovery and sessionless delayed recovery (Chromium 149.0.7827.55, real Rust verifier/SQLite, native PRF/HKDF/AES-GCM). Both preserve the original DEK, consume the recovery capability and sign in with the replacement passkey. Added race coverage for revocation during Argon2 and checks that an active delayed request cannot be accelerated. Targeted recovery tests: 10 passed, 0 failed, 19.13 s. UI doubles enforce available time locally and server readiness independently; captures use public deterministic fixture words only.
UI motion regression reproduced: the ready-to-passkey pane jumped immediately; sampled height range was 0 px (target/recovery-motion-red.log). Retargeting a fitted auth viewport now uses the existing 240 ms onboarding glide, with keyboard activation remaining instant. The full-suite first rerun also exposed two fixture issues (palette role=option, APIRequest lacked browser Origin); corrected those without changing production auth. One run under concurrent Rust compilation measured the existing 500-key probe p99=27.7 ms vs its <20 ms local threshold; will rerun without compiler overlap, with no budget changes.
Completed Specify same-device recovery authorization (D113) at
7c9fa51c41. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (777.26 s). Gate output (verbatim summary):Full output: target/atomic-gates/01-7c9fa51-fast.log; will attach gate logs at finish. No push, merge or deploy.
Production-build screenshots for owner review. Every recovery step at 393×852 and 1440×900, for immediate and delayed paths. Word captures use public deterministic fixtures and contain no real account recovery key. The delay date is the server ready_at; no progress is fabricated.
26 production screenshots are now attached across #44/#45; all recovery captures use public deterministic fixtures. D80 checks now prove 44 px targets throughout recovery at both viewports. The existing contract rejects repeated active recovery-start, and browser recovery secrets remain memory-only: after a page discard, its token is unavailable. Keeping the existing deadline safely across reload would require an explicit additive resume operation; I am preserving the existing policy and correcting the generic denial guidance instead of claiming a wrong key. Exact-commit gates are running; contract and touch module snapshots passed.
Completed Waive recovery delay only for a matching live session (D113) at
b42795b8a1. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (399.25 s). Gate output (verbatim summary):Full output: target/atomic-gates/05-b42795b-fast.log; will attach gate logs at finish. No push, merge or deploy.
Recovery/onboarding lifecycle finding: after first setup, clicking the terminal capsule produced 3 page errors because the persistent app host retained listeners querying the removed setup card. Regression failed first (target/onboarding-lifecycle-red.log: expected 0, received 3). AbortController cleanup, ResizeObserver disconnect and release of setup token/word references now pass the real browser first-run/login/terminal test (1 passed, 17.9 s; target/onboarding-lifecycle-green.log). Separate atomic fix follows; no auth.ts binary changes.
Completed Expose authoritative recovery readiness and username lookup (D113) at
96965fe309. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (428.71 s). Gate output (verbatim summary):Full output: target/atomic-gates/06-96965fe-fast.log; will attach gate logs at finish. No push, merge or deploy.
Final source at
3b1cde5; evidence handoff 9907375. Full production Playwright suite: 29 passed (3.4m), including both recovery paths, original-DEK envelope check, authoritative delay, retries, live-session entry, pane motion and touch targets. Native real-verifier recovery scenarios previously both PASS; rerunning at final head after exact-commit gates. docs/verification/mobile-recovery.md records security checklist, 26 attached screenshots, 50-session-row diagnostics and memory-only waiting-page/reload limitation. No push, merge or deploy.Production download measurement against base
56bb6f5, same Bun 1.4.2 build: main.js gzip 27911→28328 bytes (+417); all JavaScript gzip 238995→243842 bytes (+4847), including lazy chunks and workers. Raw all-JS 793205→805662 bytes. Recovery imports on demand and reuses existing BIP-39/crypto helpers; no new dependencies. target/evidence/bundle-size.json; evidence-docs commit amended to include these numbers.Completed Prove recovery session isolation, races and unchanged delays (D113) at
ece609fa4a. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (254.59 s). Gate output (verbatim summary):Full output: target/atomic-gates/07-ece609f-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Reuse onboarding recovery-word acknowledgement controls (#45) at
4c691ae366. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (247.21 s). Gate output (verbatim summary):Full output: target/atomic-gates/08-4c691ae-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Share existing browser ceremony helpers with recovery (#45) at
0bc902e2e1. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (244.94 s). Gate output (verbatim summary):Full output: target/atomic-gates/09-0bc902e-fast.log; will attach gate logs at finish. No push, merge or deploy.
Owner (2026-10-07): the sign-in card has more vertical space than its content. Measured on production: below the button,
.auth-loading(14px + 14px margin) and.auth-message(16.8px min-height + 12px margin) are reserved but empty, so the bottom has about 93px against a 40px top padding. Fix together with the 'use recovery key' link:Completed Recover passkeys by rewrapping the original browser DEK (D113) at
c64de57f16. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (253.77 s). Gate output (verbatim summary):Full output: target/atomic-gates/10-c64de57-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Open the onboarding-style recovery flow from sign-in and live devices (#45) at
0b43b4a998. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (267.24 s). Gate output (verbatim summary):Full output: target/atomic-gates/11-0b43b4a-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Verify recovery crypto and both delays in native Chromium (D113) at
3e993424d8. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (348.23 s). Gate output (verbatim summary):Full output: target/atomic-gates/12-3e99342-fast.log; will attach gate logs at finish. No push, merge or deploy.
Historical gate finding on superseded recovery-test snapshot c427643 (current replacement is
7f02473): Rust test clean_control_close_is_not_an_internal_error failed at auth/tests.rs:1687 with server closed websocket unexpectedly. 70 server tests passed, 1 failed, 6 ignored; fmt/native fmt/clippy/cargo-deny/both static builds passed. target/atomic-gates/14-c427643-fast.log retains the full run. Running the existing WebSocket case in isolation, then validating the six remaining current-branch commits; no threshold or unrelated source change.WebSocket follow-up: clean_control_close_is_not_an_internal_error passes in isolation (1 passed; 0 failed; 76 filtered out; 0.49 s), target/control-close-isolated.log. The failure was on off-branch superseded snapshot c427643, not the final source. Retaining both outputs and continuing exact fast gates on current replacement
7f02473and subsequent commits; no source or threshold changes.Completed Exercise recovery steps and finish rejection with production UI screenshots (#45) at
7f024731a4. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (246.1 s). Gate output (verbatim summary):Full output: target/atomic-gates/14-7f02473-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Match recovery pane fitting to onboarding motion (#45) at
595ae06ac1. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (245.17 s). Gate output (verbatim summary):Full output: target/atomic-gates/15-595ae06-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Give recovery actions full mobile touch targets (D80) at
697587b1fd. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (241.48 s). Gate output (verbatim summary):Full output: target/atomic-gates/16-697587b-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Explain recovery start denials and existing-device passkeys (#45) at
de4179bc7c. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (265.6 s). Gate output (verbatim summary):Full output: target/atomic-gates/17-de4179b-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Release onboarding listeners before terminal interaction (#45) at
3b1cde5f3d. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (312.73 s). Gate output (verbatim summary):Full output: target/atomic-gates/18-3b1cde5-fast.log; will attach gate logs at finish. No push, merge or deploy.
Completed Record mobile gestures and D113 recovery verification (#44, #45) at
18d5035270. Isolated exact-commit scripts/verify fast, tracer TypeScript check and production build passed (303.21 s). Gate output (verbatim summary):Full output: target/atomic-gates/19-18d5035-fast.log; will attach gate logs at finish. No push, merge or deploy.
Final-worktree gate environment finding: runtime setup_token_socket_is_private_and_requires_explicit_request failed with path must be shorter than SUN_LEN. Job TMPDIR + runtime UUID fixture + setup-token.sock was 132 bytes, above AF_UNIX 108 bytes; source is unchanged. All other fast rows passed, and native browser final gate passed (4 existing + 2 recovery scenarios). Full failing output retained as target/final-fast-long-tmpdir.log. Repeating the final fast gate with a live /proc directory-FD alias to the same job scratch directory so fixtures remain inside job scratch and the socket path fits.
Implementation finished on mobile-recovery at
18d5035270, base56bb6f5. 19 atomic commits each pass exact-commit scripts/verify fast, tracer check and production build. Final-head required Nix fast gate and native browser gate pass. Full production Playwright: 29 passed (3.4m), TRACER_TEST_PORT=4551. No push, merge or deploy; issues remain open.Unedited complete gate logs, final diff, contracts, handoff and machine/scale/bundle metadata (ZIP SHA-256 40ce882f04ef71b94bc448b8249d83c9d57fc6f52f690ff9436dc58f4bd15d8d). Screenshots are attached in the earlier production evidence comment. Reviewer handoff: docs/verification/mobile-recovery.md.
Final fast output (verbatim):
Native browser output (verbatim PASS lines):
Native recovery covers immediate same-account live session and enforced no-session delay, preserving the original DEK and logging in with the new passkey. Rust tests also cover other-account/expired/pending cookies and revocation during verification. Production main.js gzip +417 bytes; all JS including lazy chunks/workers +4847 bytes. Diagnostic 50 live session rows, n=30/path: no live p50/p99 17436/22332 us; matching live 17548/20062 us (SQLite-memory local run, not perf-VM certification).
How to test:
Known contract limitation: words/capability are memory-only; leaving, closing or reloading the waiting flow loses the capability, and an active request rejects another start until expiry or signed-in cancellation. A resumable endpoint preserving the original deadline is proposed separately on this issue.
Physical iPhone/Safari, independent security and owner screenshot review, and pinned perf-VM budget certification remain review work; local emulation is not a physical-device claim.
Focused defensive recovery audit started. Read CLAUDE.md, DECISIONS.md, architecture/process, keywrap contract and all 30 issue comments. Branch mobile-recovery, base
56bb6f5, reviewed head18d5035270. Worktree stays read-only; experiments and gates use an isolated scratch copy. Continuing the documented lost-capability limitation and verifying D113, crypto, timing, cancellation, notifications and admission.Audit requirement/contract discrepancy reproduced: browser-only recovery words assertion fails (1 failed; expected false, received true). apps/tracer/src/recovery-auth.ts:10 sends exactly {username,words}, including the readable 24-word phrase, over HTTPS. contracts/keywrap.md:6-7 explicitly requires server-side plaintext words for Argon2id. No DEK or PRF output is sent. This follows the existing contract but does not satisfy the job checklist; an owner contract decision is needed if browser-only words is required. Probe source/log will be attached with the verdict.
Audit step complete at unchanged head
18d5035270: production recovery Playwright gate passed, verbatim: 5 passed (26.7s), TRACER_TEST_PORT=4267. Covers immediate/delayed paths, original-DEK envelope check, input validation, rejected finish/retry, live-session entry and pane motion. Native verifier gate and independent expiry/reload/timing/admission probes are running. Sessions have no source/device binding in the existing schema; ceremony-cookie binding is separate, so same-account bearer-cookie replay qualifies for D113.Audit finding F1 (P1), head
18d5035: same-account unlocked session expiring at request_time+1 still waives delay after a 2200ms verification-boundary pause. Expected delay_seconds=86400; actual 0. Failing HTTP probe audit_recovery_session_expiring_during_verification_keeps_delay. auth/http.rs:207 samples time before awaits; auth/recovery.rs:48-49 checks expiry against that stale time under the writer lock. Revocation is atomic, elapsed expiry is missed. Test/log will be attached.Audit finding F2 (P1), head
18d5035: discard sessionless recovery capability at start, re-enter correct words at 24h => denied. Retry at 48h => new ready time 72h from first start. Expected resumable original 24h deadline without secret persistence/acceleration. Failing test audit_recovery_after_page_discard_can_resume_at_original_deadline. recovery.rs:55 only replaces expired requests; recovery.ts:37 also discards capability on Back. Confirms the prior author limitation; a 24h wait is insufficient after page loss. Test/log will be attached.Audit finding F3 (P2), head
18d5035: after delayed recovery starts, authenticated session contains no pending-recovery information; no notification is emitted and production browser has no recovery-cancel call/control. Expected owner visibility and signed-in cancellation. Failing test audit_recovery_pending_is_visible_to_signed_in_device. Server cancellation itself passes: two simultaneous starts admit exactly one; cancellation invalidates token and begun replacement ceremony. Sources: auth/sessions.rs:7-13, auth/recovery.rs:55-61, tracer/core-screen.ts:225. Existing server/product gap exposed by this UI.Audit gate qualification at
18d5035: first scripts/verify fast server tests report 69 passed; 2 failed; 6 ignored (178.31s): unchanged review3_backend_reply_has_a_deadline and server_setup_terminal_echo_and_resume_preserve_offsets_once. Compilation/probes overlapped; no cause attributed yet. Isolated reruns and a repeat gate follow. Native auth gate passes all 4 auth + 2 recovery scenarios; extended native crypto verifies both replacement envelopes contain original DEK, v3 input metadata, and absent PRF finish output.Audit gates at unchanged head
18d5035: focused Rust recovery gate verbatim: test result: ok. 12 passed; 0 failed; 1 ignored; 0 measured; 64 filtered out; finished in 24.26s. Rebuilt isolated unchanged WebSocket cases both pass (1 passed, 76 filtered out): deadline 60.51s, echo/resume 0.77s. An initial shared-target follow-up reused the 83-test experiment binary; those stale logs are excluded and retained with that qualification. Full repeat fast gate is running. The three recovery regression probes remain failing against unchanged production code.Verdict: REWORK, focused defensive audit of
56bb6f5..18d5035, head18d5035270ca6792e54d7c44e9d7343ffedbff94. Worktreemobile-recoveryremained read-only; no edits, commits, pushes, deployments or issue closure. Read all #45 comments and contextual parent review #40 history; D113 authority is the owner comment here (absent from this head's DECISIONS.md).Ranked findings, each with a failing test in the attached evidence:
auth/http.rs:207samples time before awaits andauth/recovery.rs:48-49uses that stale timestamp. Test:audit_recovery_session_expiring_during_verification_keeps_delay. Revocation ordering is correctly writer-locked; expiry still needs current authority time.recovery.ts:37also discards capability on Back;auth/recovery.rs:55refuses active restarts. Test:audit_recovery_after_page_discard_can_resume_at_original_deadline. Previously disclosed limitation, independently reproduced. The 72h case assumes no signed-in device is available. Additive resume policy needs owner approval; documentation alone does not make this mobile path usable after a discarded tab.recovery-cancelcall/control. Test:audit_recovery_pending_is_visible_to_signed_in_device. Sources:auth/sessions.rs:7-13,auth/recovery.rs:55-61, tracercore-screen.ts:225. The server cancellation API does work, including invalidation of an already-begun replacement. This is an existing server/product gap exposed by this production UI.{username,words}atrecovery-auth.ts:10. Boolean-only transport test fails (expected false, received true).contracts/keywrap.md:6-7explicitly requires server plaintext words for Argon2id, and the server also generates rotated words. This follows the current contract and is not a new regression; the owner must reconcile the checklist with that contract before changing the crypto foundation. DEK/PRF never leave the browser as plaintext.Verified: both replacement passkey and recovery envelopes decrypt to the original DEK in native Chromium with real Rust verifier/SQLite; v3 input metadata and unchanged
infraternal/keywrap/v1|UUID|kindAAD; PRF absent from finish proofs. Old passkeys/envelopes, sessions, API keys and approvals are revoked atomically per contract. Server readiness remains authoritative; exactly one concurrent start succeeds; cancellation invalidates tokens and pending replacement ceremonies. Missing/other-account/expired/pending/revoked sessions retain the wait. No session device/source binding exists; existing bearer-cookie replay can qualify for D113, independently of enrollment ceremony binding.Username measurements (interleaved local debug, 40 samples each, loaded host): identical 401 status/body/no cookie. Valid wrong phrases: known p50 514848 µs / p99 782445 µs; unknown 517385 / 741487 µs. Malformed phrases: known 606 / 1149 µs; unknown 611 / 857 µs. No clear separation demonstrated; this is not a general timing proof. Recovery-start and registration-finish both throttle request 121 with 429 and Retry-After: 60 under the unchanged browser partition. No partial word-guessing response was found.
Complete logs, failing tests, findings, manifest and production screenshots — ZIP SHA256
453bf05d7b429e63e0795b8a0aea5cc2c064d022c04145bba056abcf8af4605f. Logs contain no secret payloads; screenshots use public deterministic fixture words. The scratch directory will be removed after this record is posted. Screenshots are for owner review; no visual-quality verdict is made.Production delayed recovery, 393×852 · 1440×900
First fast gate output (verbatim result lines and gate table; complete output attached):
Rebuilt isolation output (verbatim):
The first fast run failed two unchanged WebSocket cases; both pass in rebuilt isolation. Initial shared-target follow-ups reused the extra-probe binary and are labelled
stale-*, excluded from head gate results. No cause is assigned solely from isolation success.Repeated fast gate output (verbatim result lines and gate table; complete output attached):
Focused existing Rust recovery tests (verbatim):
Native auth browser gate (verbatim PASS lines):
Extended native crypto (verbatim PASS lines):
Production recovery browser gate (verbatim):
TRACER_TEST_PORT=4267. Separate delayed screenshot run:
1 passed (11.8s), port 4270. Transport regression: 1 failed, port 4268. Independent Rust probes:test result: FAILED. 3 passed; 3 failed; 0 ignored; 0 measured; 77 filtered out; finished in 51.34s.Recovery fixes started on mobile-recovery at base/head
18d5035270. Read repository contract, architecture/process, all #45 and parent #40 comments, and downloaded audit evidence (comment 30593). Porting audit regressions before fixes. Owner task authorizes additive resumability and browser-only recovery derivation; no new foundational crypto library, push, deployment or merge.Additive contract proposal before implementation: recovery resume re-verifies authority and reissues a capability while preserving the stored ready deadline, including after capability expiry; cancellation/completion delete pending state. Authenticated sessions disclose only pending ready_at; each signed-in browser shows persistent cancellation notice plus toast. Start/cancel/complete audit rows commit with state changes. Recovery v2 uses existing WebCrypto HKDF-SHA256 with distinct auth/wrap info strings over 256-bit BIP-39 entropy; only auth secret reaches Argon2 storage, words and wrap key stay local. Browser generates setup/rotation words. Existing phrase PHC hashes cannot verify an HKDF output: explicit one-time legacy upgrade is required, writer-locked and permanently disables phrase admission on upgrade; the UI will state this exception. Envelope v1 ciphertext/AAD stays decryptable locally. No additional crypto engine/dependency.
Audit regressions ported and reproduced at base: 0 passed; 3 failed (6.64s), target/recovery-fixes/audit-red.log. Expiry actual 0 vs expected 86400; discarded page retry at 24h denied, retry at 48h ready offset 72h; session lacked recovery information. Boolean transport regression also failed (readable words in payload). F1 focused green: 11 passed; 0 failed; 1 ignored (33.37s), f1-green.log. Writer-locked expiry now samples the HTTP clock after verification/database waits; no pre-verification session sliding.
Completed logical slices (full exact-commit fast gates pending): F1
7c4de14, clock sampled under writer lock; focused 11 passed/1 ignored. Resume contract129b92e, serverf26145b(12 passed/1 ignored, 21.94s), browser531a781(6 passed, 21.9s including discarded-page resume). Audit schema964d16f, notice contracta7a670d, lifecycle/sessione8961d3(14 passed/1 ignored, 37.40s). Verifier/envelope schema493b66aand browser-only threat/migration contract8f05d14. Resumption regression now reports retry_at_24h_denied=false; retry_at_48h_ready_offset_hours=24. Logs target/recovery-fixes/. The initial fast run is dependency warmup, not exact-head evidence after subsequent slices; exact source snapshots will be gated before completion.Completed v2 slices: crypto ff273a0, authenticated wrap metadata 8bd6140, browser-verifier enrollment 6200deb, resumable verifier authentication/one-time legacy upgrade 839b4f5, local HKDF/entropy eb9070a, recovery UI 8545ffa. Server full: 77 passed/6 ignored (188.49s); final statement-atomic recovery subset: 16 passed/1 ignored (38.30s). Native Chromium: 4 auth + 2 recovery scenarios PASS, both retain original DEK. Browser transport and already-upgraded retry: 2 passed (5.6s). F3 socket e3cc80b and UI 12428cc pass real two-device and production notice/cancel probes. An explicit verifier-first retry guard prevents retransmitting already-upgraded words. Two synchronization/lint fixups will be folded into their logical commits before exact snapshots are gated; updated SHAs and full logs will follow.
Completed browser test fixtures
ea74162and native-auth fixtures1c36e68: verifier-only request fields are checked against independently derived HKDF output; native PRF/Rust SQLite coverage preserves the original DEK. Clock-skew finding: with browser time +7 days, Continue enabled despite a server delay of 3600 s (target/recovery-fixes/skew-red.log). Fixed indbe4385using server duration + monotonic time and foreground resumption; targeted green: 3 passed (11.6s), TypeScript check passed. Exact-snapshot fast gates are running; no mixed-source gate result is counted. History fixups were folded into their logical modules before verification.Production-build screenshots for owner review: every immediate/delayed recovery step, persistent signed-in cancellation notice/toast and explicit older-key disclosure, at 393×852 and 1440×900. Word screenshots use public deterministic fixtures only. I have not judged visual quality. Production recovery subset: 10 passed (26.2s), port 4651; target/recovery-fixes/final-recovery-browser.log.
Review finding / additive admission correction proposed before implementation: auth/crypto.rs maps all exhausted two-slot Argon2 admission to Denied (401). An explicitly selected older-key browser treats a 401 verifier probe as permission to attempt legacy phrase migration; transient overload must not trigger that fallback. Keep the two-slot bound and existing generic 429 + Retry-After: 60 by mapping capacity exhaustion to Throttled, independent of account/version. Add a real-semaphore failing regression plus browser 429/503 non-disclosure tests. No new engine or account/version signal.
Admission finding reproduced: target/recovery-fixes/capacity-red.log, real two-slot semaphore, 0 passed / 1 failed (0.77 s): exhausted verifier returned Denied, not Throttled. Fixed in the crypto module: 1 passed (0.41 s), target/recovery-fixes/capacity-green.log. Browser non-disclosure probes: 4 passed (7.1 s), including explicit older-key selection with 429 and 503, zero phrase migration requests. Contract commit
816c427precedes implementation; fixed capacity bound and generic response remain. Production screenshots attached (28); no visual-quality claim.Exact-snapshot gate
7c4de14(717.75 s), exit 0. Unedited output: target/recovery-fixes/atomic-gates/7c4de14-fast.log.Further auth review finding: verify_credential uses one database read for a known identity and two for an unknown identity (fallback owner PHC), despite paying the same Argon2 cost. Proposed correction under the existing no-oracle contract: one indexed owner/candidate join for both, retaining dummy verification and generic denial. A real SQLite acquisition counter regression is running before the fix; no verifier is mocked. No contract/engine replacement is needed. Native browser gate currently passes all 4 auth + 2 recovery scenarios. Scale socket test
e1c214e: 16/16 devices see start/cancel, other account 0 events (0.64 s). Core fixture selector21868f0: focused production check 1 passed (14.6 s).No-oracle finding reproduced: identity-work-red.log, known/unknown real SQLite acquisitions 1 vs 2, 0 passed/1 failed (2.29 s). Fixed with one indexed owner/candidate join plus unchanged dummy Argon2: identity-work-green.log, 1 passed (2.06 s). New logical auth commit follows
e1c214e. Local paired diagnostic repeats had load averages rising from 13.45 to 15.36 on 8 cores and p99 ranging 43.8–190.4 ms for v2; they are retained as loaded evidence, not a regression certification. Browser subset, original-DEK native gate and full-cap socket scope remain green; complete exact-snapshot gates continue after the final-head checks.Threat-note clarification before documentation: the approved one-time legacy phrase exception can reveal the old DEK through its retained v1 envelope. Recovery deliberately preserves that DEK; new recovery words protect the new wrapping material but cannot erase plaintext/key knowledge a server retained from the old protocol. State this explicitly rather than claiming word rotation retroactively secures an already-known DEK. Fresh v2 accounts and normal verifier recovery disclose no unwrap material. No DEK/secret rotation or new proof engine is introduced in this job.
Startup latency finding:
be0763bnotice wiring made showTerminal unconditionally call session after showAuthState had already fetched it. Startup-read-red.log reproduces failure when only the second read returns 503: signed-in terminal and pending notice never mount. Reuse the existing authenticated startup snapshot; no extra round trip, while socket and foreground authority checks remain. No polling or new component. This is required by D41/D81 and keeps the new recovery notice from increasing reload latency.Exact-snapshot gate
129b92e(573.51 s), exit 0. Unedited output: target/recovery-fixes/atomic-gates/129b92e-fast.log.Exact-snapshot gate
f26145b(692.84 s), exit 1. Unedited output: target/recovery-fixes/atomic-gates/f26145b-fast.log.Checkpoint: source frozen at
955ef5e(32 logical commits after18d5035). Every exact-commit tracer typecheck and production build passes; evidence atomic-gates/app-results.jsonl and per-SHA app logs. Latest native browser gate: all 4 auth + 2 recovery scenarios PASS (final-native-browser-2.log). Startup fix735a53e: one identity read, 2 production checks passed (3.8 s). Author checklist and threat/measurement handoff: docs/verification/recovery-audit.md.Exact fast gates:
7c4de14and129b92ePASS.f26145bcurrently fails two pre-existing real-socket timing checks: busy_logout closed before expected reply, and sequential half-open admission exceeded the five-second Hello window under load ~19 on 8 cores; all other Rust gates/static builds PASS. Required browser gate likewise has a 20 ms latency threshold failure under loaded runs (23.6, 32.2, 67.9 ms), with no threshold change. These are outstanding gate results, not completion. Continuing verification; no push/merge/deploy.Exact-snapshot gate
f26145b(260.29 s), exit 1. Unedited output: target/recovery-fixes/atomic-gates/f26145b-fast-attempt2.log.Completion gate condition: shared-host load reached 31.96 on 8 cores. The unchanged
18d5035production browser fixture also failed to connect within its existing assertion window (baseline-latency-loaded.log), before measuring p99. Current-head browser p99 and socket authority/Hello-window checks remain outstanding under overload. Need a quieter shared-host execution window from the host's job scheduling/other running work; this job does not alter authority or performance limits. Continuing independent exact-snapshot checks and retaining every failed attempt. Native/crypto/browser recovery tests and all 32 archived app checks/builds pass.Exact-snapshot gate
964d16f(237.39 s), exit 1. Unedited output: target/recovery-fixes/atomic-gates/964d16f-fast-attempt1.log.Exact-snapshot gate
531a781(323.64 s), exit 0. Unedited output: target/recovery-fixes/atomic-gates/531a781-fast-attempt1.log.Warm-build finding: migration 0009 exists in exact snapshots 531a781/a7a670d, but the cached real server unit-test binary contains CREATE TABLE users and does not contain CREATE TABLE recovery_audit. Evidence: target/recovery-fixes/migration-embedding-red.json. Pinned SQLx 0.8.6 documents that migrate! cannot watch newly added files without a build.rs rerun-if-changed=migrations directive. Adding directory tracking; immutable gate runner will explicitly refresh the migration macro for pre-fix snapshots so their schema-only gates exercise their actual migrations.
Exact-snapshot gate
a7a670d(197.49 s), exit 1. Unedited output: target/recovery-fixes/atomic-gates/a7a670d-fast-attempt1.log.Completed warm migration build fix
9eb13e7and evidence doc update7f60cf9. Real Auth::new/SQLite probe: before fix expected=10, applied=9 (assertion failure); directory watch expected=10, applied=10; second newly added SQL file with unchanged Rust expected=11, applied=11. Unedited migration-embedding-{red,green,warm-green}.log and probe retained. Schema-only archive checks will be repeated with actual migrations; prior531a781cached pass is invalidated.Head
7f60cf9fast test result, verbatim: test result: FAILED. 78 passed; 2 failed; 8 ignored; 0 measured; 0 filtered out; finished in 239.79s. Failures are existing review3_busy_expiry (unexpected websocket close) and review4_ten_second_open_preserves_authority (live ten-second open rejected); all recovery regressions pass. Shared 8-core host load 24.87/24.78/22.48. Full log target/recovery-fixes/final-fast-attempt1.log; static builds still running. Test concurrency was 2; next retry uses 1 without changing assertions, production timeouts, or latency budgets. Completion remains outstanding.Head
7f60cf9fast retry with one test worker remains red under shared-host load 18.87/20.55/21.34. All recovery regressions pass, including 16-device notifications with account isolation. test result: FAILED. 77 passed; 3 failed; 8 ignored; 0 measured; 0 filtered out; finished in 241.75sExisting failures: backend reply deadline, busy expiry, busy recovery. Their production authority storage deadline remains 25 ms. No timeout or budget relaxed. Native browser gate now running; remaining exact-snapshot fast checks will wait for a quieter host (load <=8 on 8 cores). Unedited log: target/recovery-fixes/final-fast-attempt2.log
Final-head native gate
7f60cf9: TRACER_TEST_PORT=4651 nix shell nixpkgs#binutils nixpkgs#file nixpkgs#gnumake nixpkgs#perl nixpkgs#zig_0_15 -c scripts/verify-auth-browser, exit 0. Verbatim output (capabilities remain in private IPC, no traces):Reviewable checkpoint at
7f60cf9(mobile-recovery, base18d5035), not completion: recovery-audit-checkpoint-7f60cf9.zip, 2208703 bytes, SHA-256 5722ccada7fd50a9631ea7e752bb980e5448f751d1aa2846e55f1bcdcb8f5aa8. Includes final diff/history, threat/migration note, author checklist, 34/34 app check/build results, full native PASS output, red/green regression proofs, 28 screenshot references/copies and scale measurements. HANDOFF.md/checkpoint.json list outstanding gates and exact reproduction. Only 2 immutable fast snapshots are accepted so far; the stale migration-cache pass is explicitly invalidated. Final fast remains red in existing 25ms authority tests under load; full browser latency remains red against 20ms. Remaining checks are queued for a quiet shared-host window; asked owner/scheduler when it is available. Nothing pushed, deployed, merged or closed.Final-head production browser command (port 4651), exit 1: 34 passed, 3 failed (6.7m). Recovery flow, deadline/resume, cancellation and skew checks passed. Failures are motion copy feedback, startup terminal readiness (undefined until renderer initialization), and terminal p99 23.5ms versus <20ms. No own compilation ran alongside browser checks. Shared-host load fell from >26 to 8.29 by completion; running isolated startup and then the full suite again in this quieter window. Unedited output: target/recovery-fixes/final-playwright-3.log
Blocked handoff: branch mobile-recovery, base
18d5035, head7f60cf92b1. 34 atomic commits; tracked worktree clean. recovery-audit-blocked-7f60cf9.zip, 2219034 bytes, SHA-256 4bf8802dea295f3e8fc587f10957ddedba6e6bb2d66cd6a812b2758311e0e889. HANDOFF.md/checkpoint.json include exact state, reproduction, immutable-SHA gate manifest, red/green evidence, 50-session/16-device numbers and screenshot references.All 34 app check/build snapshots pass; native browser gate passes all 6 real scenarios. Current required fast/full-browser gates are red under loaded shared-host conditions. Only 2 immutable fast snapshots are accepted; 32 remain outstanding, including invalidated stale migration-cache pass. No assertions, authority timeouts or latency budgets were relaxed. An actual CPU sample was 100% busy across the available 8 cores, load 15.49/16.85/19.98. Needed from owner/job scheduler: a quiet host window to rerun strict 25ms authority and <20ms browser checks and complete per-SHA fast validation. Baseline connection failure and all red runs are retained; they do not prove absence of a product regression.
Final-head commands/output, verbatim:
RUST_TEST_THREADS=1 nix shell nixpkgs#binutils nixpkgs#file nixpkgs#gnumake nixpkgs#perl nixpkgs#zig_0_15 -c scripts/verify fast
TRACER_TEST_PORT=4651 nix shell nixpkgs#binutils nixpkgs#file nixpkgs#gnumake nixpkgs#perl nixpkgs#zig_0_15 -c scripts/verify-auth-browser
cd apps/tracer && TRACER_TEST_PORT=4651 bun x playwright test
Terminal p99 was 23.5ms versus the unchanged <20ms limit. Isolated startup regression then passed (1.1s scenario, 6.5s harness, one session read); output in startup-final-isolated.log. Complete unedited gate output is in the attachment.
Explicit migration exception: an old phrase PHC cannot authenticate a derived verifier; the selected older-key upgrade sends words once on successful upgrade, verifier-first retries prevent resending after a committed upgrade. Legacy wrap version is preserved until local replacement. No owner live account was touched. No push, deploy, merge or issue close. No background jobs remain; only this job scratch/build targets were deleted, prior target evidence restored, current evidence kept in target/recovery-fixes/. This is not Definition of Done.
Independent defensive review started: read-only mobile-recovery head
7f60cf92b1, diff base56bb6f51d7(dev...head). Read #45 and parent #40 history; continuing prior expiry/resumption findings and examining browser-only derivation, legacy exception, transactional races and regression sensitivity. Experiments/gates run in isolated review-recovery scratch; port 4745. No source edits, commits, push or deployment.Independent R1 / P1 requirement conflict at
7f60cf9: recovery-auth.ts:18 POSTs the complete words to recovery-upgrade after explicit older-key selection and a 401 verifier probe. Public-fixture production-browser reproduction fails the absolute non-disclosure assertion: expected false, received true (1 failed; disclosure.log). auth.ts:357 uses those words as entropy for the v1 envelope; replacement retains that same DEK. Thus the receiving server can retain the original DEK, including after new words/passkey installation. keywrap.md:385-420 explicitly permits/documents this, so it follows the checked-in exception but conflicts with this review job hard never-reaches-server requirement. Successful version upgrade bounds acceptance, not receipt on failed attempts. Requires owner requirement resolution or removal of phrase admission; no real account secrets used. Findings persist in ~/.local/state/codex-jobs/infraternal/review-recovery/findings.md.Independent review step at unchanged
7f60cf9: tracer typecheck and production recovery/browser transport subset pass (13 passed, 36.6s, port 4745). Reversingdbe4385in scratch makes the skew test fail: Continue recovery enabled despite server delay=3600; restored before green rerun. Preserved 42 production screenshots using public fixture words, no visual-quality verdict. Head fast gate is running; expiry/resumption/account-isolation regressions pass so far. Independent multi-connection disk-SQLite restart and cancellation/completion probes are prepared; source worktree remains clean.Independent R2 / P1 at
7f60cf9: registration-finish accepts an expired recovery capability after writer contention. Real HTTP/software-WebAuthn/Argon2/disk-SQLite WAL probe: capability expires in 1s; begin finish while separate connection holds writer; wait until ceremony consumed, hold 2200ms, release. Actual HTTP 200; expected 401 (independent-races.log: 2 passed, 1 failed, 24.76s). http.rs:219 samples now before awaits; webauthn.rs:110 adds verifier hashing then writer wait; recovery.rs complete expiry predicate still binds the admission time. This violates capability expiry, not the 24h readiness wait. Concurrent cancel/complete (8 races) and disk restart/concurrent resumption probes passed. Recheck actual time under writer lock/statement and ceremony lifetime too. Source/log retained in ~/.local/state/codex-jobs/infraternal/review-recovery/.Independent review continuation (run 2): mobile-recovery remains read-only at
7f60cf92b1; diff base56bb6f51d7. R1/P1, R2/P1 and R3/P2 preserved. Finishing rate/admission and crypto review, remaining disk-SQLite probes and mutation sensitivity; port 4745. Absolute no-words/no-unwrap-material-to-server requirement remains binding; R1 requires a fix. No source commits, push or deployment.Independent continuation step at unchanged
7f60cf9: remaining head probes 6 passed/1 failed (48.27s); only failure reconfirms R2 expired finish, HTTP 200 expected 401. Source limits verified at 30 browser/10 device, all five recovery routes covered, untrusted XFF cannot reset budget; global recovery throttles after 120 with Retry-After=60. Six known/unknown/pending denials identical. Eight disk cancel/complete races serialize; 72h disk restart/concurrent resume and concurrent legacy upgrade preserve deadline/audit. R3 server half passes: unchanged ready time, actual remaining 90000s; browser reproduction rejects it. Production crypto helpers: independent HKDF match, six wrong-domain/account/kind/version/tamper denials, 100 unique salts/nonces; 2 bun tests, 312 assertions pass. Findings/logs in ~/.local/state/codex-jobs/infraternal/review-recovery/. Final fast gate still running; no reviewed source changes.Regression sensitivity complete at
7f60cf9: exactcc92fe4production patch reversed in scratch makes identity-work test fail (SQLite reads 1 vs 2; 0 passed/1 failed, 2.47s); restored patch passes (1 passed, 1.85s). Together withdbe4385countdown reversal and pre-71e24fc capacity-signal implementation, three regression checks detect their defects and pass restored. Reviewed source remains clean. Fast workspace gate still progressing; review host 8 vCPU KVM/i9-9900K, loaded 23.43/22.84/24.21 at verification start, so these durations are not performance certification.Independent defensive review finished at head
7f60cf92b1; diff base56bb6f51d7. Verdict: do not merge. Counts: P0=0, P1=2, P2=1, P3=0.R1/P1: recovery-auth.ts:18 sends legacy words that can unwrap the retained original DEK. The owner's absolute never-sent requirement stands; remove phrase admission. Checked-in migration exception does not satisfy this job requirement. R2/P1: recovery.rs:238/webAuthn finish uses admission time after hashing/writer waits; real HTTP/disk-SQLite proof replaces credentials after recovery expiry (200 expected 401). R3/P2: recovery-auth.ts:24 rejects honest remaining wait=90000s after server clock rollback despite preserved deadline. P1 findings already commented individually above.
Completed remaining checklist: production source/global admission and generic-denial probes pass, independent HKDF/AAD/wrong-version/tamper checks pass (2 bun tests/312 assertions), concurrent legacy upgrade commits once, eight cancel/complete races serialize, disk restart/concurrent resumes retain deadline and one live capability. Seven independent Rust probes: 6 passed/1 failed (48.27s); sole failure R2. Three fix-removal sensitivity checks fail when changed and pass restored (countdown
dbe4385, Argon2 capacity71e24fc, identity lookupcc92fe4). Retained native browser coverage: 4 auth + 2 recovery scenarios pass; production recovery subset 13 passed (36.6s). Heap zeroization limits and scope limits recorded in findings.md.Reviewed worktree unchanged/read-only; no commits, push, deployment or issue closure. Scratch worktrees/build products removed; findings, probe sources, mutation patches, logs and 42 production screenshots retained in ~/.local/state/codex-jobs/infraternal/review-recovery/. Host: 8-vCPU KVM/i9-9900K, starting load 23.43/22.84/24.21; timing evidence is not perf-budget certification.
scripts/verify fast, systemd scope CPUWeight=10000, TRACER_TEST_PORT=4745: exit 0. Full output fast-run2.log; verbatim server/summary/protocol output:
A green repository gate does not cover the independently reproduced R1/R2/R3 failures.
Recovery review fixes started on mobile-recovery at
7f60cf92b1. Read #45 and parent #40 histories and independent review artifacts. Plan: reproduce R2 with retained real HTTP/disk-SQLite probe, remove all phrase admission for R1 and add signed-in local-envelope rotation (no new UI, D162), then validate honest rollback waits for R3. Proposed keywrap correction: delete the legacy migration exception; legacy accounts require an unlocked signed-in device to upload only a v2 envelope plus verifier, with replacement-needed state in authenticated session. Owner task authorizes this contract correction; no decision edits, push or deploy.R1/R3 red evidence reproduced at base: production browser legacy probe disclosed public fixture words (expected false, received true), rollback wait=90000s never reached Recovery started; target/reviewer-browser-red.log (2 failed). New callable-rotation tests also failed first (function absent), target/r1-client-red.log. Client fixes: verifier-only request on every path, legacy control removed, local envelope+verifier rotation after acknowledgement; crypto 2 passed/0 failed (10 assertions). Remaining-wait boundary tests red 7 passed/2 failed, green 9 passed/0 failed; cap is existing 48h recovery capability policy. Retained production probes now 6 passed (1.5m), target/reviewer-browser-green.log. Rust real contention probe still building native dependencies under host load ~28; no Rust success claim yet.
R2 reproduced: reviewer_http_expired_capability_cannot_complete_after_writer_wait returned HTTP 200, expected 401 (0 passed/1 failed, 4.55s; target/r2-red.log). Under-lock live clock plus statement-time capability/ceremony expiry now pass 2/2 (7.29s; r2-green.log). Reverting the fix makes the extra ceremony-expiry contention test return 200 too (r2-ceremony-red.log). R1 independent self-review found callback-after-dismissal and cookie-account-switch gaps in new rotation: delayed callback tests failed 2/4; real HTTP foreign-account rotation returned 200 expected 401. Client now revokes settled callbacks and pins X-Infraternal-User; server compares that identity before hashing and under the writer lock. Client rotation+wait 13 passed/0 failed; retained crypto probes 2 passed/312 assertions. Full production recovery run: 14 passed/1 timeout in immediate retry; CPUWeight=10000 rerun passed 1/1 (11.9s), both logs retained. Exact R2 gate initial clippy rejected transaction function length 107/100; narrow rationale annotation added and full gate restarted.
Rotation server tests: 5 passed, 0 failed (27.24s). Tests cover local-DEK retention, metadata state, freshness, account binding, concurrent rotation and old-capability invalidation. No replacement screen was added (D162).
Production screenshots attached for owner review: phone entry, desktop entry, phone ready state. Public fixtures only.
Session-status diagnostic: 50 sessions, disk SQLite WAL 3.53.3, 1,000 samples after 200 warmups; p50 32.68 -> 36.62 us, p99 75.75 -> 78.43 us; zero added network trips or idle queries. 8-core shared KVM host, load 23.80/27.89/26.20; not pinned perf-VM certification. Evidence: target/session-scale.py and target/session-scale.json.
R2 frozen-tree fast gate: native fmt/fmt/clippy passed; unrelated shim attached_backpressure_and_detached_progress failed under load (detached producer deadline). Static builds still running. Will rerun once with CPUWeight=10000 and preserve both results; no unrelated timing-test changes.
Full production-browser run: 36 passed, 3 failed (6.6m): onboarding busy-counter timing, renderer binary-prefix canary, terminal latency. Requested single CPUWeight=10000 --last-failed retry: 2 passed, terminal latency still fails (37.1s); p99 33.6 ms against unchanged <20 ms. Recovery-specific checks all passed in the full run. Logs: target/tracer-full.log and target/tracer-full-retry.log. No unrelated test or threshold changes.
Both static architectures pass the frozen R2 gate; its sole failure was the unrelated shim producer deadline. The full gate is rerunning once under CPUWeight=10000.
Completed R2:
b7e76810f5, verified immutable index tree033db62ed5. Live HTTP clock is resampled under the SQLite writer lock; capability and ceremony consumption check commit-time expiry. Real disk-WAL probe changes expected-401/actual-200 to 401; extra ceremony probe and no-mutation checks pass.Initial fast gate: unrelated shim attached_backpressure_and_detached_progress failed under load. Requested single CPUWeight=10000 full rerun passes; both outputs retained (target/r2-fast-unweighted.log, target/r2-fast-scoped.log). Verbatim gate summary and TS result:
R1 server fast run (unweighted): 6 failures under shared load, including unchanged backend reply deadline, ten-second connection, terminal echo and socket authority tests. Recovery expiry probe failed its setup assertion (recovery-ready 401 vs expected 200 at reviewer_tests.rs:200), before the replacement/writer-contention assertion. Rotations and the ceremony-expiry probe passed. Logs retained verbatim: target/r1-server-fast.log. Static builds still running; the requested single scoped retry will use CPUWeight=10000 plus RUST_TEST_THREADS=1, without changing any test deadline or fixture. Host load currently 35.72/27.01/21.22 on 8 cores.
Completed R1 server phrase-path removal and signed-in rotation. Head
e8bc3e5437; immutable treeb604fb6ad5. Gate exit 0; full output: target/r1-server-fast-scoped.log. Verbatim summary:Completed R1 client local wrapping, legacy control removal and independent crypto regressions. Head
e0930f95d6; immutable tree039909dd2b. Gate exit 0; full output: target/r1-client-fast.log. Verbatim summary:Completed R3 policy-bounded rollback waits, nine boundary checks and independent production-browser probes. Head
fd9bbf9b98; immutable tree4f22a78d7f. Gate exit 0; full output: target/r3-fast.log. Verbatim summary:Finished R1/R2/R3 at
c5cf14ca40(mobile-recovery), tree25f17c4da0. Five atomic commits:c5cf14cRecord the rejected phrase exception and recovery review evidence (#45)fd9bbf9Accept policy-bounded recovery waits after server clock rollback (#45)e0930f9Keep recovery replacement wrapping on the unlocked device (#45)e8bc3e5Replace phrase admission with signed-in recovery rotation (#45)b7e7681Check recovery deadlines when SQLite consumes authority (#45)No production route or client path sends words. Signed-in local-DEK rotation exposes a callable function, with authenticated replacement state and no new UI (D162). Commit-time SQLite capability/ceremony expiry and policy-bounded rollback waits are enforced. Contract explains rejection of the old phrase exception; DECISIONS.md unchanged.
Final scripts/verify fast: exit 0, CPUWeight=10000, RUST_TEST_THREADS=1, TRACER_TEST_PORT=4746. All seven original reviewer server probes pass (obsolete concurrent phrase-upgrade adapted to signed-in rotation), plus the extra ceremony-expiry probe. Final client checks: 15 passed / 340 assertions; production disclosure + rollback browser probes: 6 passed / 8.9s; native Chromium auth/recovery: 4 + 2 real-verifier scenarios passed. Full client tsc passes. Evidence and B1/S1/S2/N1 checklist: docs/verification/recovery-review-fixes.md, target/final-fast.log, target/client-final-tests.log, target/reviewer-browser-final.log, target/native-auth-browser.log.
Unrelated-load results are retained: initial fast timing failures passed their one scoped retry. Full browser run: 36/39 passed; one scoped retry passed onboarding + renderer, while unchanged terminal probe still measured p99 33.6 ms against <20 ms. No unrelated timing-test changes; this run does not certify pinned performance-VM or physical iPhone budgets. Session-query scale diagnostic: 50 sessions, p50 32.68 -> 36.62 us, p99 75.75 -> 78.43 us, no new round trips or idle queries.
Production screenshots attached for owner review: phone entry, desktop entry, phone ready state. No push/deploy; issue left open. Complete gate output follows verbatim in numbered parts.
Final gate for
c5cf14ca40, verbatim output part 1/2:Final gate for
c5cf14ca40, verbatim output part 2/2:Cleanup complete at
c5cf14ca40: git status is clean, mobile-recovery scratch worktrees/build targets removed, small logs and screenshot originals preserved in worktree target/. Final summary and complete verbatim gate output are in the preceding three comments. Issue remains open; no push or deployment.Independent re-review (run 3) started: read-only mobile-recovery, fix diff 7f60cf92b10ded0d6c15011be7c1306d76384180..c5cf14ca4088fe2347f55b15f2a8abff982ef810 (5 commits). Read repository rules, prior R1/R2/R3 probes and all #45/#40 comments. Experiments and gates use separate review-recovery scratch, CPUWeight=10000, TRACER_TEST_PORT=4747. Checking non-disclosure, transactional expiry including restart, bounded rollback waits and regressions. No source edits, push or deployment.
Run-3 completed client review at
c5cf14c: whole apps/packages/crates search and request dataflow show no production recovery-upgrade or phrase fallback; remaining server legacy helpers are cfg(test). Local rotation uploads exactly envelope + independent verifier, pins account, revokes dismissed callbacks and preserves caller DEK. Client checks 15 pass/0 fail/340 assertions (103ms); tsc passes. Production-built recovery browser subset 15 passed (40.1s), including phrase_disclosed=false, 429/503 retries, honest 90000s rollback, cancellation notice and retry. Evidence: ~/.local/state/codex-jobs/infraternal/review-recovery/{whole-grep-run3.txt,client-run3.log,browser-run3.log}. Fast gate and independent restart probe outstanding.Run-3 step at
c5cf14c: independent exact-boundary production browser checks 2 passed (4.4s): 172800s accepted with Continue disabled, 172801s rejected. Additional 401/429/503 request/retry and failed-rotation probes 6 passed/63 assertions (57ms), ciphertext/verifier only and no duplicate finish. Session-query remeasurement on 50 disk-WAL sessions, 1000 samples/path after 200 warmups: p50 14.02->14.71us; p99 50.44->51.56us; no added network or idle queries; SQLite 3.53.3, 8-vCPU i9-9900K KVM, load 4.12/8.87/10.27. 52 production screenshots retained for owner review. Fast initial environment run stopped after Zig temporary-file failure caused by invalid self-FD alias; corrected parent-PID alias run continues without source changes. Logs: boundary-browser-run3.log, requests-run3.log, session-scale-run3.log, fast-run3-environment-failed.log under review-recovery findings directory.Run-3 server probes at unchanged
c5cf14c: 8 passed/0 failed (27.38s), real WebAuthn + Argon2 + four-connection disk SQLite WAL. R2 capability expiry and ceremony expiry both return HTTP 401 after 2200ms writer contention, preserving envelope/verifier/session and no complete audit. Eight cancel/complete races each commit exactly one outcome; 72h reopen preserves ready deadline and concurrent resume has one live capability/start audit. Rotation commits once, invalidates old capability/begun ceremony, retains passkey/session; source middleware preserves 30 browser/10 device limits, rejects XFF reset and exempts logout. server-probes-run3.log contains outcomes verbatim. Extra aborted-finish/reopen probe and final fast output outstanding.Run-3 production-build captures at
c5cf14cfor owner review; public deterministic fixtures only. Focused capture checks: 3 passed (16.6s), 52 screenshots retained. No visual-quality verdict.enter-words-empty-393x852.png
enter-words-empty-1440x900.png
ready-now-393x852.png
Run-3 final fast gate at
c5cf14ca40, exit 0. Verbatim complete output part 1/3:Run-3 final fast gate at
c5cf14ca40, exit 0. Verbatim complete output part 2/3:Run-3 final fast gate at
c5cf14ca40, exit 0. Verbatim complete output part 3/3:Independent re-review (run 3) finished. Verdict: merge the five-commit fix diff 7f60cf92b10ded0d6c15011be7c1306d76384180..c5cf14ca4088fe2347f55b15f2a8abff982ef810, branch mobile-recovery. R1/P1, R2/P1 and R3/P2 resolved; no new actionable finding in this diff.
R1: no production phrase route/fallback; local wrapping uploads only envelope + independent verifier, pins account and expires dismissed callbacks. Whole client/server grep, real server phrase denial, crypto and 401/429/503 retry probes pass; contract now matches.
R2: live expiry checked under the SQLite writer and in the consuming statement. Both retained contention probes return HTTP 401 instead of prior 200, with no envelope/verifier/session/audit mutation. Added queued-finish abort + disk reopen/auth-state restart rejects old ceremony and expired capability, preserves the deadline and permits one fresh completion. This is auth-state recreation, not an OS process-stop test.
R3: 90000s rollback accepted; exact 172800s maximum accepted with Continue disabled, malicious 172801s rejected.
Results: retained server probes 8/8 (27.38s); extra restart/admission/notification probes 3/3 (11.93s); client tests 15/15, 340 assertions; added request probes 6/6, 63 assertions; production recovery browser 15/15 (40.1s); extra boundary browser 2/2 (4.4s); native Chromium four auth + two recovery scenarios PASS; tsc PASS. Existing cancellation, audit, notifications, source/global limits, KDF capacity and original-DEK continuity remain covered.
50-session disk-WAL diagnostic, 1000 samples/path: p50 14.02->14.71us, p99 50.44->51.56us, zero added network/idle queries. Eight-vCPU i9-9900K KVM, load 4.12/8.87/10.27. All runs scoped CPUWeight=10000; TRACER_TEST_PORT=4747. No perf VM/other host used; no physical-iPhone or unrelated terminal-budget certification. 52 production public-fixture screenshots retained; three attached above for owner judgment.
Complete findings, unedited logs, probe sources, measurements and all screenshots; ZIP SHA256 c14abb29b5d9fe88279aa2218908710d8e8899b7f7690206c6544a466e882cfc. Findings appended under Re-review (run 3) in ~/.local/state/codex-jobs/infraternal/review-recovery/findings.md. Reviewed worktree clean/read-only at head
c5cf14ca40; scratch worktree/build products removed. No commits, push, merge, deployment or issue closure.scripts/verify fast exit 0; complete verbatim output posted immediately above and attached. Server result (verbatim):
Protocol result (verbatim):
Static artifacts: x86_64 15900816 bytes; aarch64 13371248 bytes; PT_INTERP absent for both. Initial Zig temporary-directory failure is retained separately; successful gate used corrected parent-PID directory-FD alias, with no source or threshold change.
Starting integration on merge-recovery, base/dev
9c62448a32; reviewed mobile-recoveryc5cf14ca40. Reading prior findings and parent #5; merge conflicts in auth client, session/WebAuthn/socket server and terminal tests. Backend stays enabled; D162 UI hold will be a separate atomic flag commit. TRACER_TEST_PORT=4786; no push/deploy.Merge findings: dev terminal-touch.ts is byte-identical to the merged result; terminal.ts adds only recovery Subscribe/Event handling (12 lines). No conflicting touch changes dropped. Kept provider metadata/AAGUID persistence, setup_consumed notification (#51), deterministic handshake_timeout (#65), local themes (#75), mesh crate (#80). Recovery socket fixture required insert_session(..., None) after dev provider signature; initial merge-fast.log fails E0061 at auth/socket_tests.rs:346. Adapted the provider enrollment fixture to cfg(test) legacy_setup, matching existing legacy fixtures; production remains verifier-only. Native recovery harness used hard-coded target/; corrected it to honor CARGO_TARGET_DIR. UI hold regression before flag: mobile and desktop #use-recovery count expected 0, actual 1 (hold-red.log). Captured dev
9c62448production baseline at 393x852 and 1440x900; card rectangles mobile (20,274.375,353,303.234375), desktop (500,290.625,440,318.734375). Only time-dependent backdrop canvas excluded from pixel comparison; auth content/geometry retained.Migration integration finding: dev already owns version 0009_passkey_provider.sql; recovery carried 0009_recovery_audit.sql and 0010_recovery_derivation.sql. Kept dev v9 checksum/name intact and renumbered new recovery migrations to v10 audit and v11 derivation before accepting a gate. Interrupted the initial warmup/compile-failure gate; it is not counted as merge verification. The provider migration regression builds a real v8 database and upgrades through all merged migrations. Fresh frozen merge gate follows.
Frozen merge gate environment failure: initial_attach_requires_explicit_credit_before_replay could not create target/ac469391 (FileNotFoundError); the unchanged dev Python fixture assumes target/ exists even with CARGO_TARGET_DIR elsewhere. Created ignored worktree target -> /home/kayg/.cache/codex-scratch/merge-recovery/target so all build/fixture writes remain in job scratch. No timeout/assertion/source change. Initial gate output retained in merge-fast-final.log; repeating full gate after static cache warmup.
Integration checkpoint (merge pending, frozen tree): native-auth-final.log passes 4 isolated auth + 2 real-verifier recovery Chromium 149.0.7827.55 scenarios; original DEK/capability consumption/replacement login verified. Initial native harness lacked make; repeated with documented Nix make/perl/Zig shell, no source change. Recovery client checks: 15 pass / 340 assertions. 50-device disk SQLite WAL 3.53.3 projection comparison, 1000 samples/path after 200 warmups: dev p50/p99 15.472/53.642 us; merged 17.193/52.273 us. Machine infraternal-dev, 8 cores, load [18.47119140625, 17.41552734375, 14.75927734375]; no added network trips or idle queries; loaded local diagnostic, not pinned certification. Corrected account-entry red probe expected 0 palette recovery controls, actual 1 (hold-account-red.log). x86_64 static build 15961168 bytes, PT_INTERP absent; ARM + full gate retry still running.
Completed no-ff merge
4f8b737dbf(parents dev9c62448and mobile-recoveryc5cf14c). Integration choices recorded above; v9 provider migration preserved, recovery v10/v11. scripts/verify fast exit 0, CPUWeight=10000/TRACER_TEST_PORT=4786/RUST_TEST_THREADS=1. Server: 100 passed/9 ignored; static x86_64 15961168, ARM64 13426064 bytes, PT_INTERP absent. Native 4 auth + 2 recovery PASS; client 15 pass/340 assertions. UI flag step now in progress; no push/deploy. Verbatim gate summary:Full output retained: target/merge-recovery-evidence/merge-fast-green.log (will post final full gate verbatim).
D162 production proof: default build ignores ?mock=1&proto=recovery, no sign-in recovery button/screen or account controls. Strict screenshot diff against dev
9c62448: 0 differing pixels at 393x852 and 1440x900 (production-browser.log); only time-dependent shader canvas excluded, full auth layout/content retained. Production browser run 9 passed/1 failed: onboarding, core materials/themes/font, mobile gestures and hold tests pass. Supplementary terminal-theme test fails at mobile cursor pixel (background #0d0e10 vs cursor #7a9cff), while 50 theme switches p99 14.2ms passes 16.67ms budget and history/repaint checks pass. No terminal theme code changed; retaining artifacts and repeating that test to classify before handoff.Supplementary theme classification: scoped merged retry and untouched dev
9c62448production build both fail terminal-theme.spec.ts:302 with cursor pixel #eff1f5 instead of #8839ef (Latte, mobile matrix); theme-dev-baseline.log and theme-retry.log retain identical diffs. terminal-theme.spec.ts and terminal touch/theme implementation are unchanged versus dev; merged terminal.ts adds only recovery Subscribe/Event handling. This is inherited, not a green full-browser-suite claim; no unrelated fix or assertion/budget relaxation. Required production hold tests pass with zero screenshot differences. Preview suite (explicit preview flag, ?mock=1&proto=recovery) and final fast gate are running.Final scripts/verify fast at
1c12295c6a, exit 0; CPUWeight=10000, TRACER_TEST_PORT=4786, RUST_TEST_THREADS=1. Complete verbatim output part 1/2:Final scripts/verify fast at
1c12295c6a, exit 0; CPUWeight=10000, TRACER_TEST_PORT=4786, RUST_TEST_THREADS=1. Complete verbatim output part 2/2:Finished integration on merge-recovery at
1c12295c6a. Atomic merge4f8b737preserves reviewedc5cf14chistory; separate UI-hold commit1c12295. No push/deploy or dev-ref change outside the assigned worktree; issue stays open.D162: INFRATERNAL_RECOVERY_UI defaults off. Preview builds require ?mock=1&proto=recovery; =1 is the explicit production build opt-in after approval. All new sign-in/account recovery controls, screens, notices and toast use one predicate. Signed-in rotation, server endpoints, deadlines, socket state and recovery_words_need_replacing API metadata stay enabled. Dev touch behavior is unchanged; no conflicting touch change needed dropping. Dev migration v9 retained, new recovery migrations v10/v11.
Evidence: final production hold 3/3 (10.0s), zero differing pixels versus dev
9c62448at 393x852 and 1440x900 (only dynamic shader canvas excluded). Preview recovery + URL boundary suite 21/21 (1.3m); client/compiled flag tests in fast: 20 pass, 376 assertions. Native Chromium 149.0.7827.55: four auth + two recovery real-verifier/SQLite scenarios PASS, original DEK retained. Server fast: 100 passed, 9 ignored. Static binaries x86_64 15961168 and ARM64 13426064 bytes; PT_INTERP absent.Production JS transfer: gzip 250057/307200, Brotli 205883/256000 bytes. Against identical Bun 1.4.2 dev build, main gzip 28525 -> 29412 (+887); all JS incl lazy chunks/workers 244618 -> 250057 (+5439). Recovery metadata/crypto stays integrated; no new dependency/network round trip/idle query. Loaded 50-device SQLite WAL comparison and machine/load recorded above; not pinned perf certification.
Self-review B1/S1/S2/N1 completed: writer/statement expiry and provider/user bindings preserved; middleware/Argon2 bounds unchanged; no phrase admission/DEK/PRF transmission; flag does not gate authority or crypto; disabled UI adds no notice timer/listener; existing shared controls reused. Supplementary theme cursor-pixel check fails identically on untouched dev and merged retry at terminal-theme.spec.ts:302; retained, no unrelated behavior/assertion change. Initial environment and browser fixture failures retained; this is not a claim that the entire browser suite passes. Final preview run was sequential after fast to avoid shared dist artifacts.
Screenshots/logs/capture script/measurements retained locally under target/merge-recovery-evidence/: production-signin-mobile.png, production-signin-desktop.png, production-hold-final.log, preview-browser-clean.log, flag-fast.log, native-auth-final.log, session-scale.json and theme-dev-baseline.log. Immutable dev reference PNGs are committed in apps/tracer/test/recovery-ui-hold.spec.ts-snapshots/. Scratch archives/build targets removed after copying evidence; worktree clean.
How to test:
scripts/verify fast exit 0, CPUWeight=10000/TRACER_TEST_PORT=4786/RUST_TEST_THREADS=1. Complete verbatim output is in the preceding two comments. Verbatim summary:
Deployed dev
5ed4f29to monitor01: reviewed recovery backend with the recovery UI held (live sign-in verified: no recovery entry, text "Welcome back / Your passkey is all you need / Continue with passkey"), palette keyboard selection stays in view (#85), deterministic recovery expiry tests (#65). Gate: scripts/verify fast exit 0. Rollback: web.prev / infraternal.prev.kayg referenced this issue2026-10-28 17:53:56 +00:00