Skip to content

Domain model, bounded contexts and new aggregates

Revised after round-2 review (3 October 2026). This version resolves the DD, V2, PH, RT, NS, AP and VB findings that concern the domain model, under the round-2 resolution brief. The main changes: the evidence aggregate is ReviewerStudyEvidence (study × author scope) rather than one aggregate per answer; the per-project commit sequence is gone; ScreeningOutcome has candidate and final facets with one writer; the reconciliation task is keyed by study × form; duplicate merge is an alias, never a re-key; one Stage aggregate replaces StageSettings plus StageLifecycle; append-only records are ledgers; and the page now carries a context map, an event and command catalogue, a policy catalogue, shared-kernel value objects and a glossary. Every finding's disposition is in the resolution record at the end.

Temporary planning document; planning only. It brings together the domain model the contracts imply: the bounded contexts and their relationships, which aggregates exist today, which the programme introduces, what changes in existing ones, which domain events and commands exist and where they are hosted, and which release introduces each. It is the logical design. Physical storage (documents, collections, indexes) is decided by the storage ADR at the engine freeze F1a (E15), starting from the storage blueprint in review VB §3. Aggregate, collection and policy names are PROPOSALs until the naming ADR at F1a fixes them (§13); user-facing terms are recommendations pending Chris's Batch D answer D3-03.

Companion pages written in the same revision own neighbouring topics and are cited by file name: versioning-model.md (version kinds, compatibility, publication rules, append-only repositories and explicit collection names), consistency-model.md (the commit protocol and transaction table in its §4, idempotency §5, fences and operations §7, derived records §8, durable effects and events §9, ordering and as-of §11) and programme-integration.md (the in-flight programmes).

Labels: OWNER (ledger ID or register §1.11 ID), RECOVERED, PROPOSAL, OPEN (Q-xx), ASSUMPTION (A-xx), CODE-MAIN, CODE-PR. Questions for Chris cite Batch D IDs (D1-xx to D4-xx) from the resolution brief; this page mints none.

Code baseline: file and line references marked CODE-MAIN were re-read on main at de3e98c59 (3 October 2026, 14:47 BST). The round-2 reviews read 0f5c61073; the files cited here were not diffed between the two heads, so a line number taken from a review without re-reading carries the review's ID instead. Anything not checked is marked UNVERIFIED. Domain types live under src/libs/project-management/SyRF.ProjectManagement.Core/Model/; aggregate roots derive from AggregateRoot<TId>; today's collections are named {prefix}{EntityClassName} with pm for project management (docs/architecture/mongodb-reference.md:88), which §10 replaces with an explicit map.

