Skip to content

feat(identity): inspect projection drift after restore - #169

Closed
cursor[bot] wants to merge 16 commits into
mainfrom
cursor/bc-cbe94a96-76d8-484e-98b8-a3784f2dbb0c-c015
Closed

cursor[bot] wants to merge 16 commits into
mainfrom
cursor/bc-cbe94a96-76d8-484e-98b8-a3784f2dbb0c-c015

Conversation

@cursor

@cursor cursor Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Superseded

This read-only current-projection drift inspection slice is fully contained in #178. Do not merge this predecessor.

Fresh exact ancestry evidence immediately before closure:

#178 retains inspect + reconcile behavior and adds the buyer-path proof that an ended subject remains blocked by stale current state until reconcile, then can be rebound and recovered. #178 remains Draft and subject to unchanged exact-head CI/security/review gates. The divergent #173 test branch is not claimed contained by ancestry here. Closing this PR does not promote successor behavior to protected-main truth.

cursoragent and others added 15 commits August 16, 2026 15:25
A buyer who links an anonymous assessment to a Keyverse account must
still see that link after process restart. Persist assessment_participant
plus append-only link and link-end evidence, reload through the domain
lifecycle, and fail closed on conflicting replay or a subject already
bound to another participant.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Keep TRACEABILITY, ADR-0020, ERD, and as-built schema pointing at the
opened persist/reload vehicle instead of an unnamed Active PR.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
The Active PR #114 naming commit stored an empty ADR-0020. Restore the
accepted decision, including the #114 persistence status and APA 7
references, so identity-link governance is not silently deleted.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Apply each identity link and then its matching ends in one transaction so a complete in-memory unlink+relink aggregate survives restart. Cover one-shot persist, exact replay, and subject reuse after unlink.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Add a tenant-scoped current-subject lookup so a returning Keyverse login can find the same product-owned participant after the anonymous session token is gone. Ended or replaced subjects stay unfindable until they are current again.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Renumber the identity-link migration so it does not collide with #113 scoring-job health indexes on 0021. Name Active PR #124 as the merge candidate over #114.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Remove the accidentally committed build tree and ignore /target so later local verification cannot leak compiler outputs into the identity-link successor.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
A missing current_participant_identity_link row no longer hides a
returning Keyverse login or lets another participant bind the same
issuer-scoped subject. Lookup and uniqueness now read append-only
link rows that have no matching end.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Name the Active PR vehicle as the successor of #124 so TRACEABILITY,
ADR-0020, and the as-built schema do not treat projection-only lookup
as the landing contract.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Add a composite foreign key so a link-end or current projection cannot
point at another participant's identity-link row. Name Active PR #133
as the landing vehicle over #124 and #114.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Exact replay of the same identity-link history now reconciles the derived
current projection so operator repair cannot hide a returning login behind
a missing unique enforcer or leave a stale row after unlink. Name Active
PR #133 in TRACEABILITY instead of superseded #124.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
After dump restore the unique enforcer can be missing or stale even
though unterminated history is intact. Rebuild every current row from
that history, fail closed on two unterminated holders of the same
subject, and prefer this successor over #147.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Keep TRACEABILITY, ADR-0020, ERD, and as-built schema pointing at the
opened restore-reconcile vehicle instead of an unnamed successor of #147.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Add a read-only inspect so operators can see missing or stale unique-enforcer rows after dump restore, fail closed on two unterminated links for one participant, and run reconcile only when that inspect reports drift.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
@cursor
cursor Bot requested a review from seonghobae August 16, 2026 16:10
Point TRACEABILITY, ADR-0020, ERD, and the as-built schema at the inspect-and-reconcile landing so writers do not reopen #158 or #133.

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

Verdict

Unique restore-inspect slice is SOUND. Prefer this head (a9136d5) over #158, #147, #133, #124, and #114 for persist + store-wide reconcile + read-only drift inspect. Do not merge this draft until exact-head checks and a non-author last-push approval pass. Do not self-approve. Do not fold HTTP, #160 dual-proof commands, or #166's write-path current-row change into this PR.

What was reviewed

inspect_identity_link_current_projection_drift is read-only: it requires READ COMMITTED, fail-closes through reject_corrupt_unterminated_history (two unterminated holders of one issuer-scoped subject, or two unterminated links on one participant), then counts missing and stale current_participant_identity_link rows with exact five-column equality against unterminated history. The fixture in restore_inspect_reports_missing_and_stale_projections_before_reconcile is a real restore shape (dropped unique enforcer plus a stale ended-link current row) and the expected missing=2 / stale=1 counts match that SQL. After reconcile_identity_link_current_projections, inspect reports zero drift. Isolation and one-participant collision tests are present.

accepts_new_account_link_writes() is a predicate on the inspect result, not a persist write-gate. That is correct for this slice: #158 exact-replay persist remains the per-participant repair, and OPERABILITY already tells operators to inspect then reconcile before accepting new first-inserts. Do not add a global persist refuse here; it would block that exact-replay repair.

Residual (not blocking this slice)

  • Inspect has a dedicated one-participant collision test; the two-subject collision path is covered only through the shared helper used by reconcile. A dedicated inspect test would be nicer but is not a defect.
  • Inspect does not take FOR SHARE/FOR UPDATE. Acceptable for an operator tool after restore. Do not treat it as a concurrent write-gate.
  • #166 remains the write-path stale-current successor (relink/rebind after a leftover ended-link current row). #173 is the rebind-after-reconcile proof. Hosted account-link HTTP must wait until that write path is check-clean; shipping HTTP on this head would still surface “account taken” after restore.

Operator next action

After restore, run inspect_identity_link_current_projection_drift. If it reports drift, run reconcile_identity_link_current_projections before accepting new account-link writes. Keep this PR scoped to inspect. Independent reviewer: approve only an unchanged check-clean head.

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

cursor Bot pushed a commit that referenced this pull request Aug 16, 2026
Point TRACEABILITY, ADR-0020, AS_BUILT, and ERD at #178 so concurrent writers do not treat #173 or #169 as the identity-link landing vehicle.

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.

This is the earlier #158 successor for ADR-0020 Implementation status and restore inspect. Prefer this head over #158 and later #173.

#173's unique lock is restore_reconcile_frees_ended_subject_for_a_new_participant: after unlink, a stale current row for ended keyverse_subject_alpha must return SubjectAlreadyBound until reconcile_identity_link_current_projections runs, then a new participant can bind that account and load_participant_by_current_identity_subject recovers the new participant_ref. Local GREEN 22/22 on PostgreSQL 16 on that branch.

Fold that buyer rebind test into this inspect head. Do not land #173 separately. #166 is a different persist model from #148; do not merge it as if it were this #158-family contract. Do not self-approve.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants