fix(consent): fail closed on ambiguous durable tail - #134
Conversation
Reject a grant-only snapshot after a stored revocation by locking the participant ledger and requiring the durable event tail to match the envelope before enqueue. Record the Active PR composition in traceability, changelog, ERD, UML, and as-built schema. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Exercise missing ledger or event rows, time and identity mismatch, timestamp overflow, and dropped relations so the tail lock stays at full statement and branch coverage. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Same-millisecond grant then revoke must bind the later-inserted revoke, not a lexicographically larger grant event_ref. Keep the ledger FOR UPDATE lock and fail closed on a grant-only snapshot after that revoke. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Reject a consent/outbox bind when two events share occurrence time and created_at, and require every durable event identity in the submitted ledger so opaque event_ref cannot reopen the #112 grant-beside-revoke hole. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
There was a problem hiding this comment.
Review (#134 729a2bd)
The unique fail-closed slice is sound: after persist, the adapter locks consent_ledger, requires every durable consent_event identity in the submitted ledger, selects the tail by occurred_at_unix_ms DESC, created_at DESC, and rejects a tied physical tail instead of using opaque event_ref.
Do not merge this head. Module rustdoc still says the tail is ordered by occurrence time, insertion time, then event identity. That is the exact tie-breaker this PR claims to remove. Function rustdoc and the SQL are correct; the module contract is not.
Prefer successor #142 (cursor/bc-67661417-bfc3-45ad-bb83-dcde94bd10d5-3ec5). It aligns the rustdoc, proves both tied grant and tied revoke envelopes leave integration_outbox empty, and updates ADR-0006 to Helsinki 2024 plus ISO/IEC 29184:2020 / TS 27560:2023.
Do not merge #70 3180620, #112 040bcf7, #120 3f72446, or #123 6643041.
Known residual, not a #134/#142 blocker: persist_consent_ledger remains a public write path. Next after #142 lands: make persist_consent_ledger_with_outbox the sole product consent write path, then POST /v1/consents.
Independent non-author approval and required checks on the unchanged exact head remain merge gates. Never self-approve.
Sent by Cursor Automation: Fix Issues
There was a problem hiding this comment.
Review (#134 729a2bd)
The unique fail-closed slice is sound: after persist, the adapter locks consent_ledger, requires every durable consent_event identity in the submitted ledger, selects the tail by occurred_at_unix_ms DESC, created_at DESC, and rejects a tied physical tail instead of using opaque event_ref.
Do not merge this head. Module rustdoc still says the tail is ordered by occurrence time, insertion time, then event identity. That is the exact tie-breaker this PR claims to remove. Function rustdoc and the SQL are correct; the module contract is not.
Prefer successor #142 (cursor/bc-67661417-bfc3-45ad-bb83-dcde94bd10d5-3ec5). It aligns the rustdoc, proves both tied grant and tied revoke envelopes leave integration_outbox empty, and updates ADR-0006 to Helsinki 2024 plus ISO/IEC 29184:2020 / TS 27560:2023.
Do not merge #70 3180620, #112 040bcf7, #120 3f72446, or #123 6643041.
Known residual, not a #134/#142 blocker: persist_consent_ledger remains a public write path. Next after #142 lands: make persist_consent_ledger_with_outbox the sole product consent write path, then POST /v1/consents.
Independent non-author approval and required checks on the unchanged exact head remain merge gates. Never self-approve.
Sent by Cursor Automation: Fix Issues


Superseded
This ambiguous durable-tail slice is fully contained in #142. Do not merge this predecessor.
Fresh ancestry evidence immediately before closure:
729a2bd26e0b9757c6f30a82388380412105373075d71eb3ea7e3005e3940a9a77cb127271b02a03#142 retains the fail-closed unique-tail rule and removes the stale event-identity ordering claim, with additional tied-tail persistence evidence. The separate #123 line was observed as divergent from #142 and is not claimed contained by this closure.
#142 remains Draft and still requires unchanged exact-head CI/security/review gates. Closing this PR does not promote successor behavior to protected-main truth.