Skip to content

fix(consent): stop documenting event-identity tail order - #142

Draft
cursor[bot] wants to merge 28 commits into
mainfrom
cursor/bc-67661417-bfc3-45ad-bb83-dcde94bd10d5-3ec5
Draft

cursor[bot] wants to merge 28 commits into
mainfrom
cursor/bc-67661417-bfc3-45ad-bb83-dcde94bd10d5-3ec5

Conversation

@cursor

@cursor cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Why

#134 fails closed when two durable consent_event rows share occurred_at_unix_ms and created_at. Its module rustdoc still said the tail was ordered by occurrence time, insertion time, then event identity. That is the exact opaque-key tie-breaker this slice rejects.

Prefer this head over #134 at 729a2bd. Do not merge #70 at 3180620, #112 at 040bcf7, #120 at 3f72446, #123 at 6643041, or #134 at 729a2bd.

What

Successor of #134 on the same fail-closed tail:

  • Module rustdoc now requires a unique durable tail ordered by occurrence time, then insertion time.
  • Persist-level RED/GREEN: a complete ledger plus either the tied grant or the tied revoke envelope leaves integration_outbox empty.
  • ADR-0006 records the tied-tail invariant and cites Helsinki 2024, ISO/IEC 29184:2020, and ISO/IEC TS 27560:2023. NIST Privacy Framework 1.0 remains the published framework; 1.1 is still an initial public draft.

This does not change consent purposes, infer consent, duplicate identity credentials, or weaken research opt-in separation.

Verification

  • cargo test --lib postgres_consent_propagation::envelope_tests
  • cargo test --test documentation_architecture_contract --test traceability_active_pr_contract
  • cargo clippy --all-targets -- -D warnings
  • full Runtime CI, exact statement/branch coverage, docs, security and independent review on the exact head

Next after this lands: make persist_consent_ledger_with_outbox the sole product consent write path, then purpose-specific consent HTTP (POST /v1/consents).

Independent non-author approval and required checks on the unchanged exact head remain merge gates. Never self-approve.

Open in Web View Automation 

seonghobae and others added 27 commits August 14, 2026 18:15
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>
Point TRACEABILITY, ERD, UML, and AS_BUILT at #134 so agents do not land
#70, #112, #120, or #123.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Module rustdoc still described occurrence, insertion, then event identity.
That is the exact tie-breaker this slice rejects. Align the rustdoc, prove
both tied envelopes fail closed at persist, and cite Helsinki 2024 plus
ISO/IEC 29184 and TS 27560 for the consent-record interchange target.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Prefer #142 over #134. The earlier head still documents event identity
as a durable-tail key.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Aug 16, 2026
Keep the authorization write-path gate independent of durable-tail
ordering and point agents at #142 instead of #134.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Consent/outbox landing vehicle

Head 75d71eb is the correct successor of #70/#112/#120/#123/#134.

Verified:

  • Durable tail is ORDER BY occurred_at_unix_ms DESC, created_at DESC with no event_ref sort key.
  • Tied created_at fails closed (tied != 1 → InvalidPropagationEnvelope).
  • Module and function rustdoc no longer say “then event identity”.
  • Same-millisecond later revoke beats a lexicographically larger grant.

Do not merge #70, #112, #120, #123, or #134 in parallel.

Residuals for later slices, not this merge: persist_consent_ledger is still a public write path; make persist_consent_ledger_with_outbox the sole product write after land; ledger reload stays on #140; then POST /v1/consents.

Independent last-push approval and exact-head required checks remain required. This review does not approve.

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer this exact head (75d71eb) over #134 at 729a2bd, #123 at 6643041, #120 at 3f72446, #112 at 040bcf7, and #70 at 3180620.

The unique slice matches the code. Module and function rustdoc require a unique durable tail ordered by occurrence time, then insertion time. They mention opaque event identity only to reject it. require_durable_ledger_tail locks consent_ledger, requires every durable consent_event identity in the submitted ledger, orders only by occurred_at_unix_ms DESC, created_at DESC, and fails closed when tied != 1. Persist-level equal_created_at_cannot_bind_either_tied_envelope submits a complete grant+revoke ledger with either tied envelope and leaves integration_outbox empty. ADR-0006 invariants 7–8 cite Helsinki 2024, ISO/IEC 29184:2020, and ISO/IEC TS 27560:2023. NIST Privacy Framework 1.0 stays; 1.1 is still CSWP 40 IPD.

No blocking production defect on this slice. Independent non-author approval and required checks on this unchanged head remain the merge gates. Do not self-approve.

persist_consent_ledger is still a public skip-outbox write path. That is the next product gap after this lands, then purpose-specific POST /v1/consents. Do not fold those onto this head. Do not merge the predecessor outbox PRs in parallel.

Reload remains independent #140. Session HTTP remains #149 and must not stack here.

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

Comment thread docs/architecture/ERD.md
- `consent_ledger` and `consent_event` persist the already-merged `src/consent.rs` append-only ledger through `migrations/0005_consent_lifecycle.sql`. Active PR #142 composes those existing rows with `integration_outbox` in one caller-owned transaction after locking the participant ledger, requiring the submitted ledger to contain every durable event identity, and selecting a unique durable tail by occurrence time then `created_at`; it adds no new physical objects. HTTP consent transport and derived snapshot tables remain Target.
- `participant_identity_link` is the persistence target accepted by ADR-0020. The current `src/participant.rs` `keyverse_subject_ref` field is an application-domain first-link projection, not the future mutable persistence source of truth.
- `longitudinal_enrollment`, `longitudinal_observation_record`, and `temporal_analysis_submission` make the ADR-0008 Commons-owned Gyeot/TEPP orchestration boundary explicit. No TEPP analytical kernel is duplicated here.
- `integration_outbox`, `integration_delivery_attempt`, `integration_inbox`, and `integration_consumption` reflect `src/integration.rs` domain semantics. Outbox/inbox/delivery-attempt tables are on protected main; `integration_consumption` pending/processing/completed/quarantined persistence and expire-and-reclaim of a crashed processing claim exist only on this Active PR until merged.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adjacent sentence still says integration_consumption exists only on this Active PR. Protected main already ships migrations/0012_integration_consumption.sql and TRACEABILITY maps that adapter as implemented. Leave it off this consent/outbox head; correct the leftover on a docs-only follow-up after #142 lands.

Protected-main #81 requires claim_deadline_at on processing
integration_consumption rows. Recovery fixtures that omit the column
fail constraint integration_consumption_claim_deadline_shape.
@opencode-agent

opencode-agent Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Scheduled review-feedback autofix for this PR head.

  • Head SHA: 47568be07b2b991715b4e1171037426026e71814

@opencode-agent

Copy link
Copy Markdown
Contributor

Scheduled review-feedback autofix for this PR head.

  • Head SHA: 47568be07b2b991715b4e1171037426026e71814

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority: high type: bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants