A live login failure at ledger.tessera.at logged only 'login transaction
missing or expired' — and that one message covers four unrelated faults: a
cookie the browser never sent, a truncated one, one signed with a different
secret, and one that aged out. Each points somewhere else, so the incident was
undiagnosable from the log alone.
OidcError now carries a `reason` ('absent' | 'malformed' | 'bad-signature' |
'expired' | 'incomplete'), set by a new inspectTxCookie(). readTxCookie keeps
its null-returning contract, so nothing downstream changes; callers that want
the detail read err.reason, and can treat a merely-lost cookie differently from
a signature mismatch, which may signal tampering.
Claude-Session: https://claude.ai/code/session_01N5eAryCsDiunCtQqDVCRUE
Co-authored-by: dev0zzz <dev0zzz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>