- wrongTOTPCode excludes {-1,0,+1,+2}: the verifier samples the clock after
the helper, so a step boundary in between shifts its window to {0,+1,+2}
- B3-9 "Parallel with": OC-0345/0346 any; OC-0323 with B3-8; OC-0376..0378
after B3-2 (matches the safe-parallelism rule and the section text)
- OC-0378 suggestedFix: a restored challenge must carry the accepted
verification or roll back the MarkUsed claim, or the retry is a replay
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rg9QQWVN3E5UUgBD2dydtu
- wrongTOTPCode derives a code outside the three accepted steps instead of
assuming "000000" is invalid (1-in-333k flake in the per-user cap row)
- OC-0376/0377/0378 added to B3-9 in the step table and its section
- hp-0 open-record breakdown recomputed for the 59-open ledger
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rg9QQWVN3E5UUgBD2dydtu
12 tests / 44 table rows over the mounted auth router, no mocks: read
faults via ALTER TABLE RENAME, write faults via RAISE(FAIL) triggers.
Three rows pin defects as-is with `// known:` and ledger entries
OC-0376 (register 500 after the account commit), OC-0377 (verify-totp
maps a DB error to 401), OC-0378 (challenge consumed before the session
insert); fixed in B3-9, not here. Mutation spot-check: 401->500 in
totpChallengeSecret, 500->401 in loginAuthenticate, 503->401 in
AuthMiddleware each turned the rows that name them RED.
The nine watched ledger-count claims move 56 open / 375 -> 59 / 378.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rg9QQWVN3E5UUgBD2dydtu