Skip to content

feat(identity): persist dual-proof write and recover on reconcile - #183

Closed
cursor[bot] wants to merge 16 commits into
mainfrom
cursor/bc-017fdf31-3591-455e-abd3-30ec89c183ed-c119
Closed

feat(identity): persist dual-proof write and recover on reconcile#183
cursor[bot] wants to merge 16 commits into
mainfrom
cursor/bc-017fdf31-3591-455e-abd3-30ec89c183ed-c119

Conversation

@cursor

@cursor cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

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 SubjectAlreadyBound after restore. A buyer who unlinked, then signed in again, is told the account is taken.

TDD

RED tests/account_link_write.rs called missing write/recover commands. GREEN authorizes both current proofs, persists history through the #166 reconcile path, and recovers the same participant_ref. RED tests/postgres_account_link_write.rs persisted unlink, reinserted a stale current row, then called persist_authorized_account_link for a second participant. GREEN returns Inserted and 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

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.

Open in Web View Automation 

cursoragent and others added 16 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 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>
@cursor
cursor Bot requested a review from seonghobae August 16, 2026 16:18
@seonghobae
seonghobae marked this pull request as ready for review August 16, 2026 16:20
@cursor

cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

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.

@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

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_link refuses with CurrentProjectionDrift until reconcile_identity_link_current_projections runs, 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, run reconcile_identity_link_current_projections before calling persist_authorized_account_link on the #192 head.

View PR

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.

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_account before any write.
  • Recover calls require_recoverable_account before lookup (now == 0 and expired proof fail closed).
  • Reconcile is the only current-row writer.
  • tests/postgres_account_link_write.rs covers 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.

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.

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.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

Copy link
Copy Markdown
Contributor

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.

@seonghobae seonghobae closed this Aug 16, 2026
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