Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5723218
feat(identity): persist append-only account-link history
cursoragent Aug 16, 2026
93ecaa2
docs(identity): name Active PR #114 on identity-link persistence
cursoragent Aug 16, 2026
2eb0b63
docs(adr): restore ADR-0020 after empty-file commit
cursoragent Aug 16, 2026
070187e
fix(identity): persist unlink and relink in lifecycle order
cursoragent Aug 16, 2026
2f4cfe4
feat(identity): recover participant from current account subject
cursoragent Aug 16, 2026
7ecf481
docs(identity): reserve 0022 for identity-link persistence
cursoragent Aug 16, 2026
729f3c6
chore: stop tracking Rust target artifacts
cursoragent Aug 16, 2026
a1bd393
fix(identity): treat unterminated history as subject source of truth
cursoragent Aug 16, 2026
7b92a66
docs(identity): prefer history-sourced identity-link successor
cursoragent Aug 16, 2026
82b9d95
fix(identity): bind link-end rows to the same participant
cursoragent Aug 16, 2026
1dd1d8b
test(identity): drop duplicate beta participant helper
cursoragent Aug 16, 2026
431eeca
fix(identity): restore current projection on exact replay
cursoragent Aug 16, 2026
0181224
feat(identity): rebuild current projections after restore
cursoragent Aug 16, 2026
2f6470d
docs(identity): name Active PR #158 on restore reconcile
cursoragent Aug 16, 2026
ca7662c
feat(identity): inspect projection drift after restore
cursoragent Aug 16, 2026
a9136d5
docs(identity): name Active PR #169 on restore inspect
cursoragent Aug 16, 2026
b0bdaff
test(identity): free ended subject after inspect and reconcile
cursoragent Aug 16, 2026
9e31ca1
docs(identity): name Active PR #178 on inspect-then-rebind
cursoragent Aug 16, 2026
3641d37
feat(identity): persist dual-proof write after inspect
cursoragent Aug 16, 2026
b8f43a8
docs(identity): name Active PR #192 on inspect-then-write
cursoragent Aug 16, 2026
4b608b5
feat(identity): persist authorized unlink after inspect
cursoragent Aug 16, 2026
f844ddf
docs(identity): name Active PR #202 on authorized unlink
cursoragent Aug 16, 2026
d6f3e93
feat(identity): reject rebound recover after unlink+relink
cursoragent Aug 16, 2026
b68c53f
docs(identity): name Active PR #210 on recover binding
cursoragent Aug 16, 2026
7860bc7
feat(identity): reload history before authorized unlink
cursoragent Aug 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target/
/.netlify
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable product and architecture changes are recorded here. Releases use imm
## Unreleased

