feat(research): persist restricted identity linkage - #162
Conversation
Keep operational participants out of public research projections while allowing one person to hold distinct program-scoped research identities. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Add PostgreSQL 18 storage for program-scoped research identities, a public-release view that cannot carry operational or linkage-key fields, and fail-closed exact-replay contracts. Record ISO/IEC 20889 and 27559 in doctoring. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Keep traceability, research governance, risk, and ERD pointing at the opened persistence head instead of an unnamed branch. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Prefer the program-scoped public-view load head over #162. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
There was a problem hiding this comment.
Restricted persist/load and the program-scoped uniqueness contract are sound. Do not merge this head.
A public-release fixture still has to present a restricted linkage_ref and then reconstruct the projection from research_identity_linkage. That is not equivalent to selecting public_research_identity. Padded load identities also trim into a restricted lookup.
Prefer #175. That head adds load_public_research_identities_for_program (SELECT from the public view only) and fails closed on padded persist/load identities. Keep #132 on health transport. Do not stack session start or another linkage persist PR here.
Do not merge until exact-head required checks and independent last-push approval. Never self-approve.
Sent by Cursor Automation: Fix Issues
| linkage_ref: &str, | ||
| ) -> Result<Option<PublicResearchReleaseProjection>, RestrictedIdentityLinkagePersistenceError> { | ||
| let linkage_ref = required_reference(linkage_ref)?; | ||
| let Some(linkage) = load_restricted_identity_linkage(client, linkage_ref)? else { |
There was a problem hiding this comment.
This public helper still reads the restricted table through load_restricted_identity_linkage. A release fixture that may select only public_research_identity cannot call it.
Use load_public_research_identities_for_program on #175. That query selects only the public-view columns, filtered by program, and never takes a restricted linkage_ref.


Superseded
This restricted operational-to-research identity-linkage persistence slice is fully contained in #175. Do not merge this predecessor.
Fresh exact ancestry evidence immediately before closure:
0e9ea4984f874ec68533aeea8b7a4fb035ddb2b1fe18dd486636886f05720283dd0de2c01dc3f921#175 retains the restricted linkage schema/domain/persistence contract and adds a public-release projection/load path that reads only the program-scoped
public_research_identityview plus exact-reference fail-closed guards. #175 remains Draft and subject to unchanged exact-head CI/security/review gates. Closing this PR does not promote successor behavior to protected-main truth.