feat(identity): persist dual-proof write and recover on reconcile - #183
feat(identity): persist dual-proof write and recover on reconcile#183cursor[bot] wants to merge 16 commits into
Conversation
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>
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>
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>
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Exact replay after projection loss now rebuilds the derived current row. A BEFORE INSERT trigger advisory-locks the issuer-scoped subject and rejects a second unterminated history row so a returning account still recovers instead of seeing CorruptHistory. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Exact replay now reconciles the derived current row from unterminated history, including deleting a stale projection after unlink. History lookup is indexed, and the unterminated-subject trigger remains the database uniqueness guard. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Incremental current-row writes failed closed when history already had an ended link and a stale projection remained. Reconcile is now the only current-row writer and deletes terminated tenant-scoped current rows before restore so relink and a later bind succeed. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Authorize both current proofs before persist, recover the same participant from a still-valid account, and rebind a freed subject after a leftover ended-link current row. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Stale comment
Review (COMMENT)
Verdict: do not merge this as the identity-link write landing.
This head is the #166 auto-reconcile line plus dual-proof write/recover (
c62de32). It silently clears a stale unique enforcer inside persist, so a hosted write can succeed without an operator inspect.Prefer #192
b8f43a8#192. That successor keeps the #178 inspect-then-reconcile persist line:persist_authorized_account_linkrefuses withCurrentProjectionDriftuntilreconcile_identity_link_current_projectionsruns, then the later participant binds and recovers.Do not merge #183, #166, #160, or #178 in parallel. Do not self-approve.
Operator next action: after restore, run
inspect_identity_link_current_projection_drift. If it reports drift, runreconcile_identity_link_current_projectionsbefore callingpersist_authorized_account_linkon the #192 head.Sent by Cursor Automation: Fix Issues
There was a problem hiding this comment.
Review (c62de32)
This head is the buyer-facing dual-proof write/recover landing. persist_authorized_account_link authorizes both current proofs, then persists only through reconcile. After unlink plus a leftover current row, a second participant’s write returns Inserted and recover binds to that participant. Recover requires a still-valid account proof and does not invent a participant for an unused account.
No psychometric kernels, HTTP transport, or live Keyverse verification were added. That is the correct next gap, not a defect in this slice.
Checks
- Persist calls
link_authenticated_accountbefore any write. - Recover calls
require_recoverable_accountbefore lookup (now == 0and expired proof fail closed). - Reconcile is the only current-row writer.
tests/postgres_account_link_write.rscovers restart+recover, unused recover, first-holder uniqueness, and stale-current rebind.
Queue
Prefer this head over #166, #160, #148, #147, #133, #124, and #114. Do not merge those in parallel.
#192 is a different inspect-then-refuse operator line. Do not land both as the identity-link writer.
This automation cannot approve a PR it authored. Independent last-push approval from seonghobae is still required. Do not merge until exact-head checks on c62de32 are green.
Next product gap: hosted account-link HTTP that passes server-authoritative now as linked_at_unix_ms and calls these commands, not raw persist/load.
Sent by Cursor Automation: Fix Issues
There was a problem hiding this comment.
Review update (c62de32)
This head still matches its own dual-proof + reconcile AC: persist authorizes both current proofs, recover requires a still-valid account proof, and a leftover current row after unlink does not tell the next buyer the account is taken.
It is not the identity-link landing vehicle.
Prefer #206 for write/recover/unlink. Prefer #202 only as the inspect-line unlink. Do not merge #183, #192, #166, or #160 in parallel with #206.
Hosted account-link HTTP is on #215. Do not merge #215 over #206; rebase that adapter after persist files stop racing.
This automation cannot approve a PR it authored. Independent last-push approval is still required. Do not merge until the chosen landing head has green exact-head checks.
Sent by Cursor Automation: Fix Issues
|
Closing as superseded, not merged. Current review history on this exact head already marks it non-landing; the identity-link line has advanced through the current-binding/recover/unlink work (#210) and the hosted persist/recover/unlink HTTP successor (#230). Keeping this older auto-reconcile write branch open would preserve a competing persistence model that the newer line explicitly avoids. Its dual-proof intent remains carried by the later identity path. |


Why
#166 reconciles a leftover current row so persist-time relink and rebind do not fail closed. #160 adds dual-proof persist/recover but is still based on #147, so a hosted write of a freed subject still hits
SubjectAlreadyBoundafter restore. A buyer who unlinked, then signed in again, is told the account is taken.TDD
RED
tests/account_link_write.rscalled missing write/recover commands. GREEN authorizes both current proofs, persists history through the #166 reconcile path, and recovers the sameparticipant_ref. REDtests/postgres_account_link_write.rspersisted unlink, reinserted a stale current row, then calledpersist_authorized_account_linkfor a second participant. GREEN returnsInsertedand recover resolves to that participant.Local GREEN: 3/3
tests/account_link_write.rs, clippy-D warnings, rustdoc. PostgreSQL write tests run in CI.Scope
persist_authorized_account_linkandrecover_participant_for_authenticated_account.Out of scope
Operator next action
Review the dual-proof write/recover commands and the stale-current rebind test. Prefer this head over #166 and #160. Do not merge #166, #160, #148, #147, #133, #124, or #114. Do not merge this PR until exact-head checks and independent last-push approval are satisfied. Never self-approve.