### Added
- Hosted recover current-binding and rebound-safe unlink on the identity-link persist line. After `load_participant_by_current_identity_subject`, `accept_recovered_participant_for_authenticated_account` keeps the record only when the reconstructed tenant, issuer, and subject still match the still-valid Keyverse proof. `persist_authorized_account_unlink` reloads stored history before `authorize_account_unlink` so a stale in-memory record or an ended subject's proof cannot end a rebound current binding. HTTP transport and live Keyverse verification remain Target.
- Hosted authorized account unlink on the identity-link persist line. `persist_authorized_account_unlink` requires a still-valid Keyverse account proof that matches the current issuer-scoped subject, appends the link-end without rewriting `participant_ref`, and then returns `None` from `recover_participant_for_authenticated_account` so the same account can relink. Restore drift still blocks new first-links but does not block this disconnect. HTTP transport and live Keyverse verification remain Target.
- Hosted dual-proof account-link write and recover commands on the identity-link persist line. `persist_authorized_account_link` inspects current-projection drift before authorization so a stale unique enforcer cannot accept a new account link; after restore reconcile, a later participant can bind an ended issuer-scoped subject and `recover_participant_for_authenticated_account` returns that same `participant_ref`. HTTP transport and live Keyverse verification remain Target.
- PostgreSQL 18 append-only participant identity-link persistence so a dual-proof account link, unlink, and relink survive process restart without rewriting the product-owned participant reference. Persist applies each link and then its matching ends in one transaction, exact replay is idempotent, and exact replay also restores or clears the derived current projection so operator repair cannot leave a missing or stale unique enforcer. After restore, `inspect_identity_link_current_projection_drift` reports missing or stale unique-enforcer rows without mutating them, and `reconcile_identity_link_current_projections` rebuilds every current row from unterminated history. Both fail-close on two unterminated holders of the same issuer-scoped subject or two unterminated links on one participant. After that inspect-then-reconcile path, an ended issuer-scoped subject can bind to a later participant. Conflicting evidence fails closed, and one unterminated issuer-scoped subject cannot belong to two participants even when the derived current projection is missing. A returning account recovers the same `participant_ref` from that history. A link-end cannot attach to another participant's link.
- Scoring-job cancel and lease-expiry fallback classification lock the current row until the caller transaction ends, so concurrent workers cannot rewrite terminal or unleased evidence.
- PostgreSQL operational-store readiness probe classifies the supported major version and write-readiness, and fails closed when a caller-declared required relation is missing.
- PostgreSQL scoring-job cancellation: queued, leased, or retry-scheduled work becomes cancelled without transferring a fence, exact replay is idempotent, and completed or quarantined evidence cannot be rewritten.
Expand Down
9 changes: 5 additions & 4 deletions docs/OPERABILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,11 @@ For persistence owned by Psychometrics Commons, a GA profile must establish and
3. migration/schema compatibility and expected indexes/constraints;
4. exact digest/provenance consistency for immutable snapshots/artifacts;
5. tenant authorization and restricted-linkage protections after restore;
6. outbox/inbox/job recovery without duplicate domain effects;
7. data-rights and research withdrawal/eligibility state preservation;
8. key/secret dependency recovery without embedding secrets in backup artifacts improperly;
9. measured restore duration and recoverable data point for that exact profile.
6. identity-link unique enforcer inspected with `inspect_identity_link_current_projection_drift` and rebuilt from unterminated history via `reconcile_identity_link_current_projections` before `persist_authorized_account_link` accepts a new dual-proof write, including a later participant binding an ended issuer-scoped subject; `persist_authorized_account_unlink` may still disconnect a returning account from that history while inspect reports drift; recover then keeps the reconstructed participant only when current tenant, issuer, and subject still match the proof;
7. outbox/inbox/job recovery without duplicate domain effects;
8. data-rights and research withdrawal/eligibility state preservation;
9. key/secret dependency recovery without embedding secrets in backup artifacts improperly;
10. measured restore duration and recoverable data point for that exact profile.

The architecture deliberately does **not** publish universal RPO/RTO numbers before these profile-specific measurements exist.

