Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable product and architecture changes are recorded here. Releases use imm
## Unreleased

### Added
- 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. Exact replay is idempotent, conflicting evidence fails closed, and one issuer-scoped subject cannot be current on two participants.
- 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
13 changes: 9 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** #114 persists append-only `participant_identity_link` history and reloads it after restart; 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** #114 `src/postgres_participant_identity_link.rs` persists and reloads that history without rewriting `participant_ref` | HTTP unlink/relink transport, live Keyverse verification, and backup/restore evidence |
| 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 @@ -103,6 +103,7 @@ src/lib.rs
├── narrative.rs # deterministic Personality Style identity/key
├── participant.rs # stable participant identity + issuer-scoped optional Keyverse account link
├── 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 +129,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** #114 participant identity-link persistence is not protected-main truth until an unchanged reviewed/check-clean head is integrated. `migrations/0021_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. Reload after restart replays the same history. HTTP account-link transport and live Keyverse token verification remain outside this slice.

## 5. ADR traceability by concern

Expand Down Expand Up @@ -220,6 +221,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
21 changes: 14 additions & 7 deletions docs/adr/0020-append-only-participant-identity-link-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ Active PR #29 (`fix: scope participant account links by identity issuer`) adds t

A nullable current subject link on a participant projection is therefore useful as an application view, but it is insufficient as the future physical persistence model. In-place replacement would lose who linked or unlinked an account, when the relationship changed, why it changed, and which historical sessions/results were valid under which operational identity context. It would also make identity recovery vulnerable to accidental historical rewrites and would encourage coupling product records to an identity-provider object lifecycle.

This ADR is a mixture of current and target state. Protected main provides stable participant identity plus a fail-closed subject-link primitive. PR #29 provides issuer-scoped first-link behavior on an active branch. Append-only persistence, unlink/relink/recovery transport, and operational evidence remain target behavior until corresponding source, migrations, tests, and release evidence are merged.
This ADR is a mixture of current and target state. Protected main provides stable participant identity plus an issuer-scoped fail-closed first-link primitive, including dual-proof authorization at the application boundary. Append-only persistence is Active PR work. HTTP unlink/relink/recovery transport, live Keyverse token verification, and backup/restore evidence remain target behavior until corresponding source, migrations, tests, and release evidence are merged.

### Implementation status

- `IMPLEMENTED_ON_PROTECTED_MAIN`: stable product-owned `participant_ref`; optional first subject link; distinct proof references; exact-replay idempotency; conflicting replay rejection; no silent second link.
- `IMPLEMENTED_ON_ACTIVE_PR`: PR #29 adds opaque `identity_issuer` binding and issuer-aware replay equality to the first-link domain primitive.
- `PLANNED`: append-only identity-link persistence, durable transport, unlink/relink/recovery lifecycle, concurrency arbitration, data-rights execution, backup/restore evidence, and live Keyverse verification.
- `IMPLEMENTED_ON_PROTECTED_MAIN`: stable product-owned `participant_ref`; issuer-scoped first subject link; distinct proof references; exact-replay idempotency; conflicting replay rejection; no silent second link; dual-proof authorization in `src/account_link.rs`.
- `IMPLEMENTED_ON_ACTIVE_PR`: PR #114 adds append-only `participant_identity_link` / `participant_identity_link_end` persistence, derived current-link projection, and restart reload through `src/postgres_participant_identity_link.rs`.
- `PLANNED`: durable HTTP transport, unlink/relink/recovery operator commands, concurrency arbitration beyond the participant row lock, data-rights execution, backup/restore evidence, and live Keyverse verification.

## Decision

Expand Down Expand Up @@ -227,11 +227,18 @@ Any reversal requires a superseding ADR and an explicit migration/rollback or ro