1. Principles for the new boundaries

  1. A consistency boundary is logical; storage is physical. An aggregate names what one command must read consistently and may write with one compare-and-set. It does not say how many documents hold it. The F1a storage ADR decides documents and collections per boundary, within four constraints from VB's blueprint: revisions are never embedded in sessions (SF3/SF5 share them across forms; gold and tasks reference them); the full pin map of a session version lives in its own document, bounded by E28; revisions live in their own collection for the as-of index; Study holds only the projection. (DD-01, VB improvement 1.) PROPOSAL.
  2. Study is the per-study serialisation point. Every canonical command that changes study-scoped evidence or derived state writes that study's Study document in the same transaction: a version bump plus the CanonicalSummary (§5). Two commands on one study conflict on Study; commands on different studies share no hot document. (Brief §1.3; consistency-model §4.)
  3. No per-project document in an interactive transaction. ProjectCommitSequence is deleted. Within a study, order is the Study version plus per-aggregate versions; across a project, as-of reads use a hybrid logical clock stamp carried by every canonical record (consistency-model §11). Definition-level operations that already run under fences (publication phase 1, binding changes, gold-ownership moves) may keep a project-level sequence. The reason is measured: with one shared per-project document in every save, 399 of 1,000 submissions exhausted their retries at ten reviewers (docs/decisions/ADR-019-materialized-statistics-async-point-fold.md, cited by DD-02 and PH-01; UNVERIFIED here). E25 is settled at F1a on M0 evidence. (DD-02, PH-01, VB-12.)
  4. Immutable history, mutable pointers. Versions, revisions, snapshots and ledger entries are append-only; a root holds a current pointer changed by compare-and-set. "Never edited" needs a mechanism, because today's generic save is an upsert replace: append-only repositories, explicit collection names, content digests and an architecture test (versioning-model.md, VB-10). Nothing published is deleted (QD1, SL2, GS1); no TTL index on any canonical collection; drafts are removed only by audited discard (D2-13 covers restore; D2-14 covers erasure).
  5. Every aggregate carries its project ID, except three system-scoped kinds: Publication (bibliographic identity, with the privacy rule in §4.7), SystemQuestionVersion (one immutable record per question, system version and structural digest; VB-11, VA-09) and system-scoped DefinitionTemplates (the CAMARADES-curated catalogue, D2-15 PROPOSAL). System-scoped aggregates are authorised by application role, never by project grants. (DD-25, V2-16, PH-27.)
  6. N-1, and capture rather than ignore. Older binaries tolerate new fields one release before anything writes them, and they capture unknown elements, as Entity already does through [BsonExtraElements] (SyRF.SharedKernel/BaseClasses/Entity.cs:21-22, CODE-MAIN), because Study and Project are replaced as whole documents. New fields never go inside persisted computed collections such as SessionTallies, which are rebuilt on every save. R0 also ships the behavioural floor: legacy getters and the claim pipeline merge the CanonicalSummary, inert until a canonical writer exists. (VB-01, VB-02, RT-07.)
  7. Legacy types are frozen for canonical scopes. A CanonicalScopes marker on Study and Project is checked by legacy aggregate methods and by a composite registered IAggregateWriteGuard (src/libs/mongo/SyRF.Mongo.Common/AggregateWriteGuards.cs:17-20, CODE-MAIN), so a legacy write to a canonical scope is a filter miss on the document the writer already compares-and-sets. pmCanonicalOwnership is the audited registry with a reconciliation check. The legacy embedded model is reached only through the anti-corruption layer LegacyReviewDataAdapter (readers; retired at R7). (DD-05, DD-13, VB-07.)
  8. Append-only facts are ledgers, not aggregates. A record with no invariant beyond "append only, one writer, ordered" is a *Ledger, written by the command or operation that produces the fact and ordered by the per-study version (study-scoped) or the clock stamp. (DD-18.)
  9. Every read model declares its consistency regime. Three coexist: in-transaction projection (Study.CanonicalSummary, a coexistence adapter retired at R7 with the legacy readers in E20's inventory), eventual materialised rows (FEAT-024) and computed-at-read views (queues, agreement, "Who is offered what", readiness). Each carries a freshness marker (a clock stamp or "authoritative"); gates read only authoritative or fence-verified sources. (DD-17, DD-21.)

2. Bounded contexts and context map

The map adopts review DD §3.1 and is frozen at F1a as the first contract ADR (§13). Relationship types: U/D upstream and downstream through a published language; C–S customer and supplier (the supplier accepts amendments from the customer); CF conformist (we adopt the other side's model as is); SK shared kernel (jointly owned types with a joint conformance suite); ACL anti-corruption layer. DD's "Eligibility Results" context is renamed Screening Outcomes here, so that "eligibility" keeps meaning admission (the review eligibility programme's language).

Context Root aggregates and ledgers Owns the language of Relationships
Review Design (definitions) QuestionDefinition, SystemQuestionVersion (system-scoped), AnnotationForm, FormVersionIssue, ScreeningProfile (definition side), ProfileVersionIssue, DefinitionTemplate, OutcomeSchema, EntityType (type side), SharedConcept, ProjectRule question, form, profile, version, issue (the user-facing verb is "publish"), template, compatibility, impact policy U to Evidence, Workflow, Screening Outcomes, Reconciliation and Reporting (published language: version references and compatibility relations). C of FEAT-024 for usage evidence (C8). SK with Classification for EntityTypeId.
Review Workflow (stages) Stage (settings versions, lifecycle, change requests, status history); work-admission decisions (not persisted) stage, step, route, gate, binding, admission, readiness, lifecycle, capacity D of Design. SK with the review eligibility programme (ReviewEligibilityPolicy, the facts → policy → decision pattern, IReviewMembershipFacts, the truth table as conformance suite). C of allocation, presence and claims, and batches (C7). Supplies route and admission evidence to Evidence commands.
Evidence (the engine) ReviewerStudyEvidence (per project × study × author scope), SessionDraft, ExposureLedger answer, revision, session, save, complete, fix, withdraw, draft, lease, provenance, context, exposure D of Design. SK exports: AnswerContextKey, Provenance, ExposureState, AuthorityValue, the claim key (with presence), the command ledger record (its CommandId doubles as FEAT-024's OperationId, correlation only). CF to AF2 as host, through the F1c extension points.
Screening Outcomes ScreeningOutcome, ProfileAdjudication, StudyPoolLedger decision, candidate result, final result, adjudication, pool entry, freshness D of Evidence (decisions) and Design (profile rules). U to Workflow gates (facets own, candidateCollective, final) and to Reporting.
Reconciliation and Accepted Answers ReconciliationTask (with ReconciliationSession, assignments, editor claim), AdditionalReviewRequest, StudyGold, QueryWorkItem (with ConcernResolution) task, candidate, match, accepted (gold), snapshot, concern, resolution, editor claim, held, inputs changed D of Evidence. U to Reporting and Export. CF to the notification stack (C15 v2) and to #3944/#3965 conversations (a clarification channel; StudyConversation moves to this context's lane L6 at R4a).
Classification and Populations AnimalPopulation, EntityType instances (label heads in Evidence), InferenceResult population, cohort, instance, concept, rule, assertion, inference SK EntityTypeId with Design (identities minted at F1a). D of Evidence.
Identification and Deduplication Publication (system-scoped), Citation (immutable record on Study), StudyAlias (on Study), DuplicateReviewItem, DedupAuditLedger, StudyLifecycleLedger, ExternalStepLedger, dedup batch staging citation, record, publication, duplicate, primary and secondary study, source, retrieval, external step CF to FEAT-011 and FEAT-012 with the amendment change policy. S to Reporting. C of the PDF programmes (retrieval events, amendment M) and the deletion-lifecycle programme (withdrawal, D3-12).
Reporting and History PrismaFlowSnapshot, PrismaPhaseMapping, ExportManifest, DataExportJob, AgreementResult (own rebuildable store, D3-11) report (PRISMA flow), manifest, coverage, as-of, watermark, agreement D of everything. Never writes review data.
Membership and Permissions Project (root), groups, grants, delegation envelope, invitations, join requests; DisclosurePolicy member, group, grant, capability, delegation, disclosure, owner CF to authorization #3335 (evaluator, audit, catalogue, membership schema 1). Supplies DisclosurePolicy to every other context and every channel (reads, exports, statistics, notifications, presence). Needs X-AUTH-RESOLVER (#3251) for out-of-request evaluation.
Platform and Coexistence CanonicalEnrolment, CanonicalOwnership (registry) plus per-document CanonicalScopes markers, command ledger records, operation records, LegacyWriteLedger, LegacyIdAlias, compatibility floor enrolment, ownership, scope, floor, operation, fence, lease, generation ACL LegacyReviewDataAdapter toward the legacy embedded model: readers only, writes refused by ownership, retired at R7. Hosts the ADR-020 operation pattern for every context.
Notifications (programme-owned) InboxNotification, NotificationFanOut, NotificationEmailPreferences, NotificationEmailDelivery, NotificationEmailDigest kind, occurrence, recipient, capture (inline, recorded fan-out), digest, halt U programme. Every context is CF to C15 v2; the kind registry is the extension point; one capture service is the only writer.

2.1 In-flight programmes

Details, timing and PR slicing are in programme-integration.md; this table fixes the relationship type the domain model assumes.

Programme Relationship Through
FEAT-024 materialised statistics (ADR-018/019) C–S (we are the customer) A FEAT-024-owned source-write seam with a projection-only shape; new families and scope kinds by FEAT-024 amendment at F2/F5; the engine never writes statistics or pending entries itself; canonical CommandId = OperationId (correlation only); ADR-019 gate (b) shape for the canonical write gate (D1-08)
Proportional allocation (FEAT-025) C–S StageAllocationRegime referenced by ID from StageSettingsVersion; refused on canonical stages until AL1 (D3-13a); regime schema v2 at AL1 with its floor
Progressive batches (#3936/#3939) C–S Batch plan referenced by ID; IStudyObligationEvidence seam; shared opening and personal grant are durable transitions that write StudyPoolLedger (AP-05)
Active reviewer tracking and presence SK (claim identity) Claim contract v2 (§4.11); presence and connection records keyed by form; the draft lease shares the stable tab ID but works with tracking off; X-CLAIMS and X-RECLAIM
Review eligibility programme (paused) SK ReviewEligibilityPolicy extended by WorkAdmissionPolicy; IReviewMembershipFacts extracted now; the generated truth table is the conformance suite (D3-09)
Authorization #3335 CF ProjectAuthorityEvaluator, authorizationAudit, the catalogue, membership schema 1; X-AUTH-RESOLVER
Notification stack (#3932–#3947, #3965) CF C15 v2 capture contract; kind registry; Source sub-document; per-project notification admission as an enrolment scope (NS-04, D3-21)
AF2 and reviewer layouts CF (host) F1c extension points; VersionedAnnotationFormDataSource; Needs-updating presenter; layout-contract amendment; canonical routes never fall back to AF1
PDF programmes (bulk PDF upload, PDF Agent, #3947 checked PDFs, StudyPdfCorrection) C–S Retrieval events for P1 (amendment M); their Study writers are inventoried (NS-08)
Deletion lifecycle (ADR-014) C–S Withdrawal hides Studies but keeps Citations and canonical evidence; whole-project deletion keeps ADR-014's removal with a tombstone that covers the canonical collections (D3-12)
Identity CF Canonical records store opaque investigator GUIDs only; erasure anonymises the Investigator record (D2-14, VB-19)
Study Management (FEAT-018) C–S Library placement for dedup queue, merge wizard and source classification (PH-31); study issues move to this programme (NS-19)

3. Today's domain model

Corrected per V2-15 and RT §5.1. "Where" is the folder under Core/Model/ unless stated; roots at the folder root are called out because the folder-per-aggregate convention does not hold.

Aggregate root (collection) Where (CODE-MAIN) Holds Relevance to this programme
Project (pmProject) ProjectAggregate/Project.cs:25 Embedded AnnotationQuestion list; Stage entities (review mode, grouped configuration, workload shares, allocation pointer, stage security; ProgressiveBatches once #3939 merges); memberships; security settings and groups; invitations; join requests; keywords; agreement thresholds; embedded job records (search import, bulk study update, bulk PDF upload, risk of bias); SystemQuestionVersion Root of Membership and Permissions. Questions and canonical stage settings move out; the four embedded job records stay (A-30)
Study (pmStudy) StudyAggregate/Study.cs:16 Bibliographic data; ScreeningInfo; ExtractionInfo (sessions, annotations, outcome data, computed tallies); SlotReservations (:215; natural key investigator + stage, SlotReservation.cs:12); bulk-update lock; PendingStatistics and StatisticsFoldSequence (:148-162); risk-of-bias info; PDF paths Gains CanonicalSummary, CanonicalScopes, the alias set and the claim set v2 (§5). Its embedded legacy types are frozen for canonical scopes
SystematicSearch (pmSystematicSearch) SystematicSearchAggregate/SystematicSearch.cs:10 Name, description, reference files; NumberOfStudies is computed from the reference files (:42), not a citation count; schema version kept in extra elements (:118-137); living-search link Gains source type and name, withdrawal state, external-step references and, if D4-05 is approved, search documentation fields
Investigator (pmInvestigator) InvestigatorAggregate/Investigator.cs:27 Account and profile Unchanged; erasure extends to canonical records (E32, D2-14)
InvestigatorUsage (pmInvestigatorUsage) InvestigatorUsageAggregate/InvestigatorUsage.cs:9 Usage and favourites Unaffected
InvestigatorEmail (view) InvestigatorEmailsView/InvestigatorEmail.cs:5 Email read model (AggregateRoot<string>) Unaffected
Potential (pmPotential) PotentialAggregate/Potential.cs:7 An invitee keyed by email with invitation IDs Unaffected (NS-25's duplicate invitation mail is the notification programme's)
DataExportJob (pmDataExportJob) DataExportJobAggregate/DataExportJob.cs:26 Export jobs and summaries Previous-version and as-of modes, manifest reference, D11 download ownership
StudyPdfCorrection (pmStudyPdfCorrection) StudyCorrectionAggregate/StudyPdfCorrection.cs:9; repository Mongo.Data/Repositories/StudyCorrectionRepository.cs:12 uses the generic base, so the class-name formula applies PDF correction requests (pending, PDF replaced, original kept); raises StudyPdfCorrectionApprovedEvent A Study writer on approval (PDF path), inventoried for R0. docs/architecture/mongodb-reference.md:103 still lists pmStudyCorrection/StudyCorrection: stale, corrected in the F1a docs PR. "Correction" is reserved in the glossary (§8)
RiskOfBiasAiJob (pmRiskOfBiasAiJob) RiskOfBiasAiJobAggregate/RiskOfBiasAiJob.cs:18 AI risk-of-bias jobs (dormant tool) Writers inventoried
ProjectDailyStat (pmProjectDailyStat) ProjectDailyStatsAggregate/ProjectDailyStat.cs:6 Daily statistics Unaffected
StageAllocationRegime, StageAllocationRegimeTransition (pmStageAllocationRegime, pmStageAllocationRegimeTransition) AllocationRegimeAggregate/StageAllocationRegime.cs:39, StageAllocationRegimeTransition.cs:11 Immutable regime record, transition log, pointer on the embedded Stage, startup compatibility check Referenced by ID from StageSettingsVersion (AL1). The regime pattern (immutable record, transition log, pointer, compatibility check) is the template for settings versions and batch plans
ProjectStatistics family (pmProjectStatistics*) abstract root ProjectStatisticsAggregate/ProjectStatisticsDocument.cs:18; receipts ProjectStatisticsSourceOperationReceipt.cs:20 FEAT-024 rows, source-operation receipts, publication operation, guard, manifest and marker New families by FEAT-024 amendment; FEAT-024 receipts are not the canonical idempotency authority (VB-04; consistency-model §5)
ReviewerPresence (pmReviewerPresence) Model root, ReviewerPresence.cs:24; one current presence per (investigator, stage) (:11); AnnotationSessionId points at the embedded session (:87); kept indefinitely (:8-9) Engagement windows, suspension, dirty marker Gains FormSessionId (additive), a form-keyed current-presence index (create, read both, drop), disclosure-shaped snapshots and a retention rule (E32)
ReviewSessionConnection (pmReviewSessionConnection) Model root, ReviewSessionConnection.cs:15; AggregateRoot<string> keyed by the SignalR connection ID; (study, stage, investigator) index (:12-13); HasStartedAnnotating (:59) Connection to review context, heartbeat, stale-check token Gains the stable client tab ID shared with the draft lease and a form key beside StageId; "dirty" becomes the draft-changes flag
ReviewerWorkspaceSettings (pmReviewerWorkspaceSettings) ReviewerWorkspaceSettingsAggregate/ReviewerWorkspaceSettings.cs:5 Per-reviewer Dockview layouts per capability slot Layout-contract amendment at F1c
BulkPdfUploadReleaseRecord, BulkPdfUploadQuarantineFence, BulkPdfUploadStorageBinding Roots inside ProjectAggregate/ (:13, :7, :11) Bulk PDF upload authority, quarantine and storage records Study writer at finalisation (Study.MarkBulkPdfDelivered, Study.cs:189-206), inventoried; retrieval-event source for P1 (amendment M)
ADR-020 bulk update stores (pmBulkStudyUpdateOperation, pmBulkStudyUpdatePlan in chunks of 100, pmBulkStudyUpdateBeforeImage) Core/Services/BulkStudyUpdate/Atomic/ (not Model/); explicit collection names per mongodb-reference.md:107-109 Operation record (lease, generation, phase, manifest), validated plan chunks, before-images with TTL The operation-record pattern (lease, generation fencing, plan chunks, lock, apply, release) reused for publication phase 2, projection rewrites, adoption cutover and merge/split (§4.9)
M5b risk-of-bias run stores (pmRobRunOperation, pmRobRunBeforeImage) Core/Services/RiskOfBiasAssessment/Atomic/RobRunOperation.cs; store Mongo.Data/RiskOfBias/MongoRobRunStore.cs; names per mongodb-reference.md:110-111 All-or-nothing batch run; ActiveSearch unique partial index serialises runs per search The "one active operation per scope" index reused for one active FormVersionIssue per form
Claim-revocation outbox (pmActivityClaimRevocationOutbox) Core/Services/ReviewEligibility/Revocations/ActivityClaimRevocationIntent.cs:26 (not a root); TTL 7 days on delivered intents (mongodb-reference.md:106) Durable intent for the targeted claim-revoked event The leased, idempotent dispatcher pattern for C19 class (b) effects
pmPublication Planned only (mongodb-reference.md:112) — Introduced by this plan (§4.7)

Embedded, not roots: Stage, AnnotationQuestion, memberships and groups, the four job records, SlotReservation (Entity<Guid>, SlotReservation.cs:23), Screening, AnnotationSession, Annotation, OutcomeData, StudyPendingStatistics.

PR-only (CODE-PR, per notifications integration and review NS): InboxNotification (pmInboxNotification), NotificationEmailPreferences, NotificationEmailDelivery (the delivery ledger), NotificationEmailDigest, ImportNotificationAdmission, StudyConversation, StudyIssue, CheckedPdfProposal with its file record (#3932–#3947, #3965); the progressive batch plan, membership and access collections and Stage.ProgressiveBatches (#3939).

R0 writer inventory. Every root above that writes Study belongs in R0's legacy-writer inventory (migration §1.4): PDF-correction approval, bulk PDF finalisation, ADR-020 bulk update, M5b runs, the FEAT-024 fold, the tracking writers (RT-08), #3945 study issues and #3947 checked PDFs (NS-08), and every UpdateMany on pmStudy. Mongo.Data.Tests/StudyWriteLockArchitectureTests.cs:81-90 already names UpdateStudyInclusionInfoForProjectAsync and RemoveAnnotationsFromStudiesInProjectForQuestionAsync among the known writers (CODE-MAIN).

4. New aggregates and ledgers by context

Release columns use the integrated plan's names. Collection names are the explicit map in §10, not class names.

4.1 Evidence

Aggregate, entity or ledger Key and contents Key invariants Introduced
ReviewerStudyEvidence (one logical aggregate; physically pmFormSession, pmFormSessionVersion, pmAnnotationHead, pmAnnotationRevision per VB's blueprint) Key (project, study, author scope). Author scope is candidate(investigatorId) here; the reconciled scope's heads belong to StudyGold (§4.3) and the imported scope (D4-14) and policyDerived provenance are revision attributes, not scopes. Entities: FormSession (deterministic ID from (project, study, form, author); status derived from the latest explicit version; presentation state in a separate per-session document); FormSessionVersion (Save, Complete, Fix, Withdraw or policy-derived; pinned form version seq; full pin map in its own document; route stage and step; exposure state; the (ProjectId, CommandId) unique key makes it the command ledger record); AnnotationHead (context key plus contextKeyHash; kind: ordinary answer, screening decision, decision-owned answer, later classification assertion and observation; current revision pointer; Conflicted state for adopted duplicates); AnnotationRevision (immutable typed payload, question version reference with AuthoredUnder = Unknown allowed, parentRevisionRef and owningParent edges, provenance, clock stamp, command ID, real actor, content digest) One head per context per author scope (local). Current pointers change by CAS on the aggregate version. A version pinned by gold or a task is never deleted (the one cross-aggregate read, at withdraw). Session effective state is derived on read from (latest explicit version, its pin map, current published version, recorded policies, per-answer validity); never stored as a flag (D2-01). Publication writes no evidence except Q-34 option mapping, which writes policy-derived revisions with provenance. A Save under a superseded form version is pinned to the version its client declared, never rebased. SF3/SF5 sharing and SF1 reuse are intra-aggregate. PROPOSAL (DD-01) R2a (one stage), R2b (several stages), R2d (cross-form sharing), R3a (screening decisions)
ProfileSession (entity of ReviewerStudyEvidence) Key (project, study, profile, author), deterministic ID; versions are decision submissions (DP3), with the same Save/Complete/withdraw mechanics as FormSession; the decision head and its decision-owned answers hang off it Gives screening-only steps a session and draft container (V2-18). The shape is fixed at F3 (routing) and F5 (profiles). PROPOSAL R3a (default profile), R3b
SessionDraft (pmSessionDraft) Key = session ID (form session, profile session, or the task's reconciliation session); base explicit version; content stored as patches against the base; lease (holder's stable tab ID, etag, per-holder write sequence, heartbeat); bounded conflict copies retained N days; audited discard record; size cap tied to E28 One draft per session, CAS against the base. A non-holder's edits become a conflict copy ("keeps both" is literal, AC-R2a-06). "Take over editing" transfers the lease (D2-08). Save and Complete present the draft etag and consume the draft atomically. A stale autosave arriving after a newer explicit version is rejected. A duplicate write sequence is success. Never written in a Study transaction. No TTL; retention only by audited discard. Whether a draft holds the reviewer's place: D2-07 (recommended middle ground). PROPOSAL (DC-07, VA-12, VB-15, RT-10) R2a
ExposureLedger (pmExposureLedger) Append-only: session version, revision or thread shown, kind (acceptedRevisionShown, questionedInReconciliation per NS-06), time, clock stamp Deduplicated per (session version, revision). A lost report never turns informed work into independent work (C3). Exposure arrives in the draft, Save and Complete REST payloads, never over the presence hub (RT-26). The questioned kind is looked up by session from #3965's record R4a

4.2 Screening Outcomes

Aggregate or ledger Key and contents Key invariants Introduced
ScreeningOutcome (pmScreeningOutcome) Key (study, profile), deterministic ID. Current value object ScreeningOutcomeValue {candidateResult, voteCounts, ruleVersion, finalResult, finalSource, adjudicationRef?, freshness}; the DefinitionVersionVector it was evaluated under; append-only history entries with clock stamps One writer: CollectiveOutcomePolicy, invoked by the submit, correction, adjudication and sweep commands. Candidate and final facets are separate; every reader names the facet it gates on (own, candidateCollective, final). A rebuildable projection with a parity fixture (VA-20). Readers compare vectors; admission fails closed on a stale vector; predicate-driven sweeps repeat until clean (DC-08). A collective Excluded stays Excluded despite extra extraction (PR1). Authority values per amendment H. The current value is projected into Study.CanonicalSummary.screeningOutcomes[] (FEAT-011's stored name, one array; the summary element is ScreeningOutcomeSummary, V2-17). PROPOSAL (DD-06; shape at F1a, frozen with amendment H at F3) R3a (default profile), R3b (profiles), R4p (adjudicated final)
ProfileAdjudication (pmProfileAdjudication) Key (study, profile), deterministic ID; immutable **AdjudicationVersion**s (decision, must-agree supporting answers, reasons, rationale, the input vector it applied to, adjudicator, clock stamp); current pointer Versioned (V2-18; principle 4). An adjudication whose input vector has been superseded by a DP2 correction is inapplicable to the new vector and the outcome falls back to the candidate facet until re-adjudicated (RECOVERED: the 25 September precedence rule, confirmed in screening-specialised-annotation-research.md:818-823) R4p
StudyPoolLedger (pmStudyPoolLedger) Append-only: study, stage, profile, filter-element version, release kind (sharedBatchOpened, personalGrant, importIntoActiveStage, stageOrFilterChange, dedupReversal, returnFromRetrieval), regime or batch plan ID, clock stamp Written only by the command or operation that releases the study (durable batch opening and personal grant per AP-05; D3-13e records shared-open and personal-grant separately). Never edited. Feeds amendment A's "entering screening" and PRISMA boxes 4 and 8. Legacy capture from R2a (E26) feeds the same ledger with coverage labels R3a

4.3 Reconciliation and accepted answers

Aggregate, entity or ledger Key and contents Key invariants Introduced
ReconciliationTask (pmReconciliationTask) Key (study, form), deterministic ID (RE4). State: pinned form version seq and the pinned candidate session versions (state, not key); drift state (open, inputsChanged, held, completed); match set with pairing history; ReconciliationSession entity (authority scope reconciled, current holder, versions Save and Complete, drafts through SessionDraft keyed by the task); editor claim (holder, lease expiry, generation; the X-RECLAIM claim); ReconciliationAssignment entities (assignee, expiry for unstarted work only, started, released, reacquired, audit, ExpiryWarningIssuedAt scheduler marker); audited admin release One task per study × form; versions are recorded, never keyed, so a publication that makes candidates incompatible puts the task into inputsChanged and PublicationImpactPolicy decides which candidates still qualify (DD-07, Q-D2 closed by RE4). Every qualifying candidate takes part (SF4). A reconciler is never a candidate on the same study (Q-36 default). Drift never retracts gold. Target-1 forms create no task (Q-29, PROPOSAL). "Started" means the reconciliation session has a draft or an explicit version. Only the assignee can claim an assigned task; admin release revokes the editor claim through the outbox; editor-lease expiry never expires a started assignment (RT-01, RT §5.2). The editor claim works with tracking off R4a
AdditionalReviewRequest (pmAdditionalReviewRequest) Task, requested reviewer, status (requested, returned, withdrawn, expired), returned session; a single-use scoped admission (study × form × reviewer) recorded as a requestedReview claim on Study Lets exactly that reviewer past pool, bucket and capacity filters (AP-03, D3-13c); provenance on the resulting session; never sets gold or changes the target (RA5); excluded from conversations until returned (Q-N9, recorded in the register) R4a
StudyGold (pmStudyGold; snapshots pmGoldSnapshot) Key study, deterministic ID. Reconciled-scope **AnnotationHead**s and **AnnotationRevision**s (authority reconciled); immutable **GoldSnapshot**s referencing exact revisions (outcome-series gold from R4c); current pointer; pending-query flags; re-reconciliation flag on publication drift (VA-11) Snapshots are immutable; a new snapshot keeps unchanged references; the pointer changes by CAS. Shared-question gold has one owner, which is local because all reconciled heads of a study live here: the first task to publish owns it; a second task on an overlapping form sees it prefilled as accepted and may revise it with a new snapshot carrying provenance (D2-09, PROPOSAL). Verified is an authority value from extract-and-verify (D4-03) R4a; series at R4c
QueryWorkItem (pmQueryWorkItem) Key accepted-answer version; Concern entities (raiser, proposed correction, explanation) each with a ConcernResolution (outcome: accepted, rejected, addressedByUpdate, openForApplicabilityReview; explanation optional; resolver; audited self-review); status; child-resolution tracking; queryEditor claim Gold stays effective with a pending flag; per-concern outcomes; children resolved before a replacement snapshot; QY8/QY9 closure. Query review uses the same editor-claim mechanism as tasks (AC-R4b-09). "Outcome" is never used for a concern (DD-11) R4b

4.4 Review Workflow

Aggregate Key and contents Key invariants Introduced
Stage (pmReviewStage; versions pmStageSettingsVersion) for canonical projects Key = the stage ID already embedded in Project (which keeps name, order, navigation and security grants, referenced by stage ID). Immutable **StageSettingsVersion**s: bound form and profile versions (PV2, D2-04), steps with dependency edges and AND/OR groups, compulsory, handoff and terminal scope, collective satisfaction, extra-vote admission, route policies (DP6/DP7, Q-15), VS1, BL1 and EW1 defaults with per-step overrides, the filter element (FEAT-008 filter-set schema decided at F3), the optional capacity cap (D3-17), tracking setting (D3-18), idle timeout, assignment-expiry default (RA3), and references to the allocation regime and the batch plan by ID; current settings pointer; lifecycle status (Draft, Active, Completing, Completed) and mode (automatic or manual); StageChangeRequest entities (pending, approved, declined); status history Versions immutable; dependency cycles rejected; Active is derived from status, never a separate switch. A Completed stage refuses settings publication except through an approved change request, re-checked at commit (RX2, LC1; flow per Q-02). Completion is two-step: Completing fence, drain, verify, Completed (DC-09); completion withdraws that stage's claim references through the outbox, a claim surviving if another bound stage still uses it (RT-18). Lifecycle mode has one owner, the lifecycle part, not the settings version (V2-17). The regime and batch-plan records stay in their own collections; embedded Project.Stage.WorkloadShares and ProgressiveBatches are legacy-only (AP-11). PROPOSAL at F3 (DD-09) R2a (minimal binding), R3a (steps), R3c (lifecycle)

Placement of today's per-stage settings (PH-05, RT-12, D3-18; PROPOSAL at F3):

Existing setting Owner under shared forms Rule when stages bound to one form differ
Session count target (SessionCountTarget, #3732 override) Form (requirement part, SF2); #3732 override legacy-only n/a (one form target)
Target enforcement (EnforceAnnotationTarget) Stage route policy as an optional capacity cap (D3-17), off by default Most restrictive bound stage sets the cap
In-progress limit (MaxInProgress) Stage in use The stage being used sets it; a shared session counts once
Idle timeout Stage Most restrictive bound stage
Hide excluded studies; excluded progress grouping Stage display settings, as a sub-setting of EW1 (D3-09, eligibility D8 mapping) Per route
Self-reconciliation (AllowSelfReconciliation, no writer today) Project authority policy, not the stage (Q-36) n/a
Search and partition filters The filter element of the settings version; legacy PartitionSet and the study-partitions route retired (AP-20) Per stage (each stage has its own pool)
Tracking (#3876) Binding-scope setting (D3-16a) Tracked if any bound stage is
Category guidance Stage presentation text, never evidence (A-15) Per route
Blinding (BL1), VS1, EW1 Stage, with step overrides BL1 most restrictive; EW1 and VS1 per route (Q-28)
Assignment expiry default (RA3) Stage Per the stage the assignment was made through
Allocation regime, batch plan Their own aggregates, referenced by ID One plan per shared form (AL1); refuse allocation on canonical stages until AL1 (D3-13a)

4.5 Review Design

Aggregate Key and contents Key invariants Introduced
QuestionDefinition (pmQuestionDefinition; versions pmQuestionDefinitionVersion) _id record GUID; unique (project, questionId) so system question IDs can repeat across projects (VB-11). Identity: parent, definitionOwner (project or profile), entity type identity (EntityTypeId, minted at F1a). Status (draft, published, retired). Immutable **QuestionDefinitionVersion**s: wording, options with option identity (VA-05), help, validators, conditions, response modes and metadata (PH-06), data type and multiplicity, "Why it changed", "What reviewers need to do differently", the compatibility relation to the prior version declared at commit (D2-02), structural digest Parent and owner never change (D38); a data-type or multiplicity change is an incompatible version of the same identity rather than a new identity (D2-03, PROPOSAL); compatibility is immutable once any answer pins the version; FV4 revises policy, never compatibility; QD1 (published questions are retired, never deleted; drafts may be deleted); a profile-owned question belongs to exactly one profile (DP4) R2a; profile-owned R3b
SystemQuestionVersion (pmSystemQuestionVersion, system-scoped) Key (questionId, SystemQuestionVersion, structural digest); immutable snapshot of the code-defined question at that version and code revision (E24) A project pins a system version only by publishing a form version that references it (D2-06); form versions never pin live code R2a
AnnotationForm (pmAnnotationForm; versions pmAnnotationFormVersion) Key (project, formId). Head: current published seq, publication seq, policy generation. Immutable **AnnotationFormVersion**s (the requirement part): ordered question-version references including ancestors, requiredness, minimum target. Operational settings record (audited, not pinned by sessions; D2-05 PROPOSAL): compare settings, gold-completeness policy, guidance, response-collection options A version in use never changes (FV1). One active issue per form (D2-11). AF2 renderability is validated at publication; canonical routes never fall back to AF1 (VB-08). A size ceiling applies until the tiered benchmarks prove larger forms safe (D2-16; E28 in pins and bytes). Until R2d, two forms cannot share an answerable question (A-19) R2a
FormVersionIssue (pmFormVersionIssue; chunks pmFormVersionIssueChunk) The publication operation ("publish" stays the user-facing verb). Form, issued version seq, recorded policy (per-question requireReanswer/autoUpdate/doNothing, per-category treatment, option mapping only if Q-34 approves), policy generation (FV4 revisions CAS it), phase (recorded, applying, applied, stalled), ADR-020 fields (lease, generation, cursor, chunks), the impact manifest built after commit as an audit and preview snapshot, the preview digest re-checked before phase 1, the notice fan-out intent Phase 1 is O(1): fence, drain, CAS the form head, write the policy and operation records in one short transaction. Phase 2 is a predicate-driven projection rewrite (pinnedFormVersionSeq < current ∧ appliedPolicyOp < op) that repeats until it matches nothing; admission and readiness for the form pause while it runs (D2-10) and fail closed on a stale projection. Writes no evidence (D2-01). Categories follow FEAT-001 breaking transitivity and FEAT-003 per-session categories (PH-18) R2c
ScreeningProfile (pmScreeningProfile; versions pmScreeningProfileVersion) Key (project, profileId). Immutable versions: eligibility question-version references, decision rules (including Unsure/Maybe at title and abstract, D4-01; primary exclusion reason as the first failing criterion in configured order, D4-13), agreement and resolution routes (including the discussion route, D4-02), must-agree supporting answers (RX1). Operational settings (D2-05): DP5 toggle, rationale setting (Q-32), keyword lists if profile-owned (PH-28, decided at F5). PRISMA phase lives in PrismaPhaseMapping (§4.8) Templates are copied, never linked (DP4, SET1). Profile versions publish through ProfileVersionIssue as Q-26 decides. Re-publication that changes eligibility requires an amendment entry (D4-05) R3a (one default compatibility profile), R3b
ProfileVersionIssue (pmProfileVersionIssue) As FormVersionIssue, for profile versions and the decisions cast under earlier versions As above; treatment per Q-26 R3b
DefinitionTemplate (pmDefinitionTemplate) Template ID; scope: system (CAMARADES-curated catalogue, administered by an application role) or project (copy from a project the user administers); kind (question set, profile, form, entity type per TC1, outcome schema); versions; a copy record (target project, source template and version, time) kept on the template A copy never changes when its template does. Project-scoped templates carry a project ID; system-scoped ones are the third exception to principle 5 (D2-15, PROPOSAL; Q-D1, PH-27). R1a records copy provenance on the template's own copy record, so R1a adds no field to Project before R0's floor (V2-16) R1a (question templates), R3b (profiles), C1 (entity types), O1 (schemas)
OutcomeSchema (pmOutcomeSchema) Project-owned schema versions (series and observation fields with roles, types, validators, cardinality). Supplied schemas (legacy-compatible, event-count) are system-scoped templates copied into the project Published versions immutable; forms pin allowed versions (OC1, C14) O1
EntityType (pmEntityType) Project; capabilities (classifies animals, structured subsets); numbered child questions; legacy category alias; TC1 templates Identity is minted at F1a as a shared-kernel EntityTypeId for the seven legacy categories plus cohort, outcome measure and experiment; the aggregate with capabilities and project-defined types arrives at C1 without re-identifying anything (DD-12) identities F1a; aggregate C1
SharedConcept (pmSharedConcept), ProjectRule (pmProjectRule) Concept definitions; versioned rules linking concepts Defined once; paper-specific mappings are answers; rules publish under the Design capability (Q-19) C1

4.6 Classification and populations

Aggregate Key and contents Key invariants Introduced
AnimalPopulation (pmAnimalPopulation) Study; population with its whole-population cohort; instance membership Every instance belongs to exactly one population. The default whole-study population needs no document: its ID is derived deterministically from the study ID and every answer carries it from the first canonical write (C2), so enabling classification never re-keys answers; the aggregate is created only when C1 enables classification for the project (DD-24) C1
Entity instances Not an aggregate: an instance's identity is its label head's ID in the author's scope, minted once; rename is a new label revision; delete is a set of withdrawal revisions on the label head and its descendants in one commit; duplicate mints new IDs with copiedFrom provenance; population membership is an instance attribute (VB-09, versioning-model.md) — R2a
InferenceResult (pmInferenceResult, derived) Study and population; suggested inferred cohorts, proofs, withdrawals Rebuildable projection; never authoritative; never written back as a reported answer C2

4.7 Identification and deduplication

Aggregate, record or ledger Key and contents Key invariants Introduced
Publication (pmPublication, system-scoped) DOI and PMID unique sparse; canonical bibliographic fields with per-field provenance (source project and citation); linkedProjectIds Bibliographic data only, never review data (L.6). Privacy rule: reading a Publication never exposes project or citation IDs from projects the caller cannot access; another project's enrichment is visible only as values. Cross-project enrichment is a PublicationEnriched fact with a clock stamp, so as-of exports cover what another project displayed (V2-03). Created at P1 from DOI/PMID at import, or linked later by a separate link record (amendment N) P1 or P2 per amendment N
Citation (immutable record on Study.citations[]) FEAT-011's fields; publicationId nullable until linked (amendment N) Never modified after creation; linking never rewrites a Citation. Whether Citations move to their own collection for size is decided before P1 P1
StudyAlias (set on the primary Study) and Study.mergedInto (on each secondary) Alias entries: secondary study ID, merge operation ID, provenance A merge never re-keys immutable records: nothing under the secondary study changes. Reads, candidate selection, statistics and PRISMA resolve aliases through AliasResolutionPolicy; ContributionQualificationPolicy counts a reviewer once across aliased studies; when one reviewer reviewed both, the resolution chooses the current session and supersedes the other with provenance. Merge and split are ADR-020 operations writing both Study documents and refusing busy studies (claims, drafts or open tasks). Split removes the alias and re-derives. FEAT-012's "canonical Study" is "primary Study" (amendment L). Presentation: D2-12 (DD-08, V2-02) P2
DuplicateReviewItem (pmDuplicateReviewItem) FEAT-012's review queue item: the pair, scores, review summaries, decision Studies with review data are never merged automatically (amendment D) P2
DedupAuditLedger (pmDedupAuditLedger) Every dedup decision with confidence, source, actor, time, reversibility FEAT-012 §10.2 offers embedding or a separate pmDedupAuditLog; this plan takes the separate collection under the ledger convention, recorded in amendment L P2
Dedup batch staging (pmDedupBatch) FEAT-012 §5's staging document with a 7-day TTL Kept as specified: transient staging that holds no evidence, so the no-TTL rule for canonical collections does not apply (V2-17) P2
ExternalStepLedger (pmExternalStepLedger) Project, optional search or source; step type, PRISMA fields, count, timing, tool, evidence, author; supersedes Append-only; a correction supersedes and keeps history (amendment K); box 1 from previous-review counts only if D4-11 approves P1
StudyLifecycleLedger (pmStudyLifecycleLedger) Append-only lifecycle and retrieval events: Sought, Retrieved, NotRetrieved with reasons (amendment M, D4-07; a PDF attachment only suggests Retrieved), lifecycle transitions, PublicationLinked, accepted bibliographic corrections (NS-08), SearchWithdrawn Never edited; feeds as-of PRISMA counts; Study.lifecycleStatus and retrieval status are the current projection P1
Report-to-study link (amendment O, if D4-08) A ReportLink record on Study (report identity, linked at, by) Linking never merges extraction F-P decision

4.8 Reporting and history

Aggregate Key and contents Key invariants Introduced
PrismaPhaseMapping (pmPrismaPhaseMapping) Project; versions mapping each profile to a PRISMA phase (title and abstract, full text, not reported) Project-level because it defines the set of required profiles; the profile editor is only its UI (DD-20). StudyLifecyclePolicy reads it R3b
PrismaFlowSnapshot (pmPrismaFlowSnapshot) Frozen report with manifest (computed and reported parts, definitions, versions, coverage, digests) Frozen; amendments append; never from FEAT-024 rows (MS-11) R5b
ExportManifest (pmExportManifest) Export basis, watermark (clock stamp and bounds), definitions, versions, content digests, per-dataset coverage, erasure record (D2-14) Append-only; two exports at one watermark are identical (a checksum comparison). Whether manifests are stored or regenerated is the C11 ADR's choice; this page assumes stored (PROPOSAL) R2a (version exports), R5a
AgreementResult (pmAgreementResult, derived) Per form and study set: the approved method's figures, independent and informed split, denominators Own rebuildable store, outside FEAT-024 (D3-11) R5c

4.9 Platform and coexistence

Aggregate or record Key and contents Key invariants Introduced
CanonicalEnrolment (pmCanonicalEnrolment; was ProjectAdmission) Project; admitted scope kinds (annotation forms, screening profiles, notifications per NS-04 and D3-21, AF2 per-project admission routed through P7 targeting keyed to enrolment, PH-14); the rule that applied (creator opt-in, environment); audit Changing enrolment never changes ownership. The single per-project enrolment mechanism for pilots, the setup wizard and flag targeting R0
CanonicalOwnership (pmCanonicalOwnership) and the CanonicalScopes marker Registry per (project, scope) with the owner, cutover operation and operator; the marker is a set of scope references on Study and Project The registry is audited; a reconciliation check compares it with the markers. Legacy writers include CanonicalScopes in the write filter they already use (filter miss = refusal, no extra read, no transaction needed; DD-13); direct writers go through the composite IAggregateWriteGuard; project-wide pre-checks mirror ThrowIfBulkUpdateInProgressAsync. Cutover uses ADR-020's lock, verify, stamp, release protocol; AC-R6-05 is all-or-nothing via locks (VB-07) R0
Command ledger record Not a collection of its own: each canonical command's immutable output record (FormSessionVersion, decision revision batch, FormVersionIssue, GoldSnapshot, adjudication version, operation record) carries a unique (ProjectId, CommandId), the request digest and the result IDs (consistency-model §5) Retries read it first; a different digest under the same ID is a typed 409; an indeterminate commit returns "outcome unknown". Commands without an immutable output (claim acquisition and release, draft writes) are idempotent by construction (natural key; duplicate write sequence = success). Inbox SourceIds derive from the CommandId. Retention ≥ the client retry horizon (proposal 7 days) R2a
Operation records (pmCanonicalOperation; chunks pmCanonicalOperationChunk) ADR-020-shaped records: kind (issue phase 2, projection rewrite, adoption cutover, merge, split, stage completion drain, outcome sweep), lease, generation, phase, cursor, counts, manifest reference One active per scope through a unique partial index. One record family with a kind field, or one collection per kind: the F1a storage ADR decides (PROPOSAL: one family). See consistency-model §7 R2c onwards
LegacyWriteLedger (pmLegacyWriteLedger; was HistoryCapture) Append-only capture of legacy-path writes in admitted projects: screening from R2a, pool entry from R3a, retrieval and lifecycle from P1 (E26) Captured in the same transaction where the writer is transactional, otherwise into a bounded Study-embedded log moved out by a worker (VB-14); every legacy screening writer named in AC-R2a-17 R2a
LegacyIdAlias (pmLegacyIdAlias) Legacy session and annotation IDs mapped to canonical IDs at adoption Used by #3944/#3945 remapping and exports (VB-13) R6

4.10 Notifications (programme-owned; listed for the model)

Record Change this programme needs Owner
InboxNotification Additive generic Source sub-document (type, IDs, stage list, task ID); server-provided label, context lines, typed availability and workflow state; row ID = SHA-256(SourceId, recipient); ResolvedAtUtc if D3-23 is approved; kinds registered through the kind registry (NS-03, NS-12) Notification programme
NotificationFanOut (pmNotificationFanOut) Durable intent written in the source transaction (occurrence, selector: a frozen recipient list or a capability evaluated at expansion, progress, lease); a leased idempotent expander writes rows in batches. C19 class (b) for notifications; "no outbox" becomes "no second notification store; durable intents are part of C15; in-memory outboxes stay forbidden" (NS-01) Notification programme; L2 consumes
NotificationEmailPreferences, NotificationEmailDelivery (ledger), NotificationEmailDigest, ImportNotificationAdmission Tolerant preferences (unknown keys kept, missing = off), kind-to-category map, delivery halt, retention (E32) Notification programme
StudyConversation One-to-one threads; completed sessions only; an exposure record looked up by session (feeds ExposureLedger's questionedInReconciliation); read-only context link; refuses canonical scopes through the ownership record until R4a; bound to ReconciliationTask identity at R4a; an audit record kept while the project exists (D3-25). Ownership moves to L6 at R4a (NS-19) Notification programme, then L6
StudyIssue, CheckedPdfProposal Study-attention features, not notifications: issues move to Study Management, checked PDFs to the PDF programme (NS-19); recipients by capability (NS-20); issues never carry answer disputes after R4b (NS-24); their Study writers are inventoried (NS-08) Study Management; PDF programme

4.11 Claims (claim contract v2, frozen at F1a)

Element Content
Claim value object {kind, scopeId, routeStage, routeStep, reservedAt, allocationRegimeId, leaseExpiry, holders}; kind ∈ {formSlot, profileSlot, requestedReview, taskEditor, queryEditor}; unique per (study, kind, scope, reviewer); keyed by form or profile identity, never by version; released when the last page using it ends (two stage tabs reuse one claim); an absolute lease expiry that guards treat as free once passed, or a bounded backstop sweep behind its own flag (RT-24)
Capacity claims (formSlot, profileSlot, requestedReview) Live on Study (Study.Claims, beside legacy SlotReservations, which stay for legacy scopes) so the atomic capacity guard keeps working; written and released inside the canonical transaction (first explicit Save or Complete releases the slot claim and replaces presence exactly once); released on completion, revocation and target reduction through the outbox (RT-18 to RT-20)
Editor claims (taskEditor, queryEditor) Live on their own aggregates (ReconciliationTask, QueryWorkItem): CAS plus lease; atomic "Start reconciling"; work with tracking off (X-RECLAIM)
Which sessions hold a place A draft-backed claim while the reviewer is active under today's idle and disconnect timers counting draft activity (D2-07, recommended); saved incomplete; completed; Needs updating. Withdrawal frees the place. The optional capacity cap is separate from the form's minimum target and never limits requested extra reviews (D3-17). No place is held on a dependent form while still screening; the claim is taken at Include (D3-19)
Disclosure Presence is a disclosure channel (C10): non-holders see counts and their own claim; names need the Monitor capability; never across BL1 (D3-20)
Production route Claims and capacity guards exist today only when activeReviewerTrackingEnabled is effective, which is off in every deployed environment; the production route is D3-16 (recommended: #3876 as a binding-scope setting enabled per enrolled pilot); X-CLAIMS is jointly owned by the presence and FEAT-024 owners

5. Changes to existing aggregates

Aggregate Change Release
Project Explicitly the root of Membership and Permissions, conformist to #3335 membership schema 1 (its WP-M2 renames Registrations to Memberships and CustomProjectRoles to CustomProjectGroups inside the document, per the authorization handover plan cited by DD-16; UNVERIFIED here). For canonical projects, questions live in QuestionDefinition and canonical stage settings and lifecycle in the Stage aggregate; the embedded Stage entity keeps identity, name, order, navigation and security grants (referenced by stage ID). Gains the CanonicalScopes marker (R0), custom-group management (R1c), the delegation envelope (R1d) and the owner-reserved refusals (#3964). SystemQuestionVersion stays as the legacy marker. The four embedded job records stay embedded; their extraction is an explicit non-goal before R7 (A-30); the contention they cause is measured by the AC-M0-02 Project-contention line (a grant change racing a bulk job). Every new field follows the N-1 and capture rule R0, R1c, R1d, R2a, R3a
Study CanonicalSummary sub-document (coexistence adapter, retired at R7): per bound stage, the tallies; per form and per reviewer, the membership facts ({state: placeHeld, savedIncomplete, completed or withdrawn; standing: qualifying, needsUpdating, pinnedOlderCounted, pinnedOlderNotCounted or notApplicable; versionSeq; claimActivities; admittingRegimeId; routeStageId}, as in consistency model §3.3; draft_only is never written to Study, it is read from pmFormSession and pmSessionDraft, and appears on Study only as placeHeld when a Study-writing command recorded it); per profile, the current ScreeningOutcomeSummary (this is FEAT-011's screeningOutcomes[], one array); readiness flags; the DefinitionVersionVector it was evaluated under. Not the legacy computed fields: SessionTallies and InclusionInfo are getters recomputed on every whole-Study save (StudyRepository.cs:3176-3227, ExtractionInfo.cs:31-80, per the brief; UNVERIFIED here), so R0's floor makes those getters and the claim pipeline merge the summary, and the pool, capacity and readiness predicates read it through IReviewMembershipFacts. Older binaries preserve it through [BsonExtraElements]; the F1a storage ADR chooses between this shape and VB's legacy-shaped stub sessions with evidence, default this shape. Also: CanonicalScopes marker (R0); Claims v2 (R2a, R2b); mergedInto and aliases (P2); FEAT-011 fields citations[], publicationId, lifecycleStatus, duplicateGroupId, metaAnalysisIncluded (P1, P2, R5b), with fullTextStatus replaced by the retrieval status derived from StudyLifecycleLedger (amendment M); report links if D4-08. FEAT-024 PendingStatistics rows continue through the FEAT-024 source-write seam (MS-06). Every canonical commit bumps the version and conflicts correctly with bulk-update locks. New pmStudy indexes (summary, markers, claims) are built through the operator route with commit quorum, preferring partial indexes (VB-18) R0, R2a, R2b, R3a, P1, P2, R5b
SystematicSearch sourceType and sourceName (P1); withdrawal state (amendment J, D3-12); referenced by ExternalStepLedger (amendment K); search documentation fields (database, date searched, strategy, limits) if D4-05 approves; schema version already lives in extra elements (SystematicSearch.cs:118-137), so new fields follow the same route P1, F-P
Investigator No new fields. Canonical records store only opaque investigator GUIDs; account deletion anonymises the Investigator record and answers stay attributed to the anonymised identity (D2-14, VB-19); a schema check enforces the storage rule (E32) F1a design
ReviewerPresence FormSessionId (additive; AnnotationSessionId kept); current presence keyed by form or profile for shared sessions, with the index migrated create, read both, drop; snapshots shaped by DisclosurePolicy; retention rule in E32 (RT-14, RT-21) R2a (link), R2b (key)
ReviewSessionConnection Stable client tab ID (sessionStorage), REST heartbeat lease for drafts (the bulk-PDF lease pattern) or the hub heartbeat when available; form or scope key beside StageId; HasStartedAnnotating means the draft-changes flag (RT-10) R2a
StageAllocationRegime Referenced by ID from StageSettingsVersion; refused on canonical stages until AL1 (D3-13a); regime schema v2 (form binding, target source) with its floor one release ahead (AP-10); one plan per shared form with equality checks (AL1) R2a (refusal), AL1
ProjectStatistics Families and scope kinds for form-version, question-version and profile-version usage and canonical contributions, by FEAT-024 technical-plan amendment at F2/F5 (MS-02); target-aware classification lands before R2b/R3a (MS-07); one protocol bump after gate (b), intents only until then (MS-15); OperationId = canonical CommandId R2a, R2c, R3a, F5
DataExportJob Previous-version and as-of modes; manifest reference; export disclosure contract; only the requester or an admin may download (#3335 D11, PH-25) R2a, R5a
StudyConversation (CODE-PR) See §4.10 #3965, R2a (refusal), R4a (binding)
InboxNotification (CODE-PR) See §4.10 Per kind
Legacy embedded types (Annotation, AnnotationSession, OutcomeData, Screening, SlotReservation v0/v1, SessionTally) Frozen for canonical scopes by the marker and guard; class maps capture extra elements (never ignore only; no new fields inside computed collections); read through LegacyReviewDataAdapter; retired in R7 R0, R6, R7

6. Domain events and commands

6.1 Hosting rule

  • Domain policies and aggregates live in SyRF.ProjectManagement.Core, one namespace per context (Core/Model/<Context>/, Core/Services/<Context>/), following ADR-009's domain-service criteria (docs/decisions/ADR-009-domain-vs-application-service-classification.md:24-58, CODE-MAIN).
  • Command handlers (application services) live in SyRF.ProjectManagement.Application, which today holds one service, ReviewStatsQueryService (CODE-MAIN, directory listing). Every canonical command has exactly one handler there.
  • API and PM are hosts that invoke the same handler: interactive commands over HTTP in the API; operations, sweeps and time-driven transitions through a PM.Messages consumer in PM. Quartz schedules only; a scheduled notice is a command to PM that marks the aggregate and captures inline.
  • PM gets notification-capture capability (the notification flags, or the admission-record pattern) as an R0 item (E59), because operations hosted in PM capture notices (NS-01).
  • Today's engine is API-hosted: SubmitAnnotationSessionService.cs (673 lines) and ReviewController.cs (1,707 lines) under src/services/api/SyRF.API.Endpoint/ (CODE-MAIN, line counts), calling Core domain services. docs/architecture/platform-architecture.md:125, :134, :139 says the API is "intentionally thin" and PM holds "all business logic" and "receives commands from API". That is wrong for review writes and is corrected in the F1a documentation PR, citing ADR-009 and the command catalogue (DD-23).

6.2 Event catalogue

Classes follow consistency-model §9: (a) derived on read, no fan-out; (b) durable intent written in the commit transaction and handled by a leased idempotent dispatcher or an ADR-020 operation record; © best-effort hint (SignalR, change streams) that never carries correctness. Facts are the immutable records the transaction itself writes. In-process IDomainEvent (Entity.cs:61-74 collects them until commit; the dispatch is not awaited per DD-03's reading of MongoUnitOfWorkBase.cs:731-739, UNVERIFIED here) is used only for loss-tolerant effects and only after #3973. New contract: C19.

Context, aggregate Event (fact recorded as) Consumers and effect class
Evidence, ReviewerStudyEvidence SessionVersionRecorded (Save, Complete, Fix, Withdraw; FormSessionVersion plus Study version and summary) Outdated flags, task drift, Needs updating, readiness: (a). FEAT-024 pending entry through the source-write seam: (b). Inline inbox rows, bounded (task holder, requesting reconciler): (b, inline). Slot-claim release and presence replace: in the transaction. SignalR invalidation: ©
Evidence, SessionDraft DraftChanged, DraftLeaseTransferred, DraftDiscarded (draft record, audit) Presence dirty hint: ©. LC1 readiness reads drafts: (a)
Evidence, ExposureLedger ExposureRecorded (ledger) Agreement classification, manifests: (a)
Screening Outcomes ScreeningDecisionSubmitted → ScreeningOutcomeChanged (decision revision, ProfileSession version, ScreeningOutcome entry, Study summary); OwnDecisionCorrected (DP2) Pool and route recomputation from the summary: (a). StudyLifecyclePolicy transition in the same transaction (StudyLifecycleLedger). Dependent-form claim at Include: in the transaction (D3-19). Statistics: (b). Adjudication inapplicable after correction: (a, vector)
Screening Outcomes, StudyPoolLedger StudyEnteredPool (FEAT-011's pool-entry event; ledger; from batch opening, personal grant, import, filter change, dedup reversal, return from retrieval) PRISMA boxes 4 and 8, amendment A fixtures: (a)
Design, AnnotationForm and FormVersionIssue FormVersionIssued phase 1 (head CAS, policy, operation record); IssuePolicyRevised (FV4; policy generation CAS); ProfileVersionIssued Projection rewrite sweep: (b, operation record). Notices through NotificationFanOut: (b). Admission and readiness pause for the form: (a, readers check the operation state). Issue applied or stalled notice to the admin: (b, inline)
Design, DefinitionTemplate TemplateCopied (copy record) None
Workflow, Stage StageSettingsPublished (version); StageCompleting, StageCompleted, StageReopened, ChangeRequested, ChangeDecided (status history, change request) Claim revalidation through the D6 conflict flow and claim withdrawal: (b, outbox). FEAT-024 definition-rewrite fence: (b). Queues and badges: (a). Notices inline, with auto-resolve of siblings if D3-23: (b, inline)
Reconciliation, ReconciliationTask ReconciliationStarted (editor claim); TaskInputsChanged and TaskHeld (derived); AssignmentCreated, AssignmentExpiring, AssignmentExpired, AssignmentReleased (assignment entity; expiring via a scheduler marker); AdditionalReviewRequested, Returned, Withdrawn Queues: (a). Inline notices to assignee, previous holder, requested reviewer: (b, inline). Requested-review claim on Study: in the transaction
Reconciliation, StudyGold GoldSnapshotPublished (snapshot, pointer CAS, task status) Exports and the re-reconciliation flag on overlapping tasks: (a). Statistics: (b). Inline notices to raisers of addressed concerns (QY8): (b, inline)
Reconciliation, QueryWorkItem ConcernRaised, ConcernResolved (concern, resolution) Query queue: (a). Per-raiser notice inline: (b, inline)
Identification CitationRecorded, PublicationLinked, PublicationEnriched (cross-project, clock-stamped), DuplicateReviewed, StudyMerged, StudySplit (operation record, both Study documents), ExternalStepRecorded, RetrievalRecorded, SearchWithdrawn (ledgers) PRISMA and as-of exports: (a). Dedup audit: fact. Retroactive matching after an accepted bibliographic correction: (b, operation)
Platform ProjectEnrolled, ScopeAdopted (operation), LegacyWriteCaptured (ledger), ProjectionRewritten (operation) Admission and flag targeting: (a). Adoption manifests: (a)
Reporting PrismaFlowFrozen, ExportManifestRecorded None (terminal facts)
Any UI invalidation (InboxChanged, presence, outdated flags) © only; never a correctness path

6.3 Command catalogue

Template columns: command · intent (ledger IDs) · aggregates written · aggregates read · transaction class (interactive; fenced definition; operation) · receipt (the command ledger record) · events raised (class) · capability (names are placeholders until A-03; Q-03 approved the capability list on 3 October 2026) · host · typed refusals. The full catalogue is the F1a command ADR (§13); these seed rows fix its shape. Every interactive row also writes Study (version bump, summary) when it changes study-scoped evidence or derived state.

Command Intent Writes Reads Class Receipt Events Capability Host Typed refusals
SaveSession SL2, SL3 ReviewerStudyEvidence (version, heads, revisions), SessionDraft (consume), Study (summary, slot claim release, presence) AnnotationForm head, Stage settings version, StudyGold references (withdraw only) Interactive FormSessionVersion SessionVersionRecorded Review API StaleBase, DraftLeaseHeld, Refused (ownership, admission), Locked, Fenced, SizeLimitExceeded, OutcomeUnknown, CommandDigestMismatch
CompleteSession SL2, SF2 As Save, plus validation As Save, plus ApplicabilityEvaluator fixtures Interactive FormSessionVersion SessionVersionRecorded Review API As Save, plus ValidationFailed (names the blocking question), FormVersionNotRenderable
FixSession SF5, SF6 New incomplete version Outdated-flag derivation Interactive FormSessionVersion SessionVersionRecorded Review API As Save, plus StageCompleted (creates a change request instead, LC1)
WithdrawSession C5 Withdrawal version; Study (claim release) StudyGold, task pins Interactive FormSessionVersion SessionVersionRecorded Review (or Admin per the C5 ADR) API PinnedByGold, PinnedByTask
AutosaveDraft, TakeOverDraft, DiscardDraft SL1, D2-08 SessionDraft only — Interactive (no Study) None (write sequence) DraftChanged, DraftLeaseTransferred, DraftDiscarded Review API DraftLeaseHeld, StaleAutosave
SubmitScreeningDecision, CorrectOwnDecision DP3, DP2, PR1 Decision revision, ProfileSession version, ScreeningOutcome, Study (summary, dependent claim), StudyLifecycleLedger, StudyPoolLedger (if availability changes) ScreeningProfile version, PrismaPhaseMapping Interactive ProfileSession version ScreeningDecisionSubmitted, ScreeningOutcomeChanged Screen API As Save, plus EnoughReviewers (dependent claim refused, decision kept), StaleProjection
AcquireClaim, ReleaseClaim RA1, D6 Study (claim set, FEAT-024 part or fold entry) Stage settings, membership facts Interactive None (natural key) Claim revocation via outbox on release paths Review, Screen, Reconcile API, PM (timers) AtCapacity, EnoughReviewers, NotAdmitted, StepLocked, StageCompleted
IssueFormVersion (phase 1) FV1–FV3, PS1–PS3 AnnotationForm head (CAS), FormVersionIssue, operation record, NotificationFanOut C8 usage evidence at the fence, preview digest Fenced definition FormVersionIssue FormVersionIssued Publish API PublicationInProgress, StaleUsageEvidence, PreviewDigestChanged, FormVersionNotRenderable, SizeLimitExceeded
ReviseIssuePolicy (FV4) FV4 FormVersionIssue (policy generation CAS) — Fenced definition FormVersionIssue IssuePolicyRevised Publish API PolicyGenerationStale
ApplyIssuePolicy (phase 2) FV2, FV3 Study summaries, FEAT-024 rows (projection rewrite), operation record Predicate over sessions Operation Operation record ProjectionRewritten System PM Fenced (lease lost), StalledAtLimit (D2-10)
IssueProfileVersion Q-26 ScreeningProfile head, ProfileVersionIssue Decisions under prior versions Fenced definition ProfileVersionIssue ProfileVersionIssued Publish API As IssueFormVersion
PublishStageSettings PV2, RX2 Stage (new settings version, pointer) Form and profile versions Fenced definition StageSettingsVersion StageSettingsPublished Design stage API DependencyCycle, StageCompleted (needs a change request), TargetConflict (D6 flow)
RequestStageChange, ApproveStageChange, DeclineStageChange LC1 Stage (change request, status) The underlying change, re-checked at commit Interactive Change request ChangeRequested, ChangeDecided Approve stage change API AlreadyDecided, RecheckFailed
CompleteStage, ReopenStage RX2, LC1 Stage (status, history), operation record for the drain Readiness Operation (two-step) Operation record StageCompleting, StageCompleted, StageReopened Manage stage PM (automatic), API (manual) NotReady, DrainTimeout
StartReconciliation RA1 ReconciliationTask (editor claim, session) Candidates, readiness Interactive None (claim CAS) ReconciliationStarted Reconcile API TaskHeld, NotEligible (reviewed the study), NotAssignedToYou
SaveReconciliation, CompleteReconciliation RE2, RE5 ReconciliationTask (session version), StudyGold (reconciled revisions), SessionDraft, Study Candidate versions, exposure Interactive ReconciliationSession version SessionVersionRecorded (reconciled scope) Reconcile API As Save, plus TaskHeld, InputsChanged (re-check)
PublishGold GS1, RE2 StudyGold (snapshot, pointer CAS), ReconciliationTask (status), affected QueryWorkItems, Study Validity, affected children Interactive GoldSnapshot GoldSnapshotPublished Reconcile API StaleBase (pointer), UnresolvedChildren, ValidationFailed
AssignTask, ReleaseAssignment, OverrideExpiry RA2–RA4 ReconciliationTask (assignment, editor claim via outbox) Eligibility Interactive Assignment entity AssignmentCreated, AssignmentReleased Assign reconciliation API NotEligible, StartedCannotExpire
RequestAdditionalReview, ReturnAdditionalReview, WithdrawRequest RA5 AdditionalReviewRequest, Study (requested-review claim) Target, eligibility Interactive Request record AdditionalReviewRequested, Returned, Withdrawn Request an additional review API NotEligible, AlreadyRequested
AdjudicateProfileDecision RX1, DP5 ProfileAdjudication (version), ScreeningOutcome (final facet), Study, StudyLifecycleLedger Decisions, must-agree answers, input vector Interactive AdjudicationVersion ScreeningOutcomeChanged Reconcile (profile part) API StaleProjection, InputVectorSuperseded
RaiseConcern, ResolveConcern QY1–QY9 QueryWorkItem (concern, resolution, editor claim) StudyGold pointer Interactive Concern or resolution record ConcernRaised, ConcernResolved View answer (raise); Query review (resolve) API TaskHeld, StaleTarget
OpenSharedBatch, GrantPersonalBatch Amendment A, D3-13e Batch plan (CAS), StudyPoolLedger Completion evidence Interactive (CAS) Plan or access row StudyEnteredPool System or Manage stage API, PM FrontierStale
RecordExternalStep, RecordRetrieval, WithdrawSearch Amendments K, M, J ExternalStepLedger, StudyLifecycleLedger, Study (retrieval status), SystematicSearch — Interactive Ledger entry ExternalStepRecorded, RetrievalRecorded, SearchWithdrawn Manage searches API Refused (ownership)
LinkPublication, ReviewDuplicate Amendments N, L Publication, Study (publicationId), DuplicateReviewItem, DedupAuditLedger DOI/PMID indexes Interactive Ledger entry PublicationLinked, DuplicateReviewed Manage studies API, PM (import) PrivacyRefused
MergeStudies, SplitStudies Amendment D, L; D2-12 Both Study documents (alias, mergedInto), DedupAuditLedger, operation record Claims, drafts, open tasks Operation Operation record StudyMerged, StudySplit Manage studies PM StudyBusy, Fenced
FreezePrismaFlow PR1, amendments PrismaFlowSnapshot Ledgers, outcomes, mapping Interactive Snapshot PrismaFlowFrozen PRISMA API CoverageIncomplete (labelled, not refused)
EnrolProject, RemoveEnrolment R0 CanonicalEnrolment Rule Interactive Enrolment record ProjectEnrolled Application admin API NeverChangesOwnership (no refusal; audit)
AdoptScope R6 CanonicalOwnership, markers on Project and every Study of the scope, LegacyIdAlias, operation record Manifest Operation (lock, verify, stamp, release) Operation record ScopeAdopted Chris (per wave) PM ManifestInvalidated, LockContention

Typed refusal catalogue (frozen with C18): StaleBase, RetryableConflict, Locked (LockedByBulkUpdate), Fenced, OutcomeUnknown, Refused (ownership, enrolment, permission), PublicationInProgress, SizeLimitExceeded, ConflictedLegacyAnswer, CommandDigestMismatch, FormVersionNotRenderable, DraftLeaseHeld, StaleAutosave, AtCapacity, EnoughReviewers, TaskHeld, StepLocked, StageCompleted, StaleProjection, ValidationFailed. Generated through NSwag; AF2 handles each without losing drafts.

7. Policy catalogue and value objects

7.1 Policies

Every policy is a pure Core domain service (ADR-009) with a fixture suite as its conformance test (DD-14). Inputs are facts, never repositories.

Policy Inputs Output Invoked by Conformance
ApplicabilityEvaluator (E23) Form version, answers, branch context Applicable question set; typed errors naming the blocking question Complete, Needs updating, reconciliation validity, UA1 FEAT-020's rules file and fixtures shared with AF2 (PH-07)
SessionEffectiveStatePolicy Latest explicit version, its pin map, current published version, recorded policies, per-answer validity Effective state (qualifying, needs updating, pinned under older version, not applicable) Admission, qualification, AF2, exports VA-03 fixtures
ContributionQualificationPolicy Effective state, alias set, eligibility Qualifying contributions, counted once per reviewer across stages and aliases Readiness, tallies, PRISMA C5, SF2, SF6, DD-08 fixtures
StepRoutingPolicy Stage settings version, own decision, candidateCollective and final facets Route availability per step (C6 table) Admission Research A12–A16, FX-PRISMA-03a
WorkAdmissionPolicy IReviewMembershipFacts (from the summary or embedded data), claims, settings, grants Allow or deny with reasons and evidence; never creates a vote Selection, reservation, direct access, submit The generated eligibility truth table (D3-09)
CapacityPolicy Membership facts, claim set, cap (D3-17), target, requested-review claims Place available, place held, enough reviewers Claim acquisition AC-R2a-35, 36, 37 and 06; AC-R4a-38
CollectiveOutcomePolicy Profile version rules, decisions, adjudication, input vector ScreeningOutcomeValue Submit, correct, adjudicate, sweep Parity fixture (VA-20), PR1
StudyLifecyclePolicy Outcomes by profile, PrismaPhaseMapping, retrieval status Lifecycle transition or none The same transaction that writes the outcome (DD-20) FEAT-011 lifecycle fixtures
IssueImpactPolicy Recorded policy, session category, prior version, compatibility Treatment per session (requireReanswer, autoUpdate, doNothing, option mapping) Preview, phase 2 sweep, read-time derivation FEAT-003 categories (PH-18), E1 fixtures
PublicationImpactPolicy Task pins, new version compatibility Which candidates still qualify; inputsChanged or held Task drift DD-07 fixtures
UsageEvidenceGate FEAT-024 usage read at the fence, identity Current or stale Issue phase 1 (C8) PS2/PS3 fixtures
ReconciliationReadinessPolicy Qualifying contributions, target, drafts, corrections Ready, not ready, inputs changed Task creation, LC1 RE4, SF4 fixtures
PrefillPolicy Candidate answers, exact-text match, choice agreement Prefill with provenance and autofill marks Reconcile host RE2, RE5
GoldOwnershipPolicy Overlapping forms, existing snapshot Owner task; second task revises with provenance PublishGold D2-09 fixtures
ExposurePolicy Snapshot availability, ledger entries Three states, failing safe; questioned kind Agreement, manifests C3, NS-06 fixture
DisclosurePolicy Recipient, project, stages, channel (read, export, statistics, inbox, email, digest, presence), BL1, VS1, role Shaped view Every channel NS §4.2 fixtures per kind and role; RT AC-T-08
BlindingPolicy Stages reaching the task Most restrictive BL1; alias scheme Reconcile host, threads, exports Q-28 fixtures
StageCompletionPolicy Readiness, drafts, corrections, change requests Completing, completed, blocked CompleteStage (E29) Lifecycle fixtures (Q-02)
CanonicalOwnershipGuard CanonicalScopes, the writer's declared scope Write filter; refusal explanation Every legacy writer; composite IAggregateWriteGuard StudyWriteLockArchitectureTests extension
AliasResolutionPolicy Alias set, mergedInto Primary study and attributed records Reads, candidate selection, statistics, PRISMA V2-02 and L.4 fixtures
AgreementPolicy (E9) Candidate revisions, exposure, method Figures, denominators, independent and informed split R5c Q-04, Q-16 fixtures

7.2 Value objects frozen at F1a

Shared-kernel types are jointly owned by the contexts named and have a joint conformance suite; the rest are context-local. Equality is by value unless stated.

Value object Fields Equality and rules Shared kernel
AnswerContextKey + ContextKeyHash project, study, authorScope, definitionOwner, questionId, entityPath, populationRef; the hash is SHA-256 over a versioned canonical serialisation Value equality on the ordered fields; unique indexes use the scalar hash only, with partial unique indexes per kind (VB-05) Evidence, Design, Classification, Reconciliation
EntityPath Ordered elements, each typed optionBranch(optionId) or instance(labelHeadId) (PH-16) Element-wise equality including kind Evidence, Classification
AuthorScope candidate(investigatorId) or reconciled Value Evidence, Reconciliation
DefinitionOwner project or profile(profileId) (DD-26's definition ownership; owningParent is a revision edge, not a key part) Value Design, Evidence
Provenance stage, step, settings version, question version (AuthoredUnder may be Unknown), shown revision, real actor, on-behalf-of, source system, legacy ID, mapping version, historyCoverage Value; migration time is never presented as original time Evidence, Reconciliation, Reporting
ExposureState enum (noGoldAvailable, recorded, availableUnrecorded) plus evidence Value; fails safe Evidence, Reporting
AuthorityValue candidateAgreement, reconciled, adjudicated, adminOverride, verified (D4-03), imported (D4-14), legacyUnknown Closed set stored as strings Screening Outcomes, Reconciliation, Reporting
ScreeningOutcomeValue candidateResult, voteCounts, ruleVersion, finalResult, finalSource, adjudicationRef, freshness Value; readers name a facet Screening Outcomes, Workflow, Reporting
StructuredReason primary reason, counted reasons, coverage status Value (Q-22 keeps both shapes possible) Screening Outcomes, Reporting
CompatibilityRelation same, compatible, incompatible; reason Value; declared at commit, immutable once pinned (D2-02) Design, Evidence
DefinitionVersionVector Form, profile and question version seqs a derived record was evaluated under Component-wise comparison; a lower component means stale Screening Outcomes, Platform, Workflow
Route stage, step Value Workflow, Evidence
ReviewerAlias stage-owned alias from one alias source Value within a stage Reconciliation, Notifications
ClaimKey and Claim study, kind, scope, reviewer; plus route, reservedAt, regime, lease Key equality Workflow, Evidence, presence programme
EntityTypeId System identities for the seven legacy categories, cohort, outcome measure, experiment; project-defined later Value Design, Classification
Citation FEAT-011's fields; identity = citationId; immutable Identity by citationId Identification
StudyAliasEntry secondary study, operation, provenance Value Identification, Evidence
CanonicalScopes Set of scope references (form(F), profile(P), notifications) Set equality Platform, every writer
CoverageLabel, Watermark, HlcStamp, CommandId, ContentDigest As named; the watermark is a clock stamp with bounds Value Reporting, Platform, Evidence

8. Ubiquitous language

Internal names are PROPOSALs for the naming ADR at F1a; user-facing terms are recommendations pending D3-03 (copy deck) and are checked against the copy contract (ux-strategy.md). The table resolves the collisions DD-11 listed.

User-facing term (recommended) Internal name Never use it for
Publish a form or profile version FormVersionIssue, ProfileVersionIssue FEAT-011 Publication; FEAT-024 ProjectStatisticsPublication*
Publication (bibliographic) Publication (Identification namespace only) The act of publishing a definition
Primary and secondary study (dedup) primaryStudyId, StudyAlias, mergedInto "canonical"
Canonical path, canonical scope CanonicalEnrolment, CanonicalOwnership, CanonicalScopes Dedup primaries; FEAT-024's "canonical tuple"
Screening result ScreeningOutcome {candidate, final}; ScreeningOutcomeSummary on Study (FEAT-011's screeningOutcomes[]) Measured outcomes; concern resolutions
Outcome measure, outcome data OutcomeMeasure, OutcomeSchema, Observation Screening
Concern and its resolution Concern, ConcernResolution "outcome"
Screening profile ScreeningProfile FEAT-024 AnnotationStudyProfile (a rename there is a FEAT-024 request); #2987 AnnotationProfile (not harvested); investigator profile
Enrolment (a project joins the canonical path) CanonicalEnrolment Work admission; upload admission; FEAT-024 checkpoint admission
Work admission (may this reviewer do this now) WorkAdmissionDecision Enrolment
Correction (DP2, Fix, LC1, bibliographic) OwnDecisionCorrection, FixTransition, PendingChange, BibliographicCorrectionEvent StudyPdfCorrection
Population (animals) AnimalPopulation FEAT-024's search-population family; the review population (box 1)
PRISMA flow report PrismaFlowSnapshot PRISMA "reports" (the bibliographic unit, amendment B); study issue reports; reported counts (ExternalStepLedger)
Session (a reviewer's work on a form) FormSession, ProfileSession, ReconciliationSession; presence stays ReviewSessionConnection Legacy AnnotationSession once adopted
Release (an assignment) AssignmentRelease R-releases; batch release (SharedBatchOpened); pool availability (StudyEnteredPool); BulkPdfUploadReleaseRecord
Accepted answers (gold standard) StudyGold, GoldSnapshot "reconciled" as a status word (use AuthorityValue)
Save progress; Complete SaveSession, CompleteSession "Save draft"; "All changes saved"
Changes kept, not yet saved SessionDraft (draft-changes flag) A version
Needs updating; Outdated answers; Fix NeedsUpdating (derived), outdated flag (derived), FixSession "contains outdated annotations" in UI copy
Review place (a reviewer's held place on a study) Claim (formSlot, profileSlot) Assignment; draft lease
Reconciling (editing a task) taskEditor claim Capacity claim
Stage Stage aggregate (Workflow) for canonical projects; Project.Stage entity (legacy) A step; a form
Ledger *Ledger (append-only facts) An aggregate with a current pointer
Operation ADR-020-shaped record with lease and generation A command; a transaction

9. Transactions

The commit protocol, the full transaction table (every operation with the records it writes, its capture mode, its FEAT-024 part and its claim and presence writes, including RT-15's rows and AP-05's batch rows) and the command-budget tests are in consistency-model.md §4; idempotency in §5; fences and operations in §7. This page keeps only the invariants and where each one is materialised.

Summary. Interactive commands use one MongoDB transaction (snapshot read, primary, majority write with journal, maxCommitTime) over the study-scoped aggregates they change plus Study; a stale base is re-executed from a fresh snapshot within a deadline; retries are free when Study moved only through fold, claim-token or idle-token writes. Autosave never touches Study. Definition commands run under fences with O(1) phase 1. Everything else is an ADR-020 operation or a durable intent handled after commit.

Invariant Materialised in A conflict surfaces as
One contribution per reviewer per study × form FormSession deterministic ID and unique natural key DuplicateKey → reload and CAS (two tabs create one session)
The latest explicit version is current FormSession head CAS on version seq StaleBase (draft kept)
One head per context per author scope {ProjectId, ContextKeyHash} unique; Conflicted state for adopted duplicates DuplicateKey → reload; ConflictedLegacyAnswer until Fix or Save
Per-study serialisation Study version CAS in every study-scoped command RetryableConflict; free retry if only fold, claim or idle writes moved it
Capacity and places Study claim set in an atomic write filter AtCapacity, EnoughReviewers
One editor per task or query Editor claim CAS plus lease on the aggregate TaskHeld
One active issue per form Unique partial index on FormVersionIssue (the pmRobRunOperation.ActiveSearch pattern) PublicationInProgress
Issue phase 1 versus a racing Save AnnotationForm head CAS; sessions carry pinnedFormVersionSeq; the sweep is a predicate A late Save is swept; if the sweep wins first the reviewer gets StaleBase and keeps the draft
Gold pointer StudyGold current-pointer CAS StaleBase on concurrent PublishGold and ResolveConcern
Legacy write to a canonical scope CanonicalScopes in the write filter; composite guard Refused (ownership) as a filter miss
Bulk-update lock Unlocked filter (ADR-020) LockedByBulkUpdate
A gate never reads a stale projection DefinitionVersionVector comparison StaleProjection (fail closed; the sweep repeats)
One draft writer SessionDraft lease etag and write sequence DraftLeaseHeld (conflict copy kept); StaleAutosave
Exactly-once commands (ProjectId, CommandId) unique on the output record plus request digest The original result is returned; CommandDigestMismatch
Merge or split never re-keys Alias set and mergedInto written by an operation that refuses busy studies StudyBusy

10. Identity and keys

  • IDs are CSUUID GUIDs. Aggregates with natural keys get deterministic IDs: SHA-256 over a versioned canonical key, stored as CSUUID (the #3944 precedent). That covers FormSession, ProfileSession, AnnotationHead (through its key hash), ScreeningOutcome, ProfileAdjudication, StudyGold, ReconciliationTask, CanonicalEnrolment, CanonicalOwnership, the default AnimalPopulation and SessionDraft (= its session or task). Revisions and entity instances use client-proposed, server-validated IDs (unused, same project), so AF2's inline creation needs no ID remapping. Legacy IDs are kept at adoption, with the natural-key unique index as the real guard (VB-16, DD-15).
  • Context key hash. contextKey is an ordered value object stored beside contextKeyHash; unique indexes use scalars only: {ProjectId, KeyHash} unique, partial unique indexes per kind (for example {ProjectId, StudyId, AuthorScope, ProfileId} where kind = screening decision), and a non-unique {ProjectId, StudyId, AuthorScope, QuestionId} for ancestor and SF5 reads (VB-05).
  • Kinds and statuses are strings parsed from a closed set, as FEAT-024's pending kinds are, which replaces the "append ordinals, never reorder" rule for canonical records (VB improvement 9).
  • Explicit collection names, decoupled from class names, frozen in one map with a test that asserts it; append-only repositories; content digests (versioning-model.md, VB-10). The class-name formula (mongodb-reference.md:88) stays for existing collections only.
  • System question identity: pmQuestionDefinition._id is a record GUID with {ProjectId, QuestionId} unique, because system question IDs repeat across projects (VB-11).

Collection list (aligned with VB's storage blueprint; VB's pmFormPublishOperation is this page's pmFormVersionIssue). Identity and unique keys per collection; other indexes are the storage ADR's. IssuePolicyRecord is embedded in FormVersionIssue, so it has no collection of its own; the F1a naming ADR confirms.

Collection Identity and unique keys Context
pmQuestionDefinition, pmQuestionDefinitionVersion record GUID; {ProjectId, QuestionId} unique; versions {DefinitionId, Seq} unique Design
pmSystemQuestionVersion {QuestionId, SystemQuestionVersion, StructuralDigest} unique Design (system)
pmAnnotationForm, pmAnnotationFormVersion {ProjectId, FormId}; versions {FormId, Seq} unique; head holds CurrentPublishedSeq, PublicationSeq, PolicyGeneration Design
pmFormVersionIssue, pmFormVersionIssueChunk one active per form (unique partial index); chunks {OperationId, Chunk} unique Design
pmScreeningProfile, pmScreeningProfileVersion, pmProfileVersionIssue as forms Design
pmDefinitionTemplate _id; {Scope, OwnerId?, TemplateId} Design
pmOutcomeSchema, pmEntityType, pmSharedConcept, pmProjectRule {ProjectId, …Id} unique; versions by seq Design
pmReviewStage, pmStageSettingsVersion _id = stage ID; versions {StageId, Seq} unique Workflow
pmFormSession deterministic _id; {ProjectId, StudyId, DefinitionOwner, AuthorId} unique (forms and profiles) Evidence
pmFormSessionVersion {SessionId, Seq} unique; {ProjectId, CommandId} unique (the receipt) Evidence
pmSessionDraft {SessionId} unique; conflict copies by {SessionId, HolderTabId} Evidence
pmAnnotationHead {ProjectId, KeyHash} unique; partial unique per kind Evidence (candidate), Reconciliation (reconciled scope)
pmAnnotationRevision _id; {AnnotationId, Seq} unique Evidence, Reconciliation
pmExposureLedger {SessionVersionId, ShownRef} unique Evidence
pmScreeningOutcome, pmProfileAdjudication deterministic _id; {ProjectId, StudyId, ProfileId} unique; adjudication versions by seq Screening Outcomes
pmStudyPoolLedger _id; {ProjectId, StudyId, HlcStamp} Screening Outcomes
pmReconciliationTask deterministic _id; {ProjectId, StudyId, FormId} unique Reconciliation
pmAdditionalReviewRequest _id; {TaskId, ReviewerId} unique while open Reconciliation
pmStudyGold, pmGoldSnapshot {StudyId} unique; snapshots {StudyId, Seq} unique Reconciliation
pmQueryWorkItem {AcceptedAnswerVersionId} unique Reconciliation
pmAnimalPopulation, pmInferenceResult {StudyId, PopulationId} unique Classification
pmPublication _id; DOI and PMID unique sparse Identification (system)
pmDuplicateReviewItem, pmDedupAuditLedger, pmDedupBatch (TTL staging) per FEAT-012 with the ledger rename Identification
pmExternalStepLedger, pmStudyLifecycleLedger _id; {ProjectId, (SearchId|StudyId), HlcStamp} Identification
pmPrismaPhaseMapping, pmPrismaFlowSnapshot, pmExportManifest, pmAgreementResult {ProjectId, …}; snapshots and manifests append-only Reporting
pmCanonicalEnrolment, pmCanonicalOwnership {ProjectId} unique; {ProjectId, Scope} unique Platform
pmCanonicalOperation, pmCanonicalOperationChunk one active per scope (unique partial index); chunks {OperationId, Chunk} Platform
pmLegacyWriteLedger, pmLegacyIdAlias _id; {ProjectId, LegacyId} unique Platform
pmNotificationFanOut {SourceId} unique Notifications (programme)
New pmStudy indexes (summary, markers, claims) built through the operator route with commit quorum; partial where possible (VB-18) Study

11. Modularity for parallel agents

  • One namespace per bounded context: Core/Model/<Context>/ and Core/Services/<Context>/ (ReviewDesign, ReviewWorkflow, Evidence, ScreeningOutcomes, Reconciliation, Classification, Identification, Reporting, Membership, Platform). The legacy embedded model stays under ProjectAggregate/ and StudyAggregate/ and is reached from new code only through LegacyReviewDataAdapter.
  • internal by default. Public surface per context is limited to Core/Contracts/<Context>/: shared-kernel value objects (§7.2), policy interfaces (§7.1), repository interfaces and DTOs. Hosts reference ProjectManagement.Application, never a context's internals.
  • Architecture fitness tests, in the F1a conformance suite:
  • a source-scanning test extending StudyWriteLockArchitectureTests (Mongo.Data.Tests/StudyWriteLockArchitectureTests.cs:25-74, CODE-MAIN; it scans production sources per member with regexes, with an allow-list of justified exceptions) so that every direct Study or Project write adds the ownership filter as it already adds Unlocked, and every write to a registered immutable collection is an insert (no ReplaceOne, Update*, Delete*, FindOneAnd* or update models);
  • a reflection-based dependency test (NetArchTest-style; DD-22 found none in src) asserting the context map's allowed dependencies, no internal leakage across contexts, and the hosting rule (command handlers only in Application; no policy with a repository dependency);
  • the collection-name map test and the append-only repository test (versioning-model.md).
  • Lanes map to contexts. L1 Evidence, L2 Design, L3 Screening Outcomes (with L2's editor), L4 Workflow, L6 Reconciliation, L9 Classification, L10 Design (outcome schemas), L11 and L12 Reporting and Identification, L8 Membership, L0 and L15 Platform. A change to a shared-kernel type or another context's contract goes through an ADR amendment with consumer sign-off; one writer per worktree.

12. Introduction by release

Release New aggregates, entities and ledgers Changed aggregates
M0 (engine proof) None persisted; fakes and the conformance suite —
R0 CanonicalEnrolment, CanonicalOwnership, CanonicalScopes markers Study, Project, SystematicSearch value objects capture extra elements; Study getters and the claim pipeline merge CanonicalSummary; PM gains capture capability (E59)
R1a DefinitionTemplate (question templates, with the copy record) None (R1a adds no Project field, V2-16)
R1b — Project (owner-only enforcement; no schema)
R1c, R1d — Project (custom groups, grants, delegation envelope)
R2a QuestionDefinition, SystemQuestionVersion, AnnotationForm (requirement versions, operational settings), Stage (minimal binding), ReviewerStudyEvidence (FormSession, versions, heads, revisions), SessionDraft, command ledger records, LegacyWriteLedger, ExportManifest (version exports), EntityTypeId identities Study (CanonicalSummary, version bump, claim release on first Save), Project (CanonicalScopes), ReviewerPresence (FormSessionId), ReviewSessionConnection (tab ID), DataExportJob (previous versions), StageAllocationRegime (refusal on canonical stages)
R2b — Study (claims v2, form-keyed), ReviewerPresence (form key), ProjectStatistics (form-unique derivations)
R2c FormVersionIssue, operation records (projection rewrite), NotificationFanOut (programme) AnnotationForm head (publication seq, policy generation), ProjectStatistics (usage families)
R2d — ReviewerStudyEvidence (cross-form sharing, outdated flags derived, Fix), FormVersionIssue (FV4 policy revisions), AnnotationForm (A-19 lifted)
R3a ScreeningProfile (default compatibility profile), ProfileSession, ScreeningOutcome, StudyPoolLedger, Stage (steps, routes, filter element) Study (ScreeningOutcomeSummary, profile claims, dependent-form claim at Include), ProjectStatistics (decisions, target-aware classification)
R3b ScreeningProfile (full), ProfileVersionIssue, PrismaPhaseMapping, DefinitionTemplate (profiles) QuestionDefinition (profile-owned), ScreeningOutcome (per profile), ProjectStatistics (profile-version usage, F5)
R3c Stage lifecycle (status, mode, StageChangeRequest, history), operation records (completion drain) Stage
R3d Setup drafts (a ProjectSetupDraft record owned by L13, PROPOSAL) Project (created canonical by rule)
R4a ReconciliationTask (ReconciliationSession, assignments, editor claim), AdditionalReviewRequest, StudyGold and GoldSnapshot, ExposureLedger Study (requested-review claim), StudyConversation (task binding, L6 ownership), ReviewerPresence (reconcile host joins)
R4p ProfileAdjudication ScreeningOutcome (final facet, adjudicated authority)
R4b QueryWorkItem (Concern, ConcernResolution, query editor claim) StudyGold (pending flags)
R4c — StudyGold (outcome-series gold snapshots)
R5a ExportManifest (as-of, watermark), operation records for long exports DataExportJob (as-of mode, download ownership)
R5c AgreementResult —
R5b PrismaFlowSnapshot Study (metaAnalysisIncluded)
C1, C2 EntityType (aggregate), AnimalPopulation, SharedConcept, ProjectRule, DefinitionTemplate (entity types); InferenceResult ReviewerStudyEvidence (classification assertions; instance membership)
O1, O2 OutcomeSchema, DefinitionTemplate (schemas); O2 staged copies and manifests through operation records ReviewerStudyEvidence (observation kinds), AnnotationForm (schema bindings)
P1 ExternalStepLedger, StudyLifecycleLedger, Citation records, Publication (if amendment N creates at import) SystematicSearch (source type and name, withdrawal, documentation fields), Study (citations[], retrieval status)
P2 Publication (otherwise), DuplicateReviewItem, DedupAuditLedger, dedup batch staging, StudyAlias Study (lifecycleStatus, publicationId, duplicateGroupId, mergedInto, aliases)
AL1 — StageAllocationRegime (schema v2, form binding), Stage settings version (regime by ID)
GA — CanonicalEnrolment rule (new projects by default)
R6 LegacyIdAlias; operation records for cutover Study and Project markers; adopted projections
R7 — CanonicalSummary retired with the legacy readers; LegacyReviewDataAdapter and legacy embedded types retired

13. Decided at the freeze gates

Gate Domain-model decisions taken there
F1a (engine contracts) The ADRs below. In particular: the physical shape of every §4 boundary and of CanonicalSummary (this shape versus VB's stub sessions); draft storage and lease; deterministic IDs and the collection map; the context-key hash; EntityTypeId identities (E14's identity part moves here; its catalogue and alias validation stay at F-C and F-O); the claim contract v2 and the projection shape (the presence and FEAT-024 owners' checklists pass, run by a fresh-context agent; Chris rules on exceptions); the event taxonomy (C19) and the transaction admission ADR (C18); the command catalogue and hosting rule; ScreeningOutcome facet shape; IReviewMembershipFacts; the versioning rulebook (versioning-model.md); E25 settled on M0 evidence; D2-01 to D2-16 answered
F1b (catalogue and export disclosure) The Q-03 capability catalogue subset; DisclosurePolicy channels including presence (D3-20) and notifications; the study-issue and PDF-correction capabilities (NS-20); export disclosure (U26); D11 download ownership
F1c (IA, copy, AF2 seams) The glossary's user-facing column (D3-03, D3-04); AF2 extension points including VersionedAnnotationFormDataSource and the Needs-updating presenter; the Dockview layout-contract amendment; the save-status state machine
F2 (publication) FormVersionIssue phases and the predicate sweep (E22); FEAT-024 usage families and scope kinds (MS-02); Q-34 option mapping; impact-manifest categories (PH-18); the scoped pause limit (D2-10)
F3 (workflow) The Stage aggregate and the settings placement table (E62); the filter element's schema (FEAT-008 filter set); ScreeningOutcome frozen with amendment H; StudyLifecyclePolicy; Q-24, Q-15, Q-28 mappings; D3-13, D3-17 to D3-19; batch and allocation references by ID (AP-11); the fixed-two correction as a FEAT-024 prerequisite (AP-14)
F4 (reconciliation) C9 with the task keyed by study × form (the compatibility-class decision is removed from F4); ReconciliationSession and the editor claim (X-RECLAIM); shared-gold revision (D2-09); drift and held states; legacy authority (Q-35); authority policy (Q-36); target-1 forms (Q-29); the editable reconcile host; ADR-008 absolute timestamps for every new timer (PH-30)
F5 (profiles) ProfileVersionIssue treatment (Q-26); ProfileSession shape; keyword-list ownership (PH-28); the screening renderer contract; profile-version usage family; D4-01, D4-02, D4-13 options in profile versions
F6a (as-of) Watermark semantics over clock stamps; manifest retention (stored, PROPOSAL); coverage labels; D2-13 restore and D2-14 erasure as they affect manifests
F6b (reporting) PrismaFlowSnapshot manifest; amendments B, E, F; Q-22, Q-23; D4-11 box 1
F-P (identification) Amendments K, M, N, O; Citation storage (embedded or own collection); Publication creation point and privacy rule; retrieval status derivation; search documentation fields (D4-05); D3-12 withdrawal versus history
F-C (classification) EntityType capabilities and project-defined types (identities already minted); AnimalPopulation creation at enablement; Q-18, Q-19; E14's catalogue and alias validation
F-O (outcomes) OutcomeSchema versions and supplied schemas as system templates; A-20 confirmed; Q-17; E12
F-A (allocation) Regime schema v2 and floor; one plan per shared form; the allocation owner's phase mapping (AP-10); AL1 entry after #3269's checklist (AP-23)

ADRs needed before F1a (DD §3.7 merged with the brief's C18 and C19; numbers come from the block reserved in delivery-operating-model.md, the next free number on main being ADR-021 per the inventory; each ADR cites ADR-009 and, for timers, ADR-008):

  1. Bounded contexts, context map and architecture fitness tests (§2, §11; DD-05, DD-22).
  2. Evidence aggregate boundary and physical storage, with the collection map and pmStudy index build routes (§4.1, §10; DD-01, E15, E28, VB-10, VB-18).
  3. C18 transaction admission, concurrency and idempotency: snapshot reads, re-execution, typed outcomes, the command ledger record, per-study ordering and the clock stamp, as-of bounds (§9; brief §1.2, §1.4, §1.7; replaces DD's separate receipt and history-ordering ADRs).
  4. C19 durable effects and events: the three classes, carriers, the event catalogue, PM hosting (§6.2; DD-03, NS-01).
  5. Command catalogue and hosting rule, including the PM capture capability as an R0 item and the platform-architecture.md correction (§6.1, §6.3; DD-04, DD-23).
  6. Ubiquitous-language glossary and naming, merging the C4 naming ADR and the Q-08 harvest naming, with the user-facing column pending D3-03 (§8; DD-11).
  7. Compatibility floor with the document-level CanonicalScopes marker and composite write guard (§1.7, §4.9; DD-13, VB-07, E16).
  8. Answer context key, EntityTypeId identities, default population and ID minting (§7.2, §10; DD-12, DD-19, DD-24, DD-26, VB-05, VB-16, E27).
  9. Screening-outcome facets and the collective policy, shape at F1a and frozen with amendment H at F3 (§4.2; DD-06).
  10. The versioning rulebook (versioning-model.md) and the C15 v2 capture contract (notification programme, NS-03), which this page consumes.

14. Relationships

Cardinalities show legacy projects: canonical aggregates are zero-or-one or zero-or-many until a project is enrolled (V2-26).

erDiagram
    PROJECT ||--o| CANONICAL_ENROLMENT : "enrolled (canonical only)"
    PROJECT ||--o{ CANONICAL_OWNERSHIP : "per adopted scope"
    PROJECT ||--o{ QUESTION_DEFINITION : "owns (canonical)"
    PROJECT ||--o{ ANNOTATION_FORM : "owns (canonical)"
    PROJECT ||--o{ SCREENING_PROFILE : "owns (canonical)"
    PROJECT ||--o{ STAGE : "same stage ID; grants stay in Project"
    PROJECT ||--o{ EXTERNAL_STEP_LEDGER : "reported steps"
    SYSTEMATIC_SEARCH ||--o{ EXTERNAL_STEP_LEDGER : "per search (optional)"
    STAGE ||--|{ STAGE_SETTINGS_VERSION : "immutable versions"
    STAGE_SETTINGS_VERSION }o--o{ ANNOTATION_FORM : "binds versions"
    STAGE_SETTINGS_VERSION }o--o{ SCREENING_PROFILE : "binds versions"
    STAGE_SETTINGS_VERSION }o--o| STAGE_ALLOCATION_REGIME : "by ID"
    STAGE_SETTINGS_VERSION }o--o| BATCH_PLAN : "by ID"
    ANNOTATION_FORM ||--o{ FORM_VERSION_ISSUE : "publishes through (one active)"
    STUDY ||--o{ REVIEWER_STUDY_EVIDENCE : "per author scope (canonical)"
    REVIEWER_STUDY_EVIDENCE ||--o{ FORM_SESSION : "one per form"
    REVIEWER_STUDY_EVIDENCE ||--o{ ANNOTATION_HEAD : "one per context"
    FORM_SESSION ||--o| SESSION_DRAFT : "draft with lease"
    FORM_SESSION ||--|{ FORM_SESSION_VERSION : "pins revisions"
    STUDY ||--o{ CLAIM : "capacity claims (v2)"
    STUDY ||--o{ SCREENING_OUTCOME : "one per profile (canonical)"
    STUDY ||--o{ PROFILE_ADJUDICATION : "per profile (R4p)"
    STUDY ||--o{ STUDY_POOL_LEDGER : "pool entries"
    STUDY ||--o{ RECONCILIATION_TASK : "one per form (R4a)"
    RECONCILIATION_TASK ||--o| EDITOR_CLAIM : "one holder"
    RECONCILIATION_TASK ||--o{ RECONCILIATION_ASSIGNMENT : "optional"
    RECONCILIATION_TASK }o--o{ FORM_SESSION_VERSION : "pins candidates"
    STUDY ||--o| STUDY_GOLD : "gold (canonical, reconciled)"
    STUDY_GOLD ||--o{ GOLD_SNAPSHOT : "immutable"
    STUDY_GOLD ||--o{ QUERY_WORK_ITEM : "per accepted version"
    STUDY ||--o| ANIMAL_POPULATION : "created when C1 enables"
    STUDY }o--o| PUBLICATION : "bibliographic identity (P1/P2)"
    STUDY ||--o{ CITATION : "immutable records"
    STUDY |o--o{ STUDY : "mergedInto (alias, never re-keyed)"
    STUDY ||--o{ STUDY_LIFECYCLE_LEDGER : "retrieval and lifecycle"
    STUDY ||--o{ EXPOSURE_LEDGER : "exposure"
    PROJECT ||--o| PRISMA_PHASE_MAPPING : "required profiles"
    PROJECT ||--o{ PRISMA_FLOW_SNAPSHOT : "frozen reports"

Resolution record

In the Where column, "patches (X)" names this drafter's change to X (contracts C1, C2 and C17; the decision register §2), now merged; the working patch file is not kept in the package.

Finding Category Where Note
DD-01 Adopted (PROPOSAL) §1.1, §4.1, §9 ReviewerStudyEvidence = (project, study, author scope); heads and revisions are entities; the F1a storage ADR decides documents within VB's four constraints
DD-02 Corrected §1.3, §10, §13 ProjectCommitSequence deleted; Study version plus clock stamp; E25 settled at F1a (brief §1.2)
DD-03 Adopted §6.2, §13 Event catalogue with the brief's three effect classes; C19 by the consistency drafter
DD-04 Adopted §6.1, §6.3; E59 Command catalogue and hosting rule; PM capture capability as an R0 item
DD-05 Adopted §2 Context map with relationship types; LegacyReviewDataAdapter named; shared kernels listed
DD-06 Adopted (PROPOSAL, shape F1a, freeze F3) §4.2, §7.1 Facets and CollectiveOutcomePolicy as single writer; the 25 September precedence rule is recorded as RECOVERED (research lines 818–823, verified by the consistency and versioning drafters)
DD-07 Corrected §4.3, §13; E63 Task keyed by study × form; ReconciliationSession is a task entity; the compatibility class leaves the F4 decision list
DD-08 Adopted (PROPOSAL) §4.7, §5, §9 Merge as alias; AliasResolutionPolicy; presentation is D2-12
DD-09 Adopted (PROPOSAL at F3) §4.4; E62 One Stage aggregate; Active derived; Completed refuses settings publication except via an approved change request
DD-10 Corrected (per brief §1.1) §4.1, §4.5, §6.2 Not batched materialisation of real versions: effects are derived on read and query-path projections are rewritten by an operation; "evaluate lazily on read" survives only as derivation for canonical readers; D2-01
DD-11 Adopted §8 Glossary with the renames; user-facing terms pending D3-03
DD-12 Adopted §4.5, §4.6, §7.2, §13 EntityTypeId minted at F1a; E14's identity part moves to F1a; O1 depends on it
DD-13 Adopted §1.7, §4.9, §5 Per-document CanonicalScopes marker in the existing write filter, scope-aware per VB-07
DD-14 Adopted §7.1; E60 Policy catalogue, each a pure Core service with a fixture suite
DD-15 Adopted §4.1, §10 Deterministic session IDs; the FormSession document is created on first autosave without touching Study
DD-16 Adopted §2, §5; A-30 Project named as the Membership root, conformist to #3335; embedded jobs an explicit non-goal before R7; AC-M0-02 Project-contention line for the acceptance drafter
DD-17 Adopted §1.9, §5 CanonicalSummary labelled a coexistence adapter retired at R7
DD-18 Adopted §1.8, §4.2, §4.7, §4.9 Ledger renames; one writer; ordering key
DD-19 Adopted §7.2; E61 Value-object list with equality rules and shared-kernel ownership
DD-20 Adopted §4.8, §7.1 Mapping stays project-level; StudyLifecyclePolicy in the outcome transaction
DD-21 Adopted §1.9; patches (C17) Every read model declares its regime and freshness marker
DD-22 Adopted §11; E58 Namespaces per context, internal default, fitness tests
DD-23 Adopted §6.1 platform-architecture.md corrected in the F1a docs PR
DD-24 Adopted §4.6, §10 Default population derived; aggregate only when C1 enables classification
DD-25 Question §1.5, §4.5 D2-15 (system catalogue plus copy from administered projects); principle 5 amended on that basis
DD-26 Adopted §7.2; patches (C1/C2) definitionOwner versus owningParent; "a candidate child never attaches to a reconciled parent" as a C1 conformance test
Q-D1 Question §4.5 D2-15
Q-D2 Noted §4.3 RE4 already decides one task per study × form; no question needed (brief §1.9)
Q-D3 Question §4.7 D2-12
Q-D4 Question §8 D3-03 ("Accepted answers (gold standard)")
Q-D5 Question §8 D3-03 ("Screening result")
V2-15 Corrected §3 StudyPdfCorrection and pmStudyPdfCorrection (verified through the generic repository); NumberOfStudies; roots at the Model root and inside ProjectAggregate/; ADR-020, M5b and outbox stores; writer inventory note
V2-16 Corrected §1.5, §4.5, §12 System-scoped definitions allowed with their own authorization; R1a keeps copy provenance on the template, so no Project field before R0
V2-17 Corrected §4.2, §4.4, §4.7, §5 ScreeningOutcomeSummary on Study is FEAT-011's one screeningOutcomes[] array; lifecycle mode owned by the lifecycle part only; pmDedupAuditLedger versus FEAT-012's pmDedupAuditLog; pmDedupBatch listed
V2-18 Corrected §4.1, §4.2, §10 Author scope in the session key through DefinitionOwner and separate reconciliation sessions; ProfileAdjudication versioned; conflict copy for the losing tab; ProfileSession as the screening container (PROPOSAL, fixed at F3/F5)
V2-20 Corrected §12 Rows for M0, R2d, R3d, R4c, R5a, O2, R6, GA; Project in R2a; profile-version usage at F5
V2-26 Corrected §13, §14 Zero-or-one relations; ExternalStepLedger to Project and search; StudyAlias; claims; every gate listed
PH-16 Corrected §7.2; patches (register §2) FEAT-001 D28, D49, D50-revised, D57 supersession rows; EntityPath element kinds
PH-27 Question §4.5 D2-15
PH-28 Adopted (PROPOSAL at F5) §4.5, §13 Keyword lists as a profile operational setting; project-level list legacy-only; no owner question needed
PH-30 Adopted §6.1, §13 ADR-009 cited for the hosting rule; ADR-008 for every new timer
RT-11 Adopted §4.11, §5 Claim contract v2; capacity claims on Study, editor claims on their aggregates
RT-15 Adopted §9 Rows summarised here; the table itself is consistency-model §4
RT §5.1 edits Adopted §3, §4.3, §4.11, §5, §9 Presence and connection rows; task editor and requested-review claims; projection with per-reviewer markers; FormSessionId
NS-03 Adopted §4.10 Generic Source, kind registry, one capture service
NS-18 Corrected §4.10, §5 #3944 removed from the projection's readers; conversations refuse canonical scopes until R4a
NS-19 Adopted §2, §4.10 Ownership split: capture, inbox, email, digests stay with the programme; StudyConversation to L6 at R4a; issues and checked PDFs to Study Management and PDF
NS §5.1 edits Adopted §3, §4.10, §9 PR-only records listed; Source, ResolvedAtUtc (D3-23), NotificationFanOut; capture modes per operation in consistency-model §4
AP-11 Adopted §4.4, §5 Settings versions reference regime and batch plan by ID; embedded fields legacy-only
VB §3 item 1 Adopted §1.1, §10 Collection list aligned with the storage blueprint; pmFormPublishOperation renamed pmFormVersionIssue

Cross-cutting brief items reflected without a finding row: DC-02 and AP-01 (CanonicalSummary with membership facts), MS-06 and MS-13 (FEAT-024 seam), VB-01, VB-02, VB-05, VB-09, VB-10, VB-13, VB-16, VB-18, RT-10, RT-13, RT-14, RT-18 to RT-21, RT-24, RT-26, NS-01, NS-06, NS-08, NS-12, NS-20, NS-24, AP-03, AP-05, AP-10, AP-14, AP-20, PH-05, PH-06, PH-07, PH-18, PH-25, PH-31.