Expand Down
14 changes: 10 additions & 4 deletions docs/TRACEABILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ An active PR, architecture document, conversation decision, or scheduler plan is
| Continuous scores remain source of truth; Personality Style is presentation | PRD §3.2 | Measurement Governance; AI Governance | ADR-0018 | Target product narrative mapping; numeric source remains External fast-mlsirm contract |
| Immutable instrument release/version lifecycle | PRD §6, §9 | TRD §7; UML publication state | ADR-0005, ADR-0010 | **Implemented** in `src/instrument.rs` plus `migrations/0006_instrument_release.sql` and `src/postgres_instrument_release.rs`: immutable release manifest, exact version/digest/locale/item set, fail-closed Draft/Review/Published/Suspended/Retired lifecycle, idempotent publication events, and new-session eligibility |
| Instrument publication requires intended-use scientific/right/locale evidence | PRD §6, §9, §10 | Measurement Governance; publication evidence gate | ADR-0004, ADR-0013, ADR-0019 | **Implemented** policy gate and immutable evidence provenance in `src/instrument.rs`; each real instrument still requires its own rights/locale/scientific evidence artifacts before publication |
| Optional Keyverse account linking | PRD §3.1, §9.7 | TRD §10; UML identity-link lifecycle | ADR-0003, ADR-0020 | **Partially implemented**: issuer-scoped first-link fail-closed domain primitive in `src/participant.rs`; append-only unlink/relink/recovery history, persistence, audit, and transport remain Target |
| Optional Keyverse account linking | PRD §3.1, §9.7 | TRD §10; UML identity-link lifecycle | ADR-0003, ADR-0020 | **Partially implemented**: issuer-scoped first-link fail-closed domain primitive in `src/participant.rs`; **Active PR** #210 persists append-only `participant_identity_link` history, restores the derived current projection on exact replay, inspects projection drift after restore, rebuilds that unique enforcer from unterminated history, frees an ended issuer-scoped subject for a later participant, adds dual-proof write/recover commands that refuse new links while inspect reports drift, persists `persist_authorized_account_unlink` so a returning account can disconnect and later relink, and keeps recover only when the reconstructed current tenant/issuer/subject still match the proof; HTTP/Keyverse token verification remain Target |
| Cross-cutting tenant/task authorization | PRD §7, §9 | TRD §11; Security/Data | ADR-0001, ADR-0003 | **Implemented** fail-closed domain gate in `src/authorization.rs` binds consent operations to participant-owned `ConsentLedger` / `ManageOwnConsent`; persistence/policy-adapter/public-transport integration remains Target |
| Purpose-specific consent | PRD §5, §9.6 | TRD §12 | ADR-0006 | **Implemented** domain contract in `src/consent.rs` plus `migrations/0005_consent_lifecycle.sql` / `src/postgres_consent.rs` purpose-specific ledgers; HTTP transport remains Target |
| Explicit research contribution + withdrawal | PRD §5 | TRD §12, §14–15 | ADR-0006, ADR-0007 | **Implemented** product-domain lifecycle in `src/consent.rs`; dataset snapshot/release integration is Target |
Expand Down Expand Up @@ -66,7 +66,7 @@ An active PR, architecture document, conversation decision, or scheduler plan is
| Only Published release accepts new sessions | TRD §7 | `PublicationState::accepts_new_sessions` in `src/instrument.rs`; `AssessmentSession` creation copies exact published release/version/locale provenance and fails closed on unpublished eligibility or locale mismatch | session-creation persistence/API integration test |
| Publication event replay is idempotent/conflicting reuse fails closed | TRD §7 | `src/instrument.rs` | durable DB uniqueness/concurrency test |
| Published instrument requires exact-version scientific evidence | Measurement Governance; ADR-0019 | `src/instrument.rs` binds approved evidence status, provenance/scope, mandatory evidence references, validity window, and immutable release identity before publication/reactivation | persistence/API publication integration and real instrument-specific evidence artifacts |
| Optional account linking does not rewrite historical participant/result identity | ADR-0003, ADR-0020 | `src/participant.rs` issuer-scoped first-link primitive preserves stable participant ID | append-only identity-link persistence + unlink/relink/recovery audit tests |
| Optional account linking does not rewrite historical participant/result identity | ADR-0003, ADR-0020 | `src/participant.rs` issuer-scoped first-link primitive preserves stable participant ID; **Active PR** #210 `src/postgres_participant_identity_link.rs` persists and reloads that history without rewriting `participant_ref`, inspects projection drift after restore, rebuilds the derived unique enforcer, and frees an ended issuer-scoped subject for a later participant; `src/account_link_write.rs` authorizes both proofs, refuses new links until that inspect is clean, persists an authorized unlink so recovery returns `None` until relink, and rejects a recovered participant whose current binding no longer matches the proof | HTTP unlink/relink transport and live Keyverse verification |
| Sensitive authorization is tenant- and task-bound | TRD §11; Security/Data | `src/authorization.rs` fail-closed authorization context/gates bind consent operations to participant ownership | policy adapter + route/repository integration + cross-tenant E2E tests |
| Research consent separate from service consent | TRD §12; Research Governance | `src/consent.rs` | public API/UI negative test |
| Research withdrawal preserves evidence | TRD §12–15; Research Governance | `src/consent.rs` | release-pipeline exclusion test |
Expand Down Expand Up @@ -102,7 +102,9 @@ src/lib.rs
├── item_delivery.rs # sequence-aware delivery evidence without confidential response data
├── narrative.rs # deterministic Personality Style identity/key
├── participant.rs # stable participant identity + issuer-scoped optional Keyverse account link
├── account_link_write.rs # Active PR dual-proof persist/recover/unlink commands; new links wait for inspect, unlink may proceed from history
├── postgres_consent.rs # PostgreSQL purpose-specific consent ledger persistence
├── postgres_participant_identity_link.rs # Active PR append-only identity-link persist/reload (not protected-main truth)
├── postgres_data_rights.rs # PostgreSQL data-rights request and local propagation persistence
├── postgres_health.rs # PostgreSQL major/write-readiness and relation-integrity probe
├── postgres_inbox_consumption.rs # PostgreSQL inbox consumption distinct from receipt
Expand All @@ -128,11 +130,11 @@ migrations/
└── 0012_integration_consumption.sql
```

Still-Target logical modules/adapters include remaining product aggregate persistence/repositories, public/admin HTTP and event transports, live fast-mlsirm/Keyverse/Gyeot/TEPP/semantic-data-portal adapters, research-release staging, deterministic narrative mapping, longitudinal normalized ingestion, participant identity-link history persistence, runtime health transports/metrics, and Measurement Workbench orchestration.
Still-Target logical modules/adapters include remaining product aggregate persistence/repositories, public/admin HTTP and event transports, live fast-mlsirm/Keyverse/Gyeot/TEPP/semantic-data-portal adapters, research-release staging, deterministic narrative mapping, longitudinal normalized ingestion, runtime health transports/metrics, and Measurement Workbench orchestration.

### Active implementation work that is not protected-main truth

**Active PR** #76 data-rights processing-start persistence is not protected-main truth until an unchanged reviewed/check-clean head is integrated. Identity-verified requests persist an immutable operation identity and processing-start time under `FOR UPDATE` so later lifecycle composition cannot race the classified row. Dependent-system execution remains outside this slice.
**Active PR** #210 participant identity-link persistence is not protected-main truth until an unchanged reviewed/check-clean head is integrated. Prefer #210 over #202, #192, #183, #178, #176, #173, #169, #160, #158, #147, #133, #124, and #114. This head keeps the inspect-then-reconcile persist line and adds `src/account_link_write.rs` so a hosted adapter authorizes both current proofs, refuses new account-link writes while inspect reports drift, persists an authorized unlink from unterminated history, recovers the same `participant_ref` after restart, and keeps that record only when the reconstructed current tenant/issuer/subject still match the proof. `migrations/0022_participant_identity_link.sql` and `src/postgres_participant_identity_link.rs` persist `assessment_participant`, append-only `participant_identity_link` / `participant_identity_link_end` evidence, and a derived `current_participant_identity_link` projection. Persist applies each link and then its matching ends so a complete unlink+relink aggregate can be written in one transaction. Exact replay then restores or clears that derived projection. After restore, `inspect_identity_link_current_projection_drift` reports missing or stale unique-enforcer rows without mutating them, and `reconcile_identity_link_current_projections` rebuilds every current row from unterminated history. Both fail-close on two unterminated holders of the same issuer-scoped subject or two unterminated links on one participant. After that inspect-then-reconcile path, an ended issuer-scoped subject can bind to a later participant. Unterminated issuer-scoped subjects remain the lookup and uniqueness source of truth. HTTP account-link transport and live Keyverse token verification remain outside this slice. Migration `0021` remains reserved for #113 scoring-job health indexes.

## 5. ADR traceability by concern

Expand Down Expand Up @@ -220,6 +222,10 @@ CI should validate linked documentation paths and status/name consistency now an

## 10. References

International Organization for Standardization & International Electrotechnical Commission. (2019). *IT security and privacy—A framework for identity management—Part 1: Terminology and concepts* (ISO/IEC 24760-1:2019).

National Institute of Standards and Technology. (2025). *Digital identity guidelines* (NIST Special Publication 800-63-4). https://doi.org/10.6028/NIST.SP.800-63-4

Nottingham, M., Wilde, E., & Dalal, S. (2023). *Problem Details for HTTP APIs* (RFC 9457). Internet Engineering Task Force. https://doi.org/10.17487/RFC9457

OpenAPI Initiative. (2025). *OpenAPI Specification, Version 3.2.0*.
Expand Down
Loading
Loading