- Product requirements: `docs/PRD.md` anonymous participation, optional account linking, research contribution, and data-rights requirements.
- Technical requirements: `docs/TRD.md` identity, tenant authorization, consent/data-rights, persistence, and integration contracts.
- Protected-main domain evidence: `src/participant.rs` and its contract tests on the protected-main baseline named by `docs/TRACEABILITY.md`; this baseline does not yet bind issuer.
- Active-PR domain evidence: PR #29 adds issuer-scoped first-link validation/storage/replay and remains `IMPLEMENTED_ON_ACTIVE_PR` until merged.
- Protected-main domain evidence: `src/participant.rs`, `src/account_link.rs`, and their contract tests on the protected-main baseline named by `docs/TRACEABILITY.md`.
- Active-PR persistence evidence: PR #114 `migrations/0021_participant_identity_link.sql` and `src/postgres_participant_identity_link.rs` remain `IMPLEMENTED_ON_ACTIVE_PR` until merged.
- Logical data view: `docs/architecture/ERD.md`.
- Behavioral view: `docs/architecture/UML.md`.
- Security/privacy views: `docs/architecture/SECURITY_AND_DATA.md`, `docs/THREAT_MODEL.md`.
- Operations/recovery: ADR-0017 and `docs/OPERABILITY.md`.
- Maturity/status mapping: `docs/TRACEABILITY.md` and `docs/ROADMAP.md`.
- Machine-readable transport and physical-schema artifacts: none claimed until corresponding implementation exists.
- Machine-readable transport artifacts: none claimed until a hosted identity-link API exists.
- Physical-schema artifacts: Active PR `migrations/0021_participant_identity_link.sql` is not protected-main truth.

## 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
11 changes: 11 additions & 0 deletions docs/architecture/AS_BUILT_SCHEMA.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ The protected-main slice persists:

The slice does **not** persist publication-event history, bound scientific evidence records, HTTP publication transport, or session-creation integration. Those remain Target unless separately evidenced on protected main.

## Active PR participant identity-link physical schema

PR #114 adds `migrations/0021_participant_identity_link.sql` and `src/postgres_participant_identity_link.rs`. The slice is **Active PR**, not protected-main truth. It stores:

- immutable `assessment_participant` identity (`participant_ref`, `tenant_ref`, `created_at_unix_ms`);
- append-only `participant_identity_link` rows for accepted dual-proof account links;
- append-only `participant_identity_link_end` rows that end a specific historical link without editing it;
- derived `current_participant_identity_link` projection enforcing one current link per participant and one current issuer-scoped subject per tenant.

Exact replay is idempotent. Conflicting event identity fails closed. Reload reconstructs the domain `ParticipantRecord` so a buyer who linked an anonymous assessment to an account still sees that link after restart. HTTP account-link transport and live Keyverse verification remain Target.

## Logical-to-physical mapping rule

A logical entity is classified as physical only when all of the following exist on the named protected-main baseline:
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/ERD.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ The target ERD deliberately includes several logical entities that are not yet p
- `data_rights_request` and `data_rights_propagation_state` are the first durable export/deletion slice. Physical `migrations/0003_data_rights_propagation.sql` stores requested-state identity plus one local outbox event per dependent system; verification, processing, completion, and dependent-system execution remain Target.
- `item_delivery_event` reflects the already-merged `src/item_delivery.rs` domain primitive; durable persistence/API orchestration is still Target.
- `consent_ledger` and `consent_event` persist the already-merged `src/consent.rs` append-only ledger. Physical persistence is carried by Active PR #49 (`migrations/0005_consent_lifecycle.sql`); HTTP consent transport and derived snapshot tables remain Target.
- `participant_identity_link` is the persistence target accepted by ADR-0020. The current `src/participant.rs` `keyverse_subject_ref` field is an application-domain first-link projection, not the future mutable persistence source of truth.
- `participant_identity_link` is the persistence target accepted by ADR-0020. The current `src/participant.rs` current-link fields are an application-domain first-link projection, not the future mutable persistence source of truth. Active PR #114 `migrations/0021_participant_identity_link.sql` persists append-only link and link-end rows plus a derived current projection; HTTP transport remains Target.
- `longitudinal_enrollment`, `longitudinal_observation_record`, and `temporal_analysis_submission` make the ADR-0008 Commons-owned Gyeot/TEPP orchestration boundary explicit. No TEPP analytical kernel is duplicated here.
- `integration_outbox`, `integration_delivery_attempt`, `integration_inbox`, and `integration_consumption` reflect `src/integration.rs` domain semantics. Outbox/inbox/delivery-attempt tables are on protected main; `integration_consumption` pending/processing/completed/quarantined persistence and expire-and-reclaim of a crashed processing claim exist only on this Active PR until merged.

Expand Down
Loading
Loading