Skip to content

Target architecture and shared contracts

Temporary planning document; planning only. This page defines the shared contracts that let the lanes in the integrated plan work in parallel. Each contract has an owner, consumers, a freeze gate and conformance tests. Field lists are logical and illustrative; physical storage is decided by ADR at the engine freeze F1a (E15).

Revised after round-2 review (3 October 2026). The contracts now summarise the round-2 companion documents and defer to them for mechanics: the versioning model (compatibility, options, publication, sessions, and reconciliation under versioning), the consistency model (transactions, idempotency, ownership markers, fences, durable effects, ordering and restore), the revised domain model (aggregates, naming, events and commands), programme integration (allocation, batches, eligibility, tracking, statistics and notifications), the UX strategy and methodology coverage. The single engine freeze F1 is split into F1a (engine contracts), F1b (catalogue and export disclosure) and F1c (IA, copy, AF2 seams and the Dockview amendment), as the delivery operating model §3.3 sets out. Two contracts are new: C18 (concurrency, transactions and idempotency) and C19 (durable effects and events). Decisions still pending with Chris cite their Batch D question IDs (D1-xx to D4-xx).

Revised after the owner session (5 October 2026). Chris's owner session of 4 and 5 October amended C1 to C19 and added three contracts: C20 structured history events, C21 duplicate consolidation and reversal, and C22 external and AI-model screening sources. The catalogue now holds twenty-two contracts (C1–C22). The owner-session consolidation wins over older text, and the nine specifications (prefixes RD, DM, SP, RS, BC, TI, RI, UX, AC) carry the detail; each contract below cites the specification rule it now follows. Superseded rules are kept and marked "Superseded by the owner session (5 October 2026)", and amendment IDs OS-A01 to OS-A30 are listed in the owner-session integration. Feature implementation remains on hold (Chris, 5 October 2026). The owner decisions are planning approval. Brief approval and implementation authorisation are separate per gate (D1-04) and still on hold; no work has started, no gate has passed and nothing is enabled in production. Thresholds quoted here are proposed, not approved.

The aggregates these contracts imply (new ones, changes to existing ones, transaction boundaries and the release that introduces each) are brought together in the domain model.

Labels: a rule followed by an owner decision ID is that decision (OWNER, or recovered where the register says so). Rules marked PROPOSAL are recommendations from earlier designs or from this plan. Baselines are CODE-MAIN unless marked otherwise. Engineering items (E1–E35, and E36 onwards from the round-2 documents) are in open questions §2.

1. Design stance

  1. One shared annotation infrastructure, explicit domain capabilities. Ordinary answers, profile-owned screening decisions and, later, classification assertions and quantitative observations share identity, revisions, context, provenance, commands and history. They keep distinct validators, authority and derived results. The research verdict rejects a generic graph that infers scientific meaning (classification research §8).
  2. Forms own evidence; stages own workflow. A form version defines requirements and target. A stage settings version binds form/profile versions and defines steps, routing and policies. Stages never copy evidence or targets (SF1/SF2, PV2). Owner session: the standard reviewer target is inside the immutable form version; the form owns the inactivity timeout, the in-progress limit, the capacity cap baseline, reconciliation identity blinding and the reconciled-hint baseline (the profile owns screening reconciliation blinding); a stage owns its study filter, its steps and their dependencies, and may only narrow (a stricter route cap, hiding hints at a step). There is no incoming stage-entry gate (Q-15).
  3. Immutable history, explicit transitions. Autosave is draft. Save and Complete create immutable versions. Publication, correction, Fix, withdrawal, release and approval are explicit commands with receipts (SL1–SL3, SF5, FV1–FV4, RA4, LC1). Owner session: publication may create attributable generated session versions (D2-01 amended); merges and unmerges create attributable versions on the Study they target (C21); history explains past eligibility in structured events and never decides current access (C20).
  4. Extend existing machinery rather than clone it. Reuse FEAT-024 projections (its receipts stay statistics-protocol receipts; C18 owns command idempotency), allocation buckets, presence/claims, progressive batches, ReviewEligibilityPolicy, AF2, the question designer, import/template paths, the notification stack, the authorization programme's evaluator and audit, and existing grants (OPS1 and the 3 October notification update).
  5. The server is authoritative. Every read and command checks scope, permission, admission and blinding. UI hiding is never a control.
  6. Fail closed on unsupported scope. A project, form or context the new path can't represent is rejected before editing. Ownership is never split between legacy and canonical writers, and ownership is data, not configuration (C16).

2. Contract catalogue

ID Contract Owner lane Main consumers Freeze gate
C1 Canonical annotation identity, revisions, commands and Study coupling L1 Engine L2–L6, L9–L12, L15 F1a
C2 Answer context identity and sharing L1 Engine L2, L5, L6, L9 F1a
C3 Provenance, exposure and history capture L1 Engine L5, L6, L11, L12 F1a
C4 Question, form and profile definitions and versioning L2 Definitions L1, L3–L6, L9, L10, L13 F1a (identity, compatibility and publication shape), F2 (publication), F5 (profiles)
C5 Form session lifecycle, drafts and contribution qualification L1 Engine L4–L7, L11 F1a
C6 Workflow binding, steps and admission L4 Workflow L5–L7, L12 F3
C7 Operational projections and claims (statistics, allocation, presence, batches) L7 Operations, with existing owners L4–L6 F1a (identity, claim contract v2), F3 (routing), F-A (allocation)
C8 Version usage evidence and protected publish boundary L7 + L2 L2, L3 F2 (forms), F5 (profiles)
C9 Reconciliation task, gold snapshots, assignments and queries L6 Reconciliation L5, L11, L12, L14 F4
C10 Capabilities, groups, delegation and disclosure L8 Permissions All F1b (catalogue, export disclosure), per feature
C11 History, export and manifests L11 History L12, L15 F1b (versions, previous-version exports), F6a (as-of); HLC stamps freeze with C18 at F1a
C12 PRISMA units, authority and report manifest L12 PRISMA L3, L11, L15 F3 (write-shaping parts), F-P (identification), F6b (reports)
C13 Classification, populations and inference L9 Classification L5, L6, L10 F-C (population key and EntityTypeId at F1a)
C14 Outcome schemas, measures and observations L10 Outcomes L5, L6, L11, L15 F-O
C15 Notification capture contract (C15 v2) through the existing notification stack Notification programme; L14 writes the specification L2, L4, L6, L12 F1b (contract); kinds per feature
C16 Compatibility floor, admission and reader/writer compatibility L0 Integration All F1a
C17 Information architecture, coexistence, overview and settings DTOs L16 Admin UX L2–L8, L13 F1c (IA, copy, AF2 extension points, Dockview layout amendment), F3 (DTOs, coexistence)
C18 Concurrency, transactions and idempotency L1 Engine with L0 All writing lanes F1a
C19 Durable effects and events L1 Engine with L14 L2, L4, L6, L12, L14, L15 F1a
C20 Structured history events (owner session) L4 Workflow with L11 History and L1 Engine L2, L3, L6, L7, L12, L14, L15, L16, the training lane, XS1 F1a (envelope, storage, idempotency and ordering), F3 (stage-pool and eligibility event types)
C21 Duplicate consolidation and reversal (owner session) L12 PRISMA (deduplication) with L1 Engine L3, L4, L6, L7, L11, L14, L15, L16 F-P (after the current evidence view proof); P2a, P2b and P2c deliver it
C22 External and AI-model screening sources (owner session) L3 Screening profiles with L12 PRISMA and the XS1 lane (proposed ID) L4, L6, L8, L11, L12, L16 F5 (the reserved ScreeningSourcePolicy slot in the profile-version shape), XS1 freeze (the contract)

The owner session (5 October 2026) amended C1 to C17 and C19 as marked in each section below and added C20 to C22; C18 is unchanged apart from new typed outcomes. The catalogue holds twenty-two contracts.

3. Contracts

C1 — Canonical annotation identity, revisions, commands and Study coupling

Implements: SF1–SF3, SL1–SL3, PV1, DP3/DP4 (screening as a specialised kind), GS1 inputs. Current baseline (verified at 78c6d097d, unchanged at 2949ca3a7; the Study read-surface bullet re-read at eb93caffa; see the inventory):

  • Annotation subclasses (bool, int, decimal, string, plus arrays) are mutable and embedded in Study, with client-supplied stable IDs and a StageId that is only a provenance stamp.
  • A save removes all of the caller's answers to the stage form's questions, whatever stage they came from, and adds the submitted ones (ExtractionInfo.cs:183-194). A cross-stage save therefore changes what an older session exposes.
  • Screening is a separate mutable entity keyed by project + screener, with no profile and no history.
  • Writes go through SubmitAnnotationSessionService (three CAS retries, FEAT-024 source-operation receipts bound to the Study version) and must honour bulk-update study locks (Study.cs:242).
  • Study's legacy read surfaces are computed getters whose results are persisted: ExtractionInfo.SessionTallies, the SessionTally sums and ScreeningInfo's inclusion members are recomputed from embedded data on every whole-Study save, and stored values are ignored on read (StudyRepository.cs:3176-3228, ExtractionInfo.cs:31-81). ScreeningInfo, ExtractionInfo and SessionTally have no extra-element capture. Entity subclasses capture unknown elements through [BsonExtraElements] (Entity.cs:21-22), and FEAT-024's pending classes both ignore and capture them (StudyPendingStatistics.cs:14-19). C16 and the consistency model §3 address both.

Detailed analysis: screening research §1.

Logical model (illustrative):

Element Fields / rules
Annotation head annotationId (server-minted, or client-proposed and validated; legacy IDs preserved through the adoption manifest and LegacyIdAlias), kind (OrdinaryAnswer, ScreeningDecision, decision-owned answer; later ClassificationAssertion, Observation), contextKey (C2), definitionOwner (project, or the profile for eligibility answers; DD-26), author or authority scope, currentRevisionId. One head per context key (C2), so per author or authority scope and compatibility class.
Revision revisionId, annotationId, immutable typed payload, questionVersionRef, parentRevisionRef and owningParent edges (answer-tree ownership; distinct from definitionOwner), provenance (C3, including authorship), recordedAt, its per-aggregate sequence and HLC stamp (C11, C18), commandId
Command commandId (minted per user intent and reused for every retry) and a request digest; the bases the command observed (session version, draft etag, task input etag, query target; CR-5); actor, realActorId and onBehalfOf; admission evidence (C6). Its command-bearing record is its receipt (C18)
Kind policies Validators and authority per kind: one effective screening decision per reviewer/study/profile; decision-owned reasons; derived decision confirmed only on explicit submit (DP3)
Study canonical summary Study.CanonicalSummary, a top-level sub-document keyed by form and profile: per form, per-reviewer members {state: placeHeld, savedIncomplete, completed or withdrawn; standing: qualifying, needsUpdating, pinnedOlderCounted, pinnedOlderNotCounted or notApplicable; versionSeq; claimActivities; admittingRegimeId; routeStageId}, where 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 screening outcome summary (FEAT-011's screeningOutcomes[], one array); a per-bound-stage projection (tallies) for legacy readers; readiness flags; and the definition-version vector it was evaluated under. Written in every study-scoped canonical transaction and by projection-rewrite operations; legacy getters and predicates merge it from R0 (E20, E48; consistency model §3.3). Readers (pool filters, capacity guards, readiness, statistics, exports) reach the membership facts through IReviewMembershipFacts. #3944's candidate lookup is not a reader: conversations refuse canonical scopes until R4a. A coexistence adapter, retired at R7 with the readers in E20's inventory, and not the legacy computed fields. Owner session: the per-form member list moves to the CurrentEvidenceView (Study.currentEvidence, C21), which also carries the effective target and the current accepted result; the summary gains filterInputs[] and stagePoolTracking[] (C20, SP §3.5) and the per-reviewer standing excluded (contribution exclusion, ACD §3.2)
Merge and split A dedup merge is an alias that never re-keys immutable records: Study.mergedInto on the secondary plus a StudyAlias entry on the primary. Reads, candidate selection, statistics and PRISMA resolve aliases (AliasResolutionPolicy). A reviewer who reviewed both is counted once: the current session is chosen and the other superseded with provenance. Merges and splits are ADR-020-style operations that write both Study documents and refuse busy studies; a split removes the alias and re-derives (E33, amendments D and L; presentation D2-12). PROPOSAL. Superseded by the owner session (5 October 2026; D2-12 replaced), see C21 below: one consolidated current Study, atomic activation, conflict resolution before commit, reversible unmerge; input records are never edited
Version kinds (owner session) Besides Save, Complete, Fix, Upgrade and Withdraw: PublicationGenerated (attributed to the publication operation and the publisher, D2-01 amended, C4) and MergeResolved, MergeCarriedForward, UnmergeCarriedForward (attributed to the merge or unmerge operation, C21). The reviewer stays the effective author of answers carried or re-pinned; an operation never records a Complete that fails validation

Invariants:

  • A revision is never edited. A retry with the same commandId returns the original result from the command ledger; a different request digest under the same ID is refused (CommandDigestMismatch); an indeterminate commit returns OutcomeUnknown, and the client retries the same ID. A stale base is rejected with a typed conflict that keeps the draft. Kind validators can't bypass common checks (research A20, A23).
  • Command ledger (E50, replacing E35): each canonical command writes one command-bearing record with a unique (ProjectId, CommandId), the result IDs and the request digest. FEAT-024 source-operation receipts stay statistics-protocol receipts; FEAT-024 reuses the CommandId as its OperationId, for correlation only (C18).
  • Study coupling (E20, CR-1): every canonical command that changes evidence, gold, outcomes, capacity claims or any fact in the canonical summary writes the Study document in the same transaction: an Audit.Version compare-and-set, the summary and the study clock. It writes Study only through FEAT-024's source-write seam, so pending entries or intents follow the project's statistics path; the engine never writes statistics itself. No per-project or per-form document is written by interactive commands (CR-2).
  • Real actor: every command, receipt and revision records the real actor and the effective author. Support edit-mode writes are flagged and excluded from independence statistics.
  • Limits: an explicit ceiling in pins and bytes per commit applies until large immutable submissions are proven (E28, D2-16). Superseded by the owner session (5 October 2026; D2-16 replaced): no form is excluded for size; the largest project (2,023 questions) is an acceptance case and the E28 limits are engineered and measured at or above that tier (RD-R33, RD-AE23).

Conformance tests: the screening research's acceptance cases A1, A3, A7, A8, A11, A13, A14 and A20–A23, and C18-T01 to C18-T04 (the DC review's AC-DC-01 to 04). Answer and ScreeningDecision pass the same suite through one logical repository. A canonical commit racing a bulk-update lock conflicts. Legacy readers see correct tallies through R0's floor (AC-R0-09). A candidate child revision never attaches to a reconciled parent (C1-T09; DD-26). A merge leaves every secondary-study record unchanged and the primary counts each reviewer once (owner session: restated by C21-T07 and C21-T12 for the consolidated model). Test IDs: C1-T01 to C1-T17 and C1-T19 (acceptance criteria §7.5); C1-T18, the alias merge, is retired by the owner session in favour of C21-T07 (superseded wording 2).

C2 — Answer context identity and sharing

Implements: SF3, SF5, DP4, SF6 (flags). Same reviewer + same study + same question identity + same entity or branch context + same compatibility class = the same shared answer. QuestionId alone never merges repeated entities or branches. Eligibility answers are scoped to their profile (definitionOwner), so two profiles never share answers even with identical wording. The rulebook is the versioning model §3.5, §6.

Logical key (frozen at F1a), the AnswerContextKey value object: {projectId, studyId, authorScope (candidate reviewer, reconciled, imported), definitionOwner (project | profile:<id>), questionRef {questionId, systemQuestionVersion?}, classSeq, entityPath[], populationId}. classSeq is the compatibility class of the pinned question version (versioning model §3.5): one head exists per context and class; a revision under an incompatible version creates a new head whose lineage SF5 shows read-only. entityPath[] elements are typed instance identities from the root: instance(labelHeadId) for reviewer-created entity units, instance IDs for repeated-answer branches, and optionBranch(optionId) for option-keyed multi-select branches (PH-16). Every answer carries a population from its first write: the default whole-study population ID is derived deterministically from the study ID, so enabling classification never re-keys answers and needs no document (DD-24). Decision heads (kind ScreeningDecision) omit questionRef, classSeq and entityPath; decision-owned answers add the owning decision's head ID. The key is stored as an ordered value object beside contextKeyHash (SHA-256 over a versioned canonical serialisation); unique indexes are on scalars only ({projectId, contextKeyHash}, plus partial unique indexes per kind), never on the array, because a unique index over entityPath[] would be multikey (VB-05).

Two ownership notions, named apart (DD-26): definitionOwner (part of the key: which requirement owner defines the question, DP4) and owningParent (a revision edge: a decision owns its reason revisions; an answer may own child answers). Ownership forbids cycles, cross-study edges, a reason owned by two decisions, and a candidate child attached to a reconciled parent.

Rules: show the reviewer's own prior answer and all ancestor answers across forms and stages in the matching context (SF5), including heads of earlier classes, read-only. Changing a shared answer creates a new revision on its head; every other session of the same reviewer pinning an older revision of that head is flagged "contains outdated annotations"; nothing adopts the new revision automatically; the flag alone never removes qualification (SF6). Two forms pinning incompatible versions of one question never flag each other (different heads). Legacy duplicates that conflict adopt as one head in state Conflicted with no current pointer until the owner's Fix or Save; it is shown with a conflict marker and excluded from prefill, agreement and autoUpdate. Entity instances: identity is the label head ID in the author's scope (client-proposed, server-validated, minted once); rename is a label revision; delete is a withdrawal commit on the label head and its descendants; duplicate mints new IDs with copiedFrom provenance; population membership is an instance attribute (versioning model §6.5).

Owner-session amendments (5 October 2026). Option mapping is decided (Q-34): a mapping declared by the publisher writes new immutable revisions on the same head with mapping provenance and keeps the originals (RD-R21). A hint copied by click-to-fill writes an ordinary candidate revision on the reviewer's own head with adoptedFrom; it shares no head with the reconciled scope (RS-R33). The imported author scope is restricted to mapped human annotation imports (XA1); external and AI-model screening decisions are not candidate heads and live in C22 records. Author scope training(attemptId) keys training sessions apart from live heads (TI §3.4). A duplicate consolidation creates heads under the consolidated Study's key and copies current revisions with provenance; heads on input Studies never change (C21). Hints are offered only where the answer context matches without instance correspondence (Study-level questions and option branches); hints for repeatable entity instances wait for a correspondence rule (RS-R37, PROPOSAL).

Conformance tests: identical QuestionId under different entities stays separate; heads that differ only in the second entityPath element coexist and an exact duplicate is refused; ancestor lineage across two forms including an earlier class; a compatible added option shared across two forms with no flag; two forms on incompatible versions never flag each other; a v2-only option is never offered under v1; legacy duplicate conflict surfaced as a Conflicted head; two profiles stay separate; candidate and reconciled heads stay separate; a candidate child never attaches to a reconciled parent; unit delete flags the reviewer's other forms, rename keeps identity, duplicate mints new IDs; enabling classification changes no existing key. Test IDs: C2-T01 to C2-T08 (acceptance criteria §7.5).

C3 — Provenance, exposure and history capture

Implements: PV1, VS2, GS1 context, EX2 legacy coverage.

Record Content
Revision provenance Source stage, step, stage-settings version (the requirement-bearing part only, D2-05), question version (questionVersionRef), accepted-answer revision actually shown (if any), real actor and on-behalf-of, authorship (reviewer, reconciler, adjudicator, policyDerived, legacySnapshot, imported), command ID, HLC stamp, recordedAt, optional observedAt (evidence only, never ordering)
Session-version workflow context Stage/step route used, declared (pinned) form version, accepted snapshot available, the full pin map (head → revision) of every answer in the session at that version, the resolved question set, exposure state, command ID, HLC stamp
Exposure state Three states, failing safe: no gold available (derived on the server from "accepted snapshot available"); exposure recorded (an accepted revision rendered into view, deduplicated per session version and revision; and the kind "questioned in reconciliation", NS-06, which makes later versions of that reviewer's session on that study × form informed); available but unrecorded, treated as informed or unknown, never as independent. Visibility permission alone is not exposure. Exposures travel in the draft, Save and Complete payloads and are recorded in the commit; late events are accepted keyed by draft etag and base version; the independent, informed or unknown class is derived on read, so a late event downgrades it. Exposure never travels over the presence hub (RT-26).
Observation-basis markers (PROPOSAL, frozen at F1a) Initial independent submission: the first effective Complete (form) or decision (screening) by a reviewer for a (study, form) or (study, profile) context, made before any collective outcome, accepted answer or adjudicator output for that study was visible to that reviewer; derived at commit from the commit order and the visibility events; stored on the session version. Collective exposure at correction: for DP2 corrections, extra votes and the discussion route (D4-02), whether the collective outcome (Pending, Conflict, Included, Excluded, Unsure) or any reconciler or adjudicator output was visible to the actor, and through which route (availability, discussion, monitor); written on the correcting submission. Questioned in reconciliation: the exposure kind above, written by #3965 and looked up by session; consumed by R5c, C11 manifests and R6 adoption mapping. Calibration purpose: purpose = calibration records (D4-04) never vote, qualify or count. Conversations are audit record only, never agreement inputs except as these markers (D3-25). Owner-session kinds (5 October 2026): reconciledHintShown (HintExposure, written when a hint control renders in view) and reconciledHintAdopted (HintAdoption, written on click-to-fill; the revision carries adoptedFrom with the source revision, snapshot and mapping), so an adopted answer is informed and never an independent observation while still counting for progress (RS-R34, RS-R35); the screening discussion exposure, recorded when a discussion opens (RS-R61); trainingReferenceShown for training feedback (TI). D4-04 is decided-amended: calibration becomes training under its own records (TI), which never vote, qualify or count
Operation provenance (owner session) A version or revision written by an operation records the operation and generation, the actor (the publishing admin, the merging user, the resolver, the system rule) and the exact source versions: PublicationGenerated versions (C4), merge and unmerge records (C21), system-authored SingleAnnotator revisions with derivedFrom (C9), promoted training evidence with promotedFrom (TI). The actual resolver of a merge conflict is recorded; an admin's choice is never presented as a reviewer's (DM-R06)
Import/migration provenance Source system, legacy ID (kept through the append-only LegacyIdAlias table), mapping version; historyCoverage (observed-record-only, unknown-authoring, …); AuthoredUnder typed union on adopted revisions: Verified(v1) when the stored Annotation.Question wording equals the adopted v1 wording, otherwise Unknown (excluded from same-version agreement and exact-match prefill); migration time is never presented as original time. Imported authority (PROPOSAL): decisions and answers imported from a CSV column or another tool (FEAT-004, D4-14) carry authority = Imported with source system, import job, mapped investigator and independence ∈ {unknown, declared-independent (declaring admin, time)}; declared-independent records count toward sufficiency and appear in a labelled agreement view; unknown ones never count toward sufficiency or agreement; for PRISMA they are "screened in SyRF (imported record)" (amendment K rule 6); they never become gold or adjudicated outcomes automatically. Owner-session amendment (5 October 2026): "imported authority" becomes imported provenance with the independence declaration, restricted to mapped human annotation imports (D4-14 decided-amended, lane XA1; RI §3.10); Imported is a candidate provenance kind, never an outcome or accepted-result authority. Configured external and AI-model screening sources follow C22: each decision records its source type, the machine source identity (never a member or login), the exact model configuration and run versions, the importer and accepter separately, confidence and threshold where supplied, training-input flags and explicit missing metadata, and counts by the profile's ScreeningSourcePolicy; the reviewer-mapping requirement no longer applies to these sources (superseded wording 17). Migration provenance uses the legacy-gap states NotRecordedInLegacy, CurrentSnapshotOnly, UnknownLegacyAuthor, UnknownLegacyTime, UnknownAuthoredUnderDefinition (the AuthoredUnder = Unknown case), ValueOrDefaultUnknown and LegacyCompletionUnvalidated; they are never answer values (BC §3.2)
History capture from first admission Append-only capture of legacy-path writes for enrolled projects: legacy screening from R2a, pool entry from R3a, retrieval and lifecycle from P1 (E26, E54). Captured inside the aggregate: the legacy write appends a bounded entry to a top-level Study log in the same document write, and a leased worker moves entries to pmLegacyWriteLedger; overflow is a coverage gap (consistency model §12). Owner session: "pool entry" means first release (WorkFirstReleased); stage pool membership history is C20, and for a legacy stage it starts at conversion with StagePoolBaselineMember events and earlier history labelled NotRecordedInLegacy

Conformance tests: a reused answer keeps its original authoring stage. An informed contribution counts for progress but is labelled informed in agreement statistics. A lost exposure report never turns informed work into independent work. Legacy records never gain fabricated versions. An adopted answer whose stored wording equals the v1 wording is Verified(v1); one whose wording differs is Unknown and is excluded from same-version agreement. A reviewer questioned in reconciliation who saves a new version is classified as informed. A DP2 correction after a visible conflict never changes the initial-observation agreement. An imported decision with independence = unknown never counts toward sufficiency. A calibration record never creates a pool-entry or screening event. Owner session: an adopted hint is recorded and excluded from independent agreement (RS hint fixtures); a training attempt writes no pool, release, target or PRISMA input (TI-AE01); external decisions and AI-model-generated screening decisions follow C22-T01 to C22-T17. Test IDs: C3-T01 to C3-T09 (acceptance criteria §7.5).

C4 — Question, form and profile definitions and versioning

Implements: FV1–FV4, VU1–VU3, recovered transition choices, DP4, DP5, RX1, TC1, SET1 (templates copy). Current baseline:

  • AnnotationQuestion is embedded in Project and edited in place. Its fields are at AnnotationQuestion.cs:107-150: target/parent, root, label, category (one of seven hard-coded values), type, control, multiplicity, conditional parents, filtered options, lookups, answer labels.
  • System questions are rebuilt from code on every read, and their structure depends on Project.SystemQuestionVersion: in v0 and v1 projects the outcome error-type question has a different parent and option filters (AnnotationQuestion.cs:559-592).
  • Placement rules apply to new questions only; parent and category can't change.
  • Deletion cascades to answers. Answered questions are locked in the new editor rather than versioned. The only version-like markers are the schema version and SystemQuestionVersion.

The QM v2 domain (#2572/#2573) is unmerged reference code harvested per Q-08; the versioning model's §12.6 says what to harvest and what to avoid. The rulebook for everything below is the versioning model; this contract summarises it.

Identity versus content. A question is identified by questionRef {questionId, systemQuestionVersion?} plus structural identity {definitionOwner, parent, entityTypeId, repeatable}; a structural change is a new question with lineage by reference. Data type and selection multiplicity are version content and a change to either is always incompatible (PROPOSAL, Batch D D2-03; FEAT-001's D38 is the alternative). Stable system entity-type IDs for the seven legacy categories plus cohort, outcome measure and experiment are minted at F1a; the category string is a display alias (DD-12).

Definition Identity Immutable version content (once committed; published through forms or profiles) Operational settings (audited, read live, no impact flow; D2-05)
Annotation question (project-owned) questionRef, definitionOwner = project, parent, entity type, repeatable Wording, description, help, control type, display labels, data type, selection multiplicity, validators, options {optionId, value, displayLabel?, description, parentFilter (option IDs), state}, conditions (option IDs), response modes and metadata fields, "Why it changed", "What reviewers need to do differently", compatibleWithPrevious with the system suggestion, the admin's confirmation, rationale and optional option mapping (Q-34). Owner session (D2-02 amended, Q-34 decided): compatibility {suggestedBySyrf, declared, declaredBy, declaredAt, rationale} and optionMapping {oldOptionId → newOptionId, declaredBy, declaredAt}, declared explicitly by the authorised publisher, normally when publishing the first form or profile version that pins the question version none
System question (systemGuid, SystemQuestionVersion); definitionOwner = system Stored as data in a global store, seeded idempotently from code, published by CAMARADES with the same compatibility declaration; never rebuilt per read; never keyed by code revision (D2-06) none
Profile eligibility question Same editor and types; definitionOwner = profile:<id> As above; copied from templates, never live-linked (DP4) none
Annotation form formId (project-owned) Requirement version (formId, seq): ordered question-version pins including all ancestors (one version per question), per-question requiredness and minimum instance counts, the validated applicability graph, the renderability result, entity types present, allowed outcome-schema versions from O1. Owner session: FormVersion.standardTarget (target-versions-form, OS-A12) and ReconciliationPolicy {targetOneHandling ∈ AutoAccept, RequireHumanReconciliation (R1; conversion alone may set NoAcceptance, RS-R04a PROPOSAL); acceptedCompleteness (Q-04); identityBlinding (Blinded default); reconciledHints (Shown default); outdatedAnswerCompletion (WarnAllowComplete default or BlockUntilAddressed, D4-17)}; the last four are classified inside the version as PROPOSALs (RD §3.5) Minimum target (SF2, SF4), optional capacity cap (D3-17), reconciliation compare settings, gold-completeness policy (Q-04), form guidance (A-15), bulk-approve flag (Q-11). Owner session: the minimum target leaves this column (superseded: it is inside the version); gold completeness moves into ReconciliationPolicy; the column holds the inactivity timeout and per-reviewer in-progress limit (D2-07), the CapacityCap baseline (D3-17, off by default, PROPOSAL defaults), optional unstarted-assignment expiry (Q-30, off by default), bulk acceptance (Q-11, off by default), comparison display and guidance
Screening profile profileId Criteria version (profileId, seq): eligibility question pins with ancestors, decision rules, must-agree supporting answers (RX1), requiredness, compatibleWithPrevious. Owner session (ScreeningProfileVersion): sufficiency rule; unsureEnabled (D4-01, on in the title/abstract template); tiePolicy ∈ ExtraReview with a bound or Adjudication, with handling per trigger and no inferred default; discussionEnabled (D4-02); adjudicationRationaleRequired (Q-32, off by default); reason handling (DP5, RX1, primary reason as template guidance, S3); identityBlinding (Blinded default); the ScreeningSourcePolicy slot (C22) DP5 toggle, agreement and resolution routes (RX1), rationale settings (Q-32), Unsure/Maybe and discussion route if D4-01/D4-02 approve, reference to the project's PRISMA phase mapping (C12). Owner session: DP5, routes, rationale, Unsure and discussion move into the criteria version (superseded here); the column keeps the PRISMA phase mapping reference, optional assignment expiry for adjudication tasks and keyword lists (PH-28); the adjudicator assignment is a separate AdjudicatorAssignmentVersion that needs no profile publication
Template (templateId, seq) Copy source only; a copy is a new identity at seq 1 recording copiedFrom; a template change never changes a copy. Owner session (D2-15 amended): the system scope is one application-wide CAMARADES catalogue (CatalogueItem, CatalogueItemVersion) with copy provenance copiedFrom {catalogueId, itemId, versionId, copiedBy, copiedAt} and publication requests none

Compatibility (frozen at F1a; versioning model §3.5). compatibleWithPrevious(Q, n) is declared when version n is committed: the system suggests it from the diff (presentation, added options, renamed options keeping their ID, condition and filter changes, validator changes, added modes → compatible; retired or replaced options, removed modes or required metadata → incompatible; data type or multiplicity → incompatible, never loosened), the admin confirms, may tighten freely and may loosen only with a one-to-one option mapping and no free-text change (Q-34). The declaration is immutable once any revision pins version n (D2-02); before that a change recomputes classes and re-validates active publication policies. Superseded by the owner session (5 October 2026; D2-02 amended, Q-34 decided): the authorised publisher declares compatibility and whether mapping applies, explicitly and with actor and time; the declaration and the mapping are immutable from commit; a meaning change must be declared incompatible; mapping never bypasses type or option validation or a mandatory re-review; a wrong declaration is corrected by guided rollback and republication, which commits a corrected question version (same content, corrected declaration) and publishes a new form version whose phase 2 generates restoring versions, while the wrong declaration stays in history with a "corrected by" link (RD-R20, RD-R21, RD §4.13). Classes: class(n) = class(n−1) ∪ {n} if compatible, else {n}; classSeq = the lowest version in the class; compatibility is an equivalence relation, which is FEAT-001's breaking transitivity restated. Per-answer validity is separate: an answer is valid under a version when the classes match, every selected option ID is active (or mapped), the response mode and metadata exist, and validators pass; applicability is evaluated separately by E23 and never counts as invalid. SF3 and SF5 share only within a class; AG3 compares only within a class and flags differing versions; FV3 qualification needs class match and validity; RE4 holds a question whose candidates span classes; RE5 prefills only within a class; gold whose class differs from the form's current pin is flagged for re-reconciliation.

Options. Every option has a stable optionId; canonical answers store option IDs; values and labels are display data resolved from the pinned version; conditions and parent filters reference option IDs and are validated against the pinned parent version (composition validity); renaming keeps the ID and is compatible; retiring is incompatible unless mapped.

Response modes, metadata and suppression (PH-06). Modes and metadata fields are version content; a payload is value XOR responseModeId plus validated metadata; descendants suppressed by an ancestor's answer or mode are preserved (state NotApplicable, derived per ancestor instance) and never tree-shaken on the canonical path; exports resolve suppression. "Not applicable" is an explicit mode; blank is not N/A (UA1).

Applicability (E23): one written specification of which questions apply (multi-option conditional parents by option ID, filtered options, branch context, ADR-011 hybrids mapped to option IDs), with shared fixtures run by both the .NET validator and AF2, based on FEAT-020's rules file (PH-07). The same evaluator drives server Complete validation, Needs updating (VU1), reconciliation validity (RE2) and UA1. Typed errors name the blocking question and context.

Composition and renderability. A requirement version is composable only if every pinned child's condition and parent filter resolves to an active option in the pinned parent version; the validated graph is stored in the version. AF2's structural guards run server-side at publication with shared fixtures; a version AF2 cannot render is refused (FormVersionNotRenderable); canonical routes render on AF2 through a VersionedAnnotationFormDataSource that loads the pinned versions by ID and never fall back to AF1 (VB-08).

Two-step publication. Committing a question version has no session impact and no prompt. Publishing a form or profile requirement version is the only impact point (FV2, Q-26). A new system question version reaches a project only when its admin publishes a form version that pins it (D2-06). Operational settings changes never publish anything. Owner session: a change to the standard target creates a new form version and goes through the publication impact process even when no question changes (target-versions-form; RD-R12); its preview lists sufficiency, readiness and accepted-result changes and every Study target override with an explicit treatment (keep the effective value, rebase or remove; RD-R16, treatment set PROPOSAL); a target-only publication generates no session version and may generate result and override versions (RD §4.9, RS §4.6).

Publication command (FV2/FV3/PS3; versioning model §8):

  • Input: the requirement version to publish; per question a change class derived from the diff with every prior version in use, added (required: countEarlierCompletes | requireAnswerBeforeCounting), removed (dropFromRequirement; answers stay in history; children of a removed parent become not applicable), changedCompatible (autoUpdate | requireReanswer | doNothing), changedIncompatible (requireReanswer | doNothing), mapped (autoUpdate applies a one-to-one Q-34 mapping | requireReanswer | doNothing); per category (completed, saved-incomplete, draft-only) whether the treatments apply, and for completed sessions left pinned whether they count toward the new requirement (FV3); the admin's rationale. autoUpdate is offered only within a class and satisfies only valid answers (SR-16); it writes no revision. The dialog follows FEAT-003's four steps (scope, compatible, incompatible, confirmation) with the system suggestion and per-question and per-category counts (U6).
  • Preconditions: usage evidence at the protected boundary (C8, Q-31; draft_only counted authoritatively from drafts by base form version, MS-03), the preview digest, and a recorded admin choice. One active publication per form (unique partial index; D2-11); a second publish is refused.
  • Effects are derived, never written (D2-01). Publication writes no session versions and no answer revisions. Session standing (satisfies, needs updating, pinned older counted or not counted) is derived by one evaluator from the latest explicit version, its full pin map, the current published version, the recorded policy generations and per-answer validity; canonical readers derive it on read. The only derived-revision writer is Q-34 option mapping, which writes one policyDerived revision per mapped head and operation, with provenance, excluded from SF5 outdated flags. Superseded by the owner session (5 October 2026; D2-01 amended, OWNER): publication may create attributable generated session versions (kind PublicationGenerated). For each affected session whose latest explicit version pins an older form version in a category the admin chose to treat: autoUpdate with every answer valid re-pins the same revisions to the new version; Q-34 mapping writes new revisions with provenance {sourceRevisionId, mappingRef, operationId, generation} and re-pins to them; requireReanswer on an answered question and a new required question under requireAnswerBeforeCounting re-pin and leave the session incomplete, so a completed session stops qualifying. No version is generated where every changed question is doNothing, where only the target or a policy changed, under countEarlierCompletes, outside the chosen categories, or for a draft-only session (its draft is rebased); there standing stays derived. One session gets at most one generated version per publication generation; it is attributed to the operation and the publisher, keeps the reviewer as effective author, never records a Complete that fails validation, and never overwrites a newer reviewer version (RD §3.15; generation table PROPOSAL, whether autoUpdate generates is confirmed in the brief). SF6 now applies literally.
  • Two phases (consistency model §4, §7): phase 1 is O(1): fence the form, drain, re-check the preview digest, CAS the form head and write the policy record (generation 1) and the operation record in one short transaction. Phase 2 is an ADR-020-style operation that rewrites query-path projections by predicate until nothing matches, writes the Q-34 derived revisions, and captures notices once per recipient; admission and readiness for the form pause while it runs (D2-10). The impact manifest is an audit and preview snapshot built after commit from authoritative records, never an input to any effect. Owner session: phase 2 works per Study item in one short transaction that writes the generated versions (deterministic ID per session, operation and generation; CAS on each session head, recomputing if the reviewer saved meanwhile), mapped revisions, result and override versions under the confirmed treatments, the Study write and the notice intents; a crash resumes and replays return the existing versions; the pause and operation limits are measured (D2-10 brief item; the earlier 90-second and 30-minute figures are proposed, not approved).
  • Late Saves and Upgrade: a Save or Complete declaring a superseded version is accepted pinned to that version and never rebased; the policy applies to it by derivation (owner session: still true where no version was generated; where one was, the late Save is refused as stale and the draft is rebased, non-overlapping changes apply and overlapping ones show both values, RD-R24). The reviewer's Upgrade (offered from the Needs-updating banner, implied by Fix when accepted, or taken on the next Save or Complete that declares the current version) pins the current version with unchanged revision pins. Under doNothing the reviewer may keep working on the old version indefinitely.
  • Rules: a missing reason gives a non-blocking warning (VU3). A missing required answer is never declared answered. A question is published once any of its versions is referenced by a published form or profile version (or adopted); thereafter it can be removed from forms by a new form version or retired (no new pins), but never deleted (QD1, Chris, 3 October). A committed but unreferenced version, a pending edit, and a question none of whose versions is published may be discarded with an audit entry. A published requirement version never changes; an unpublished one may (this is A-14's "until first use"). FV4: a later policy revision appends a generation to the same operation, CAS-ed on the generation; it never rewrites versions, work, drafts or the compatibility declaration. Notices are captured once per recipient per publication (C15). Owner session: a new generation may generate further versions (for example re-pinning a session to the version under which its Complete was validated); earlier generated versions stay in history. A reviewer's own edit that makes another answer need attention gives an in-form warning only; a change by someone else gives one deduplicated notice per recipient and cause (Q-20, RD-R28). Before commit the publisher sees affected existing and active work under every prior version and route; the inputs are rechecked at commit (RD-R22).
  • Profiles: profile criteria versions publish through the same command, with treatment of decisions cast under prior versions as Q-26 decides (F5). Decision heads carry no class; the profile's class only derives a decision's standing under the recorded policy. Owner session (Q-26 decided): publication detects mismatches with the exact versions of existing decisions, outcomes and adjudications, previews them with active screeners, adjudicators, dependent pools and accepted results, and applies the admin's treatment after a final recheck: keep decisions pinned, request new decisions, or carry compatible decisions forward as attributable generated profile-session versions. Policy is recorded at profile scope, never per stage. Required new screening stays pending; originals and frozen reports are kept (RD-R27). A change to the source policy is a new profile version through this flow (C22). An eligibility change needs a protocol amendment entry in the same publication (D4-05).

Designer pending edits use the same lease, etag and take-over model as reviewer drafts, so two admins editing one question get a typed conflict (PH-33). Superseded by the owner session (5 October 2026; D2-11 and the collaborative question drafts amendment, OS-A01): several DesignDrafts may exist per form; each accepted edit appends a DesignDraftChange stamped with actor, time and base item revision; a stale base is refused and the local edit kept beside the current value; authorised presence (viewers and editors) and live updates appear in every open view, and presence is never an audit record; one publication operation per form at a time, and a draft published after another rebases item by item and recomputes its impact (RD §3.7, §4.7, RD-R25, RD-R26).

Conformance tests: the versioning model's fixtures FX-VM-01 to FX-VM-17, FX-VM-23 to FX-VM-27, FX-VM-38, FX-VM-39 and FX-VM-42, plus: adding a question creates a new requirement version; sessions under v1 and v2 are both found when publishing v3; Needs updating stays visible and blocks Complete; two profiles importing one template stay independent after the template changes; a question hidden by a condition is never required; publishing a form with 10,000 sessions writes no session versions and phase-1 time is flat across session counts (owner session: phase-1 time stays flat; phase 2 writes at most one generated version per affected session per generation and only where the generation table says so, RD-AE16). Owner-session additions: a target-only change creates a form version and generates no session version (RD-AE08); every override gets a recorded treatment (RD-AE11); the declaration is stored with actor and time and cannot be edited (RD-AE14); mapped revisions keep the originals and an incompatible declaration cannot be mapped (RD-AE15); a late Save after a generated version is refused and rebased (RD-AE18); profile publication finds every mismatched decision, outcome and adjudication (RD-AE22); FX-VM-42 is rewritten as "a target change creates a form version" (versioning model §14). Test IDs: C4-T01 to C4-T06, C4-T07r, C4-T08 to C4-T12, C4-T13r and C4-T14 to C4-T20 (acceptance criteria §7.5); the owner session retires C4-T07 (compatibility immutable once pinned) for C4-T07r (declared by the publisher, immutable from commit, guided rollback) and C4-T13 (publication writes no session versions) for C4-T13r (attributable generated versions under the generation table).

C5 — Form session lifecycle, drafts and contribution qualification

Implements: SL1–SL3, SF2, SF5/SF6, FV3, EW1 surplus, LC1 readiness input.

State (SL3, stored fact of the latest explicit version) Definition
draft_only Session exists (created on the first autosave) with a draft but no explicit version
saved_incomplete Latest explicit version is a Save
completed Latest explicit version is a validated Complete
withdrawn An append-only withdrawal version; the session no longer counts or qualifies; its revisions stay readable
Draft-changes flag A draft exists over the current explicit version (any state)
Derived on read (never stored as a fact; versioning model §7.4, §7.5) Definition
Per-answer state Current, OutdatedOwnAnswer, NeedsUpdatingVersion, NeedsUpdatingValue, NeedsAnswering, PinnedOlderVersion, NotApplicable, Conflicted, from the pinned revision, the head's current revision, the classes of the pinned and required versions, the recorded policy, validity and applicability
Requirement standing satisfies, needsUpdating, pinnedOlderCounted, pinnedOlderNotCounted, against the current published requirement version under the recorded policy generations
Qualifying contribution completed ∧ standing ∈ {satisfies, pinnedOlderCounted} ∧ eligible (D4-20). One per reviewer per study and form. A warning alone never removes it (SF6); a requireReanswer policy removes it by derivation with no version written (D2-01). Owner session: under the D2-01 amendment a requireReanswer treatment generates an incomplete PublicationGenerated version, so SF6 applies literally; the contribution must also not be covered by an active ContributionExclusion (O1, D4-20 decided-amended); it counts once across every route and across merge lineage
Flags hasOutdatedOwnAnswers, hasDraftChanges, informed (C3 exposure, including "questioned in reconciliation")

Identity (E27, DD-15): a FormSession is keyed (project, study, form, reviewer) with a deterministic ID and is created by upsert on the first autosave as a Study-free write; opening a study creates nothing. The reconciler's session is an entity of the reconciliation task with authorScope = reconciled and a current holder (C9), never a FormSession. Screening-only steps use the profile-owned session container (PROPOSAL at F3/F5, versioning model §7.1). Claims are keyed by form or profile identity, never by version, and the first explicit Save releases the reviewer's claim in the canonical transaction (C7, claim contract v2).

Session versions (E28): every explicit version pins the complete map (head → revision) of every answer in the session, the declared form version, the route and the resolved question set; storage may delta-encode, but the contract, previous-version exports, candidate pinning, gold pins and E28's ceiling (in pins, changed revisions and bytes per commit) are defined on the full map.

Drafts contract (E21; versioning model §7.6; mechanics in consistency model §4.4): drafts are stored outside Study. One draft record per session, pinned to a base explicit version and base form version, stored as patches, size-capped with E28, with a lease holder (a stable client tab ID shared with tracking's connection model but working with tracking off, RT-10), an etag and a per-holder write sequence; a duplicate write sequence is success; a stale autosave arriving after a newer explicit version is rejected and discarded by the client. A non-holder's edits are kept as a bounded conflict copy, so "keeps both" is literal; the second tab is read-only with "Take over editing" (D2-08). Save and Complete present the draft etag and consume the draft atomically. No TTL; removal only by audited discard (owner, admin after revocation, or the system with an audit record), which feeds LC1. No autosave trail beyond the current draft and its conflict copies (SL1 is satisfied without explicit versions). Drafts are indexed by base form version (the draft_only category, counted authoritatively at publication), are never visible to reconcilers or exports. A cross-form draft based on an older revision changed through another form gets a typed stale-base conflict at Save that shows both values and keeps the draft. Whether an autosaved draft holds the reviewer's place is Batch D D2-07 (recommended middle ground: held while the reviewer is active under today's idle and disconnect timers counting draft activity; released when they lapse with the draft kept; Complete still allowed as an extra contribution unless an optional capacity cap applies, D3-17). The earlier single mutable pendingAnswer model in annotation versioning is superseded.

Drafts, places and connections after the owner session (5 October 2026). The lease, take-over, "no autosave trail" and D2-07 middle-ground clauses above are superseded (RD §3.10, §3.11):

  • Diff change log. Autosave sends only changed answers, each with its per-answer base. Each accepted change appends a SessionDraftChange {draftVersion, basedOnDraftVersion, per-answer base, patch, connectionId, tabId, actor, at} and moves the draft head by CAS on draftVersion, so the draft history is fully reconstructable (replaces PH-33's "no autosave trail"; retention and any compaction are brief items, and compaction never removes an explicit version). Autosave never writes Study, never creates a version and never changes qualification (RD-R05).
  • One shared session across tabs and devices (D2-08 decided). Connections are tracked separately; two connections may autosave; a change to an answer that has not moved since its base applies, and one to an answer that moved becomes a recoverable conflict copy with both values. A read-only take-over presentation is a brief detail for small screens.
  • Rebase, never silent loss. A draft whose base was superseded, by a generated version or by the reviewer's own Save in another tab, is rebased at the next autosave or Save; non-overlapping changes apply and overlapping ones are shown with both values (RD-R24).
  • Form-owned place rules (D2-07 decided; Q-28). One place per reviewer per Study × form across every stage, tab and device. The form owns the inactivity timeout and the per-reviewer in-progress limit. One idle or closed tab never releases the place while another connection is active; the place is released when every connection is idle beyond the form's timeout or closed, and the draft is kept. On return admission and capacity are rechecked. The in-progress limit counts sessions, never connections. Capacity mechanics are C7's.
  • Status words. "Draft auto-saved" (a recoverable draft) and "Version checkpoint saved" (an explicit Save) stay distinct from completion; the words are illustrative and may iterate (D3-03, U1, UX §3.2).

Transitions: autosave (draft only; never a version, never Study); Save (new immutable incomplete version, becomes current, consumes the draft); Complete (validates every required applicable answer under the declared form version, new immutable completed version, becomes current); Fix (explicit, from an outdated flag: a current incomplete version pinned to the session's resolved version; opens that session's form; SF5); Upgrade (a new incomplete version pinned to the current published form version with the same revision pins; nothing is rebased; offered from the Needs-updating banner, implied by Fix when the reviewer accepts it, or taken on the next Save or Complete that declares the current version); Withdraw (append-only); versioned clear (withdrawal revisions for every head plus a Save; replaces "Remove all annotations"). A Save, Complete or Fix declares a form version that must be the session's pinned version or the current published version; any other value is a typed StaleBase. A Save declaring a superseded version after a publication is accepted pinned to it and never rebased; the recorded policy applies by derivation. There is no publication-written transition (the former "policy transition" is deleted; D2-01). Superseded by the owner session (5 October 2026; D2-01 amended): a publication may write a PublicationGenerated version under C4's generation rule, computed against the latest head and never overwriting a newer reviewer version; where it does, a late Save declaring the superseded version is refused as stale and the draft rebased. Merges and unmerges write MergeResolved, MergeCarriedForward and UnmergeCarriedForward versions on the Study they target (C21). Revisions pinned by gold or reconciliation are never deleted. Whether reviewers may withdraw canonical sessions themselves, or only through an admin, is settled in the C5 ADR; the hard delete reviewers have today never applies to canonical sessions. Presentation state, such as entity order, lives in a separate per-session record outside versions and never affects qualification. History never counts as a session or reviewer.

Downstream effects of an incomplete Save (proposal from the ledger, Q-27): recompute shared sufficiency and dependent-step applicability; show affected steps as needing reassessment; preserve dependent work; never change gold or screening decisions as a side effect. Owner session (Q-27 decided): before an explicit change that affects dependent work, the actor sees which work is affected and how, shaped by their access and blinding; the dependency set is rechecked at commit; each affected author is informed once afterwards; reconsideration is explicit and creates new immutable versions (RD-R09, RD-R10).

Outdated-answer completion (owner session; D4-17 decided-amended). The form version declared by a Save or Complete carries outdatedAnswerCompletion: WarnAllowComplete (default; "Complete anyway" after the warning) or BlockUntilAddressed (refused with the list and jump links). Neither mode bypasses validation, applicability, permissions or a mandatory publication treatment; drafts are kept; the completed version records the declared form version, and so the mode and its generation. A session pinned to an older version keeps that version's mode until it upgrades. No stage or step setting exists (RS-R39 to RS-R42).

Admission basis (owner session). Every explicit version and decision revision carries admissionBasis: InPool, ContinuationAfterExclusion {outcomeVersion, settingVersion} or ContinuationAfterDeparture {departureEventId, settingVersion}, with both continuation entries when both triggers applied (SP §3.8). Continuation never restores pool membership and never admits new reviews (C6).

Conformance tests: Save after Complete removes qualification. Autosave alone does not. Complete restores one contribution, not two. The same session is reached from two stages. An order-only change never removes Complete. SF6: a warning alone keeps Complete; a requireReanswer policy removes qualification by derivation with no version written; doNothing with and without counting yields the two pinned-older standings. A withdrawn session neither counts nor loses its history. A late Save pinned to the declared version; Upgrade keeps pins; a previous-version export equals the full pinned map; two tabs' first autosaves create one session; the eight per-answer states render and are explained (U13); the draft fixtures FX-VM-32 and FX-VM-33. Owner-session additions: 200 autosaves on the 2,023-question form send only changed answers and the draft rebuilds byte for byte from its base and change log (RD-AE01); two devices editing different answers both apply and a stale same-answer edit keeps both values (RD-AE02); one place across two stages and two tabs, kept while one connection is active and released with the draft kept when all are idle (RD-AE05); no draft edit is lost across a publication (RD-AE17); the outdated-answer modes behave as configured (RS fixtures); the draft rebase fixture FX-VM-47. Test IDs: C5-T01 to C5-T07, C5-T08r, C5-T09, C5-T10r, C5-T11 and C5-T12 (acceptance criteria §7.5); the owner session retires C5-T08 (the lease and take-over draft mechanics) for C5-T08r (one session across tabs and devices, the kept change log, FX-DRAFT-01r to 04r and 05 to 10) and C5-T10 (a late Save always pinned) for C5-T10r (refused as stale and rebased after a generated version).

C6 — Workflow binding, steps and admission

Implements: PV2, DP6, DP7, EW1, VS1 (setting), BL1 (setting), RX2/LC1, RA1 expiry default, DP2 (admission recheck), RC6 (skip semantics). Owner session: Q-15 (replaced by the filter and step model), Q-01, Q-02, Q-24, Q-28, the finishing-after-departure, self-departure and reviewer-pool amendments (OS-A05, OS-A06, OS-A27), D4-19; DP6/DP7's cross-stage part, BL1 and the stage VS1 default and expiry default are superseded here. Current baseline: one stage owns its mode, questions, target, allocation and security; there is no multi-step domain. ReviewEligibilityPolicy and the eligibility programme (S1–S7) own action-specific admission (eligibility policy; inventory).

Owner session (5 October 2026). Q-15 is replaced by the stage study filter and step model (consolidation §3; superseded wording 5): a stage study filter defines the stage pool, dependencies exist only between steps inside a stage, exclusion-stop is a separate step setting, and there is no incoming stage-entry gate. Q-01, Q-02, Q-24 and Q-28 are decided. The rows below are amended in place; SP §3.2 to §3.11 is the detail.

Element Content
Stage settings version Bound form versions and profile versions; steps; incoming cross-stage route policy (Collective Include required by default, own Include sufficient as advanced; collective-Exclude veto always); within-stage policy (own Include; strict collective only if Q-01 approves); EW1 default; VS1 default; BL1 setting; lifecycle mode; allocation/batch settings; assignment expiry default (defaults per Q-30). Owner session: the incoming cross-stage route policy is superseded by the embedded StageStudyFilterVersion (AND/OR groups over profile outcome clauses and accepted answer clauses, an implicit base predicate, three-valued evaluation failing closed, a stored dependency set; SP §3.3); the within-stage policy becomes the progression basis OwnIncludeSufficient (default) or CollectiveIncludeRequired (Q-01 decided); BL1 and the VS1 default leave the stage (form or profile, below); the assignment-expiry default leaves the stage (optional, off by default in form and profile settings, Q-30); the settings version adds the saved-work default (AllowCompletion or PreserveOnly, Q-28), the started-work-after-departure setting (Allow default; placement ambiguity SP-AMB-01), an optional route capacity cap stricter than the form baseline, and the browsing setting (off by default, PROPOSAL)
Review step Screening profile reference and/or form reference; display order (never a dependency by itself); dependency edges with AND/OR groups (cycles rejected); compulsory flag; handoff allowed; collective satisfaction for unvoted reviewers (recorded as collectively satisfied, no vote); terminal-on-Exclude scope; extra-vote admission after sufficiency (Allow/Stop, from eligibility D1/D2); per-step overrides (EW1 advanced, VS1). Owner session: step kinds review (screening, annotation or both), system adjudication (serves the profile's AdjudicationTasks, shown only to eligible adjudicators, no designer dependencies, reachable when the outcome moved the Study out of the pool; SP-R91, SP-R92, RS-R59) and training (practice against references; no live work, claims or pool events; TI); a tighten-only progression override; extra screening after sufficiency Stop (default for new combined steps) or Allow (Q-24); exclusion-stop with a personal basis, a collective basis and a scope (DependentSteps or an explicit list; defaults personal on, collective on, DependentSteps, PROPOSAL); a saved-work override; the reconciled-hint hide-only override of the form baseline; the EW1 and VS1 overrides above are superseded by these
Admission decision Evaluated identically for selection, reservation, direct access and submit. Returns allow/deny with reasons and the policy/version evidence used. Never creates a vote, submission or outcome. Extends ReviewEligibilityPolicy and reads per-reviewer facts only through IReviewMembershipFacts (E64). The eligibility decisions map as Q-24 sets out (D3b, D1/D2, D4, D6; D5 and D7 unchanged); D8 maps as D3-09 recommends (programme integration §5.2). Never writes a per-project document per admission: it checks the bound stage-settings version in the Study write filter, and a settings change publishes a new version under the engine's scoped fence (DC-05). Owner session: the decision reads the stage pool predicate, step dependency and exclusion-stop results, the continuation basis, allocation and batch scope, capacity and the in-progress limit, and returns reasons from the closed set OutsidePool, NoRemainingWork, TerminatedByExclusion, AwaitingPriorStep, AwaitingCollectiveInclude, StageNotActive, StageCompleted, PublicationInProgress, NotAllocatedToReviewer, BatchNotOpen, NoPermission, AtCapacity, InProgressLimitReached, ContinuationRestricted, SavedWorkOnly (appended to AccessDenialReason; SP §3.14). The first start through a route records ReviewStartEligibility (C20)
Shared-evidence policies When stages reaching one task or session differ: BL1 uses the most restrictive bound stage; EW1 and VS1 are evaluated per route (Q-28, PROPOSAL). Superseded by the owner session (5 October 2026): reconciliation identity blinding belongs to the form (the profile for screening reconciliation and adjudication), blinded by default, and stages have no blinding setting (RS-R24); reconciled-answer hints follow the form baseline in the session's resolved form version, which a step may only hide (RS-R31); the saved-work and departure-continuation settings are evaluated for the route a session version is submitted through, and when both triggers apply completion needs every applicable setting to allow it (SP §3.9, PROPOSAL)
Route status DTO Gate status, form sufficiency and work status are separate fields; a lock is never labelled "Excluded". Owner session: availability text uses the copy deck ("Waiting for the team's screening result", "Enough reviewers are already working on this", "Stopped by exclusion", "No longer in this stage", "Saved work"; UX owns the words)

Evaluation table (DP6/DP7 plus assumption A-06): superseded by the owner session (5 October 2026) as a whole, see the dependency satisfaction table after it. It is kept as the record of the round-2 proposal.

Personal decision Collective state Within stage (default) Across stages (default: collective) Across stages (advanced: own Include)
Include Pending/Conflict Allowed Wait Allowed
Include Included Allowed Allowed Allowed
Any Excluded Blocked Blocked Blocked
Exclude Any not Excluded Blocked for this reviewer Blocked for this reviewer (A-06) Blocked for this reviewer
None Included Allowed only with collective satisfaction Allowed (A-06), no vote invented Allowed: the advanced option adds the own-Include path and keeps the collective path (A-18)
None Pending/Conflict Screening prerequisite to do Wait Prerequisite to do

The within-stage column follows the confirmed handoff table. The cross-stage columns apply DP7. The rows for personal Exclude and for an unvoted reviewer are interpretations A-06 and A-18, put to Chris as Q-15. (Owner session: Q-15 is replaced; A-06 and A-18 are retired; neither alternative is approved.)

Permissions, allocation, batches, capacity, lifecycle and other configured dependencies apply to every allowed row. Saved-work completion after collective exclusion follows EW1, never this table.

Dependency satisfaction for reviewer R (owner session; owner basis Q-01 and Q-15, mechanics PROPOSAL; SP §3.4):

Prerequisite activity Basis in force Satisfied when
Screening under profile P OwnIncludeSufficient (stage default) R's current decision under P is Include (or Unsure, under the RS-R47 PROPOSAL), even while the collective result is pending; or R has no decision and P's current outcome is Included, recorded as collective satisfaction with no vote invented
Screening under profile P CollectiveIncludeRequired (stage setting) P's current outcome is Included
Annotation with form F Either R's current session for F is Completed, or F is already sufficient for the Study through qualifying evidence from any route (no duplicate work)
Both Either Both rows hold

Exclusion-stop then applies on top. With the personal basis on, R's own current Exclude under P blocks R from the scope. With the collective basis on, a collective Exclude under P stops new work in the scope for everyone, including before any offer when the Study was never reviewed through this stage; an adjudicated Exclude is a collective Exclude, and a pending outcome (AwaitingExtraReview, InDiscussion, PendingAdjudication) never triggers exclusion-stop (RS-R57). "Pending" never means ignoring an eventual Exclude. A Study with no remaining work stays in the pool and is not offered; no stage-local review, vote or submission is fabricated. Matching the filter means neither that review is needed nor that it happened, and a filter failure is never a screening exclusion. Started work may be completed after a screening exclusion by default (step setting PreserveOnly refuses completion and keeps drafts) and may continue after any filter-driven pool departure by default (an authorised restriction prevents it); continuation never restores pool membership and never admits new reviews (Q-28, OS-A05). A valid result that makes its own Study leave the pool is accepted, the evidence is kept and new offers stop (OS-A06). Branching on accepted answer values between steps is deferred beyond MVP (D4-15).

Programme notes (PROPOSAL):

  • reviewEligibilityPolicy and proportionalStudyAllocation are delivered to API and PM with a cross-host agreement check before either is enabled, and one evaluation per request is passed into admission (E75).
  • The generated eligibility truth table is C6's conformance format; it gains step and route columns (PH-04).
  • A requestedReview claim admits exactly the requested reviewer past bucket, pool and capacity filters (E66, D3-13c).
  • Proportional allocation is refused on canonical stages until AL1 (D3-13a).
  • Batch access is scheduling access, never permission; X-ELIG precedes batch activation.
  • A dependent form's claim is taken at Include, not while the reviewer is still screening; a refusal shows "Enough reviewers" for that step and keeps the screening decision (D3-19). Owner session: D3-19 is a brief item; own Unsure tries the dependent claim as own Include does (RS-R47 PROPOSAL); under CollectiveIncludeRequired the claim is tried when the reviewer next opens the step after the collective Include.
  • Owner session: the generated eligibility truth table gains filter, step, exclusion-stop and continuation columns and drops the cross-stage columns (D3-09 brief item).
  • Owner session (S4, TI): the "passed-training admission hook" is replaced by group admission through the existing membership contracts after a configured pass (automatic or with manual approval, recorded with causation), plus an optional explicit dependency of a live step on "passed this training step" (TI-R15 to TI-R19; the dependency is a PROPOSAL). There is no hidden privilege expansion.
  • Owner session: automatic stage completion follows remaining-work rules, and an automatic Completed stage reopens as soon as remaining work appears; a manually completed stage stays Completed until an authorised reopening; an admin change that adds work shows its impact first (Q-02). Open adjudication work is remaining work.

Conformance tests: the access-policy fixtures, the research A12–A16, FX-PRISMA-03a (C6-T16; owner session: FX-PRISMA-03ar), "PRISMA stays Excluded with completed extraction" (PR1), and every eligibility truth-table row answering identically from CanonicalSummary and from embedded data (E64). Owner session: the rows built on A-06 and A-18 and on the cross-stage columns are retired; the dependency satisfaction table, exclusion-stop, saved-work and departure-continuation fixtures, step kinds and the closed reason set are added (SP §11, SP-AE rows for steps, continuation and explanations). Test IDs: C6-T01, C6-T02r, C6-T03r and C6-T04 to C6-T22 (acceptance criteria §7.5); the owner session retires C6-T02 and C6-T03 (FX-ACCESS-02 and 03, built on A-06 and A-18) for C6-T02r and C6-T03r (the next stage's study filter defines its pool, with no cross-stage gate or route policy).

C7 — Operational projections and claims

Implements: OPS1, SF2 (counting once), SL3 (moves), SF4 (more than the target), RA1 (active-work tracking for pool work, delivered by the task editor claim), RA5, E18, E19, E20. Owners: FEAT-024 statistics, allocation, active reviewer tracking, eligibility and progressive batches keep their programmes. This contract is the amendment list they review. It is not a takeover. Details, timing and PR slicing: programme integration.

Boundary Required amendment (PROPOSAL unless a decision ID is given)
Study membership projection (E20) Per form and per profile, per reviewer: the member state {state: placeHeld, savedIncomplete, completed or withdrawn; standing: qualifying, needsUpdating, pinnedOlderCounted, pinnedOlderNotCounted or notApplicable} (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), claim kinds held, admitting allocation regime, and the reviewer's current decision per profile; derived tallies per bound stage for legacy readers. Bounded by the SF4 rule (every qualifying candidate), not by the target. Carried by Study.CanonicalSummary (C1; shape and write rules in the consistency model §3.3), written in every study-scoped canonical transaction and by projection-rewrite operations, and read only through IReviewMembershipFacts (E64)
Stage and membership annotation tallies Derive form-unique current explicit contributions once per reviewer; stage views project their bound form; never sum duplicate stage projections. R0's floor merges the summary's per-stage projection into SessionTallies and the claim pipeline, so legacy readers stay correct (E48)
Statistics protocols and checkpoints The engine never writes statistics or pending entries; it writes Study only through FEAT-024's source-write seam (a projection-only shape). Three compatibility mechanisms stay separate (C8): extra-element capture (R0), the fold protocol window (one bump, protocol 5, after gate (b); intents until then) and per-family catalogue versions with the configuration digest. Targets, thresholds and bindings are digest inputs, so each change has a reconciliation plan; replacing the fixed two-reviewer classification with targets is a FEAT-024-owned change at all three sites (E71, X-STATS-c). Enrolled projects never run transactional point mode. Old stage-only checkpoints are never reinterpreted
Claims (claim contract v2, frozen at F1a) {kind, scopeId, routeStage, routeStep, reservedAt, allocationRegimeId, leaseExpiry, holders} with 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. Capacity claims live on Study, inside the atomic guard; editor claims live on their own aggregates and work with tracking off. The first explicit Save releases the slot claim inside the canonical transaction; release paths read drafts in the same snapshot (D2-07); a lease expiry and a backstop sweep catch orphans (E57). Owner session: one claim serves every tab, device and stage route; the form's inactivity timeout releases it only when every connection is idle or closed, keeping the draft (D2-07, D2-08 decided); claims of reviewers without started work on a Study that departed a pool are released through the revocation outbox; editor claims also guard AdjudicationTasks. New hub methods rather than new parameters until MinUiVersion moves; additive DTOs; new command contracts with old handlers kept for at least the suspension grace plus the idle timeout; presence index migrated by create, read both, drop. Legacy v0/v1 pages stay for legacy scopes. One reservation migration, with the eligibility programme's S4-B (AP-07, E68)
Capacity and target The form target is a minimum (SF4). An optional capacity cap (stage or route policy) is separate: off by default; when on it defaults to the form target, never limits requested extra reviews and never evicts existing work (D3-17). Places are held by a draft-backed claim while the reviewer is active (D2-07), and by saved-incomplete, completed and Needs-updating sessions; withdrawal frees the place. For a form bound to stages with different settings, the most restrictive bound stage sets the cap and the idle timeout, the stage in use sets the in-progress limit counting a shared session once, and the form is tracked if any bound stage is (D3-18). Screening capacity follows the profile's collective rule (D6). Owner session (5 October 2026; Q-28, D2-07; D3-17 and D3-18 carry-forward): the effective target (the current StudyTargetOverride value or FormVersion.standardTarget) is the minimum; the form-owned CapacityCap baseline (Off, EffectiveTarget, EffectiveTargetPlus(n)) applies through every route and a stage may set only a stricter route cap; one shared place count per Study × form; off by default and EffectiveTarget when enabled are proposed defaults, not approved; a cap never falls below a Study's effective target (PROPOSAL); lowering a cap never evicts a held place, and conflicting temporary reservations are released only through an explicit Apply anyway that keeps drafts (Q-24). The form owns the inactivity timeout and the per-reviewer in-progress limit. The D3-18 sentence about the most restrictive bound stage and the stage in use is superseded. Enforcement exists only while tracking is effective; with tracking off ReviewStartEligibility records NotEnforced (tracking off). Who owns the timeout and limit for screening-only work is SP-AMB-03
Requested review (RA5) The AdditionalReviewRequest command writes a requestedReview claim on Study: single use, expiring, audited. It admits exactly that reviewer past bucket membership, the at-target pool filter and the capacity guard; it never changes the target; the resulting session records it as provenance and is counted outside allocation progress (E66, D3-13c). Superseded by the owner session (5 October 2026; consolidation §1): a request for additional reviews may name people or groups and many Studies; each Study item raises the effective target through a StudyTargetOverride version with basis AdditionalReviewRequest(requestId, raiseBy) and a scoped assignment; qualifying reviewers count once across routes; with the cap following the effective target the requested reviewer has a place; there is no invisible bypass; an assignment never grants a permission (RD §3.12, RD-R17; SP §3.7)
Proportional allocation Refused on every canonical stage until AL1 (D3-13a): shares cannot be configured on a canonical stage, and R0 refuses a stage whose regime is enabled. AL1, after allocation Phase 2 and X-AUTH-RESOLVER and before Phase 3: one plan per form with equality checks, regime schema v2 (form binding, target source) with a floor one release ahead, read APIs on the membership projection, the D8 slot rule on form-keyed claims (E65). Canonical stage settings reference the regime by ID
Progressive batches (#3939) Completion through IStudyObligationEvidence with legacy and canonical providers; membership over pool-entry events with late cohorts appended; shared opening and personal grant are compare-and-swap transitions that write pool-entry events and durable intents; status reads never mutate; a performance gate precedes any enablement; X-ELIG first (E67). Pool entry is the first release to anyone, with shared openings and personal grants recorded separately (D3-13e; amendment A). Canonical stage settings reference the plan by ID. Owner session: batch membership is defined over stage pool episodes (StagePoolEntered and baseline members, C20), late entrants join as separately shuffled cohorts, and the first release is recorded as WorkFirstReleased (renamed from StudyEnteredPool; releaseKind SharedBatchOpened or PersonalBatchGrant); later openings stay in the plan's own records; departures for other reasons are ambiguity SP-AMB-09
Normal reconciliation Reconciliation reserves nothing today (StageReviewService.cs:153), and tracking excludes it at every layer, so enabling tracking gives RA1 no protection. R4a's task editor claim (taskEditor: compare-and-set plus lease; atomic "Start reconciling"; assignment and release hooks) delivers RA1's editor exclusion in every environment, with tracking on or off (X-RECLAIM). Explicit assignment is a separate record (C9)
Tracking mode and production claims Claims, capacity guards and typed admission exist only when tracking is effective, which is off in every deployed environment. Production claims need X-CLAIMS: the route D3-16 chooses; API and PM switched together statically; load, failover and orphan backstop; E2E in both tracking modes (E69). Realtime presence is a disclosure channel under C10 (D3-20). Owner session: D3-16 and D3-20 are brief items; tracking at project scope, replacing the binding-scope setting, is a PROPOSAL (SP-AMB-12); the shared-form capacity, load and statistics pilot precedes broad rollout
FEAT-024 reservation derivations The reservation fold kinds move to the claim contract's key through a protocol bump (IntroducedAt), batched into protocol 5 after gate (b)

Conformance tests: truth-table parity between the embedded and summary providers; two tabs through stages A and B hold one claim, closing either keeps it, closing both releases it once (AC-R2b-03); twelve concurrent first joins through two stages create one claim (AC-R2b-09); a stage-keyed claim on a canonical form is refused or translated (AC-R0-02); under allocation at target the requested reviewer is admitted and nobody else is (AC-R4a-38; owner session: rewritten so the request raises the effective target and the requested reviewer holds a place under the cap); N reconcilers pressing "Start reconciling" never share a task (AC-R4a-37). Owner session: a route cap only refuses admission through its route; lowering a cap evicts nobody; a 500-Study additional-review request writes one override and one assignment per Study idempotently (RD-AE12). Test IDs: C7-T01 to C7-T08, C7-T09r and C7-T10 to C7-T12 (acceptance criteria §7.5); the owner session retires C7-T09 (the RA5 target boundary and the D3-13c bypass) for C7-T09r (an additional-review request raises the effective target through an override version and the named reviewer passes ordinary capacity checks against it).

C8 — Version usage evidence and protected publish boundary

Implements: PS1–PS3, FV2. Owner: FEAT-024 owner with L2.

  • Usage families (MS-02, MS-03): new FEAT-024 families over canonical sources, delivered by a FEAT-024 technical-plan amendment ("canonical sources"): FormVersionUsage (sessions by category, deduplicated across stages, explicit versions only) and QuestionVersionAnswers (counted from revisions) at F2; profile-version decisions, and profile-grain screening if D3-10c chooses families, at F5. Their scope kinds and key components (FormId, FormVersionId, ProfileId, ProfileVersionId) are authoritative over the canonical collections in the same pinned snapshot. Their catalogue and source versions are independent of ProjectScreening's constants (#3506 first). A new-family onboarding contract with a rolling-deploy test precedes F2 (E72). draft_only counts are authoritative counts from the draft collection inside the publish fence, never a materialised row.
  • Protected boundary: publication raises a fence on the form head, drains for at least the server's transaction lifetime plus its expired-transaction sweep plus a margin, and reads the usage families at the fence in a pinned snapshot (currentness below). Every dependency-relevant write (Save, Complete, Fix, Upgrade, imports, binding changes, session creation) reads the form head in its snapshot, so it either commits before the drain ends or is refused and retried after release (consistency model §7.3). There is no high-water mark and no per-project sequence. Definition moves that change counters without a Study write (form target, binding, publication policy) admit FEAT-024's definition-rewrite fence in the phase-1 transaction; that fence makes statistics bundles answer a typed 503 and serialises no reviewer writes. The reviewer "pause" is the engine's scoped write fence, not a FEAT-024 facility.
  • Currentness (MS-04, D3-10a): "current" for PS2/PS3 is a FEAT-024 read at the fence whose result is Materialised-Fresh or pinned-Authoritative, with the read's identity (projection revision, source revision, digest) recorded in the frozen manifest. FEAT-024 exposes a "scoped rebuild at a pinned snapshot" service API, reusing the rebuild publication (its sanctioned retry unit), callable by the publication command under the fence. Missing or stale evidence is never treated as zero. Affected identities come from authoritative records in the same scope, never from counts.
  • Production (MS-01, Q-31): the materialised families reach production only after the X-STATS-b chain (idle gate (b); soak; production pending index; separately approved rollout lifting the in-code refusal; production eligibility; family built; staging proof). Under Q-31, authoritative counting and identity enumeration at the protected boundary is the designed first pilot path, with the materialised family a swap-in behind the same interface. Preview pilots use that path (D3-10d); staging pilots need X-STATS-a.
  • Compatibility (MS-09): three separate mechanisms: (a) BSON extra-element tolerance (R0's floor); (b) the fold protocol window: new transition kinds for canonical commits go into one bump, protocol 5, after gate (b), with intents only until then; © per-family catalogue and source versions plus the configuration digest: new families, dimensions and target-aware classification.
  • Write path (MS-06, DC-21): the engine never writes statistics or pending entries; FEAT-024's source-write seam does. Admitted projects run FEAT-024 in fold mode or with statistics writes off, never in transactional point mode.
  • Authorization (MS-18): ProjectQuestion resolves canonical questions, not only Project.AnnotationQuestions; the canonical designer reads QuestionVersionAnswers (or authoritative counts), never the legacy question locks.
  • Limits: FEAT-024 excludes broad agreement and outcome-level statistics. R5c keeps its own rebuildable store (D3-11). PRISMA snapshots are computed from authoritative records at the report watermark; FEAT-024 rows and history are never report or as-of inputs (MS-11, MS-22).
  • Known hazard: today's per-projection fresh zero can't prove "unused" across snapshots (StageReviewStatisticsEvidence, cited in COMPARISON F9).
  • Owner session (5 October 2026): D3-10 and D3-11 are brief items (RI-R52 to RI-R56). The publication manifest records the identity of the statistics read it relied on in a pinnedStatisticsRead block (PROPOSAL); project 0102 stays out of overlapping pilots until C8-T07 passes; R3b pilots serve profile-grain screening statistics live; preview publications record authoritative counts. FEAT-024 gate (b) failed on latency on 3 October (#3510), so production readiness stays provisional. Machine-source decisions are a separate source class in progress statistics, served live until a FEAT-024 scope amendment covers them (PROPOSAL). Generated session versions and target-only publications are definition moves for the definition-rewrite fence.

Conformance tests: Test IDs: C8-T01 to C8-T08 (acceptance criteria §7.5).

C9 — Reconciliation task, gold snapshots, assignments and queries

Implements: RE1–RE5, RA1–RA5, SF4/RE3, MG1, NT1, BL1, GS1, UA1, QY1–QY9, RX1, DP5, VS2. Owner session (5 October 2026): Q-29 and D4-03 (decided-amended, R1), Q-36, Q-11, Q-32, Q-04, Q-30 (R2, R3), Q-35 removed, the tie, adjudicator, blinding and hint amendments (OS-A02 to OS-A04, OS-A13, OS-A28), D4-17 (O3); detail in RS. Baseline: readiness is completed sessions ≥ the stage target. There is one shared reconciliation session per study and stage, editable by any Reconcile holder, with no editor exclusion (reconciliation uses no claim or presence at any layer). Reconciled answers are one overwritten set per question across stages, and counters are two booleans. The reconcile response maps every study session across stages. The web route shows read-only candidate cards (any number, two per row) with no reconciler form, and AF2's reconcile host is read-only by rule. No gold, adjudication or query entities exist. The canonical task replaces this model.

Element Content
Reconciliation task One per study × form (RE4, PV2), keyed (project, study, form) with a deterministic ID, reachable through any stage using the form; there is never a second task for one study × form (DD-07). It pins, as versioned state and never as part of the key, an input set holding the form version it reconciles against and the full set of qualifying candidate session versions (all of them; SF4); a new input set is appended when inputs change, PublicationImpactPolicy decides which candidates still qualify after a publication, and the gold snapshot records which input set produced it. Per question, a derived held state when the candidates' pinned revisions fall in different compatibility classes, a candidate's value is invalid under the task's form version, or a candidate head is Conflicted; a held question blocks only itself (prefill, agreement, its own acceptance) and "Ask vN reviewers to update" raises a Needs-updating request that changes no standing. v10's later "Mark compatible" is replaced by the admin's immutable compatibility declaration (D2-02; owner session: the publisher's declaration, immutable from commit). The compatibility class is not part of the key (corrects B-28). Owner session: a task exists for every form with at least one qualifying candidate, including target-one forms in both targetOneHandling modes; it carries a pointer to the current AcceptedResultVersion (RS §3.1)
Candidate drift A new qualifying candidate, a Save after Complete, a Fix or Upgrade after gold, a publication of the form's version, a publication policy that de-qualifies a pinned candidate (requireReanswer), a candidate withdrawal, or a dedup alias puts the task into "inputs changed · re-check"; it never retracts gold. Under doNothing with counting, candidates keep counting until they submit (v10's rule); under requireReanswer they stop qualifying by derivation; the admin's publication choice selects which. Owner session: "a dedup alias" reads "a duplicate consolidation or reversal" (C21); a generated version drifts only the questions whose pinned revision or class changed, or a candidate that stopped qualifying; a contribution exclusion drifts the task and leaves existing results flagged; under requireReanswer the generated incomplete version removes qualification explicitly
Matching Suggested pairs/groups across all candidates (MG1); reconciler confirms; candidates preserved; re-pairing keeps prior pairings in history and re-evaluates only dependent answers (PROPOSAL, COMPARISON F7)
Reconciliation session An entity of the task with authorScope = reconciled and a current holder (the editor claim below), with Save and Complete versions and drafts through SessionDraft keyed by the task; "started" means it has a draft or an explicit version. Never a FormSession, so it cannot collide with a candidate session under Q-36. On a new editable AF2 reconcile host. Autosave/Save are unfinished; final Complete accepts the displayed valid answers including prefill (RE2); exact-text free-text prefill only within a class (RE5); exposure tracking for the unseen-control warning (actual controls, not tab visits); Complete anyway allowed; validity and affected children enforced. Owner session: completeness follows required questions with the form's acceptedCompleteness override and no stage override; a blank candidate comparison is "not assessed", never disagreement or a block; Unknown and Not reported are answers; legacy-gap states are never answers (Q-04; RS-R13 to RS-R16)
Editor claim Compare-and-set plus lease on the task (taskEditor, X-RECLAIM); atomic "Start reconciling"; only the assignee may claim an assigned task; admin release revokes the claim through the outbox; lease expiry never expires a started assignment; works with tracking off (AC-R4a-36 to 39). Query review uses the same mechanism on QueryWorkItem (queryEditor, AC-R4b-09).
Gold snapshot Immutable per study (studyId, seq); entries reference exact reconciled revisions (each carrying its question version and class); new snapshot on change, keeping unchanged references (GS1); compare-and-set on the study's current-snapshot pointer when tasks and query resolutions publish concurrently. Derived per entry: goldNeedsReReconciliation when the form's current pin for the question is in another class than the entry's revision, or the entry's value is invalid under it; gold stays effective while flagged and is labelled with its version in exports and PRISMA manifests. Owner session: each AcceptedResultVersion publishes exactly one new snapshot
AcceptedResultVersion (owner session) One immutable accepted result per Study × form version, (projectId, studyId, formId, seq). authority ∈ SingleAnnotator (system rule), HumanReconciled, Adjudicated (profile-owned screening annotations through an AdjudicationTask), MergeResolved (C21); acceptanceMethod ∈ SystemRule, Individual, BulkConfirmed, MergeResolution; origin ∈ Native, MergeCarriedForward, UnmergeCarriedForward; the input set and exact candidate versions with candidateCount; the form version (which pins the standard target and ReconciliationPolicy), any override version and the effective target used; the snapshot it produced; the actor (rule and version, reconciler, or publication operation and confirming admin); the blinding mode and a protected mapping reference; supersedes and a reason code. Derived standing: Current, InputsChanged, BelowCurrentTarget, SuspendedByTarget, NeedsReReconciliation, Superseded. A new target, policy or input creates a new version only through the entitled rule or person; earlier versions stay immutable; raising the target invents no reviewer, vote or placeholder (RS-R09 to RS-R12)
Shared question gold Overlapping forms share question gold (RE4). All reconciled heads of a study live in StudyGold, so ownership is local to the study. Batch D D2-09 decides between "first publisher wins; other tasks challenge by query" and the recommended "the second task sees existing gold prefilled as accepted, with its source snapshot and reconciler shown, and may revise it in its final submission, producing a new snapshot with provenance; queries remain for everyone else". Until answered, pilots avoid overlapping reconciled questions. Owner session: D2-09 stays OPEN, the one open owner decision (T-OI-01); FX-VM-45 stays parameterised
Target-1 forms No task and no automatic gold; exports label the single assessment "single reviewer, unreconciled"; optional attributed "accept as gold" (Q-29). If D4-03 approves, a Verification step produces Verified gold (C14). Superseded by the owner session (5 October 2026; Q-29 and D4-03 decided-amended, superseded wording 11): when the effective target is one, the form version's targetOneHandling decides. AutoAccept: exactly one qualifying candidate becomes an immutable SingleAnnotator result with the exact session version and the rule version, never labelled reconciled, verified or checked ("Single annotator (accepted automatically)"). RequireHumanReconciliation: the same task becomes ready with one candidate and an eligible reconciler completes it in the normal workspace (HumanReconciled, candidateCount = 1). No separate verification engine, session type or Verified authority exists. Two or more candidates always need a human reconciler, even when they agree (T-POL-03 unapproved). A surplus candidate after a SingleAnnotator result moves the task to InputsChanged and the result stays effective until a reconciler completes. New forms default to AutoAccept and converted legacy forms carry NoAcceptance (both PROPOSALs, RS-R04, RS-R04a). Publication lowering the target or switching modes creates results only through the treatment the admin confirms (RS-R01 to RS-R12)
Screening-profile part A separate aggregate that adjudicates decisions and writes the final screening outcome (RX1); never a reconciliation session writing screeningOutcomes (a FEAT-011 MUST NOT). Who reconciles each part follows stage grants (C10). Owner session: the aggregate is the AdjudicationTask, one per Study × profile × trigger (decision tie, unresolved Unsure, reason disagreement, sole-source AI-model Unsure), shared by every stage that binds the profile and served through each stage's system adjudication step. The profile version's tie policy routes ties to extra review with a bound or to adjudication, with no inferred default; extra review never resolves a reason disagreement. Assignment is an AdjudicatorAssignmentVersion naming a member or an eligible group; the individual resolver is recorded; an assignment never grants authority. The adjudicator submits an immutable AdjudicationVersion (rationale required when the profile says so, Q-32). Pending adjudication is not a definite outcome. After resolution, a later correction, exclusion, surplus decision or replaced external decision leaves the adjudication as the current final facet, flagged InputsChanged, until an eligible adjudicator explicitly reconsiders it (RS-R50 to RS-R59)
Assignment Optional; eligible reconciler; expiry only for explicit, unstarted assignments; audited override; started assignments are released by an admin and must be reacquired (RA2–RA4). Random eligible start and assigned-work-first ordering are PROPOSAL (v10 r2). Owner session (Q-30): expiry of unstarted assignments is optional, admin-configured and off by default in the form (tasks) and profile (adjudication) operational settings; the seven-day expiry is superseded (superseded wording 13)
Additional review request Separate capability (RA5); independent eligible reviewer; no candidate exposure; result returns to the reconciler; target unchanged; no automatic gold. The request writes a single-use requestedReview claim on Study (study × form × reviewer) that lets exactly that reviewer past pool, bucket and capacity filters (AP-03, D3-13c); provenance on the resulting session; counted outside allocation progress. The requested reviewer is excluded from conversations until the review is returned (Q-N9, recorded). Owner session (consolidation §1): "target unchanged" and the bypass are superseded; the request (one or many Studies, optional member or group assignees) raises each Study's effective target through a StudyTargetOverride version and qualifying reviewers count once across routes; the other clauses stand (C7)
Reconciliation identity blinding and presentation (owner session) The form owns blinding for its tasks and the profile for adjudication and screening-annotation reconciliation; default blinded; stages have no blinding setting. Candidates appear under context-local random aliases in a random order drawn per reconciliation session and independently per Study, fixed while that session lasts; new candidates are appended with fresh aliases. Blinded payloads carry no reviewer IDs, FormSession IDs, avatars, submission or edit times, chronology-revealing counts, allocation or route metadata. Real identities stay in protected provenance and disclosure follows the C10 export contract (RS-R24 to RS-R30; OS-A02, OS-A03)
Reconciled-answer hints (owner session) The form version's baseline shows applicable accepted answers as labelled hints by default; a step may hide them and never reveal hints the form hides. SyRF never fills a control from a hint; the reviewer clicks "Use accepted answer". HintExposure and HintAdoption are recorded (C3); adopted answers count toward progress and are never independent observations; hiding never erases entered answers (RS-R31 to RS-R38; OS-A04)
Bulk acceptance (owner session) A per-form operational setting, off by default, delivered after the core workflow. The reconciler confirms the exact list; each result is HumanReconciled with BulkConfirmed. Agreement alone never creates a result; held questions, changed inputs, required blanks, free-text differences, self-candidacy and any disagreement are excluded (Q-11; RS-R21 to RS-R23)
Self-reconciliation (owner session) No ordinary self-reconciliation: a member with a candidate session is never offered or allowed that task, nor an adjudicator who cast a decision on the adjudication. An explicit, audited override grant scoped to named forms or profiles is the only exception, and every use is shown in provenance, exports and the methods summary (Q-36; RS-R17, RS-R18)
Query work item One per reconciled revision ID (the accepted-answer version, QY2), shared unchanged across every snapshot that pins it; individual concerns, proposed corrections and outcomes; gold stays effective with a pending flag; children resolved before a replacement snapshot; audited self-review; optional rejection explanation; QY8/QY9 closure rules, where QY9's current applicability compares the target revision with the snapshot's current revision for that head and with the form's current class, flagging without silent retargeting. After a correction, screening decisions re-run profile rules, while annotation gold always needs the reconciler's final submission: candidate agreement never confirms it automatically (RC10 split).
Legacy reconciled answers Readable as LegacyAuthorityUnknown; treatment in exports, queries and readiness per Q-35. Legacy reconciliation refuses canonical forms from R2a. Removed by the owner session (5 October 2026; Q-35 removed, superseded wording 7): no legacy reconciliation records are assumed; there is no LegacyAuthorityUnknown authority and no mandatory backfill; the baseline conversion dry run counts any records found and an unexpected record stops that project's conversion case (RS-R68, BC-R20). Legacy reconciliation still refuses canonical forms
Clarification thread (StudyConversation; #3944 and #3965, open PRs) Pre-gold questions from a reconciler to selected candidates: one-to-one threads on completed sessions only, an exposure record looked up by session (C3 kind "questioned in reconciliation"), a read-only context link, reconciler eligibility across bound stages. Kept separate from queries; must meet Q-10 before conversations are enabled. Refuses canonical scopes until R4a, when it binds to the task identity and L6 owns it (NS-18, NS-19). Threads are part of the project's audit record (D3-25). Study issues never carry answer disputes after R4b (NS-24)

v10 settings dispositions (PROPOSAL): step-level "who reconciles, per part" is replaced by stage-scoped grants, with a per-part grant if needed; "earlier gold standard … candidates never see it" is revised under VS1, which lets candidates see gold by step policy; "rationale for a reconciled decision: Always" applies only to screening adjudication, if Q-32 allows it; "EDIT RECONCILIATION reopens it" is replaced by the query or new-snapshot route (GS1, QY). Owner session: "Reconciler sees reviewers" moves to the form and profile versions' identityBlinding; candidates see accepted answers as labelled hints by the form baseline (narrowed per step), never prefilled; Q-32 is decided (profile setting, off by default, adjudicated decisions only).

Screening resolution (owner session; S1, S2, S3, tie amendment; RS §5.9 to §5.13). The profile version's rules combine decisions into a ScreeningOutcome whose resolutionState is Pending, AwaitingExtraReview (with the remaining bound), InDiscussion, PendingAdjudication, Included or Excluded; only the last two are definite, and evaluation is order-independent over the multiset of current applicable decisions. Unsure is a per-profile setting (on in the proposed title/abstract template); it counts as not excluded for availability, never as a definite Include, and never triggers exclusion-stop; bounded handling follows the RS §5.10 table, where Include, Unsure, Include is a sufficient Include under the owner's example rule and Include, Unsure, Exclude goes to adjudication; all-Unsure, in-flight responses, larger bounds and other thresholds are brief items and no common numeric threshold is approved. Ties go to extra review (one more decision at a time up to the bound, then adjudication) or straight to adjudication, as the profile version records; there is no inferred default. Optional discussion starts only after submitted independent decisions conflict; initial observations are preserved for independent agreement and corrections are new versions; an unresolved discussion applies the tie policy. A profile's sufficiency rule is the configured screening rule and is distinct from the unapproved automatic acceptance of agreeing annotation candidates (T-POL-03). A primary exclusion reason is template and reporting guidance, never a limit on the number of reason questions.

Conformance tests: Owner-session additions: the RS acceptance evidence for SingleAnnotator acceptance, one-candidate human reconciliation, no automatic multi-candidate acceptance, result versions under target changes, blinding and order, hints, bulk acceptance and adjudication (RS §11). Test IDs: C9-T01 to C9-T12, C9-T13r and C9-T15 to C9-T19 (acceptance criteria §7.5); the owner session retires C9-T13 (target-one forms create no task) for C9-T13r (a target-one form creates a task: AutoAccept gives one SingleAnnotator result, RequireHumanReconciliation completes as HumanReconciled with candidateCount = 1), and retires C9-T14 (legacy authority, Q-35 removed) in favour of AC-R4a-12r and the conversion premise check BC-AE11. C9-T15 (shared gold, D2-09) stays pending-D2-09.

C10 — Capabilities, groups, delegation and disclosure

Implements: PM1, PM2, AG1, RA5, QY4/QY7, EX1 authority. Baseline:

  • ResourceSecurity.json has 25 project and 4 stage activities; ChangeOwner, AssignPermissions and Delete are owner-only in the catalogue.
  • ChangeOwner is not enforced: ownership moves through the project PATCH under the Edit permission (inventory §7). The permission-update endpoints accept any activity, so an AssignPermissions holder can grant owner-reserved activities.
  • Only the built-in Administrator group is reachable. Custom groups exist in the domain but have no creation path; the authorization programme gates them on membership schema 1 (G-D) and plans their administration as WP11 after WP9 explanations.
  • Stage grants for groups and all members exist; per-member stage grants have no API writer.
  • ProjectAuthorityEvaluator is the single new evaluator, dark until the authority programme's enforced-mode cutover.

See the matrix and the inventory.

Rules:

  • Capability is distinct from administration. Assignments and notifications never grant access. Every read and command rechecks active membership and grants; revocation applies to new access and never erases evidence.
  • Owner-reserved activities are refused by every permission-update endpoint and hidden in the dialog. ChangeOwner is never grantable (ownership transfer stays owner-only, PM1). AssignPermissions becomes grantable only through R1d's delegation envelope (PM2). Delete follows the permission matrix decision (Q-03).
  • Anti-escalation: a membership editor can't add themselves or anyone else to a group whose grants exceed what the editor may administer (Q-03a).
  • Delegation stays inside an owner-defined envelope without recursion (approved with Q-03, 3 October 2026). Audit reuses the authorization programme's authorizationAudit; no new audit store.
  • Disclosure policy is shared by interactive reads, exports, statistics and notifications. The export disclosure contract says who may unmask identities (a capability or an explicit mapping to ExportData), keeps candidates separate from gold for exporters who aren't reconcilers, applies BL1 to exports and audits every unmasking. Today any ExportData holder can choose "UNMASK DATA" regardless of blinding.
  • Presence is a disclosure channel. Realtime presence snapshots pass DisclosurePolicy: people who are not holders get counts and their own claim only; identities need the Monitor capability and never cross BL1 (RT-14, D3-20, AC-T-08). Owner session: "BL1" reads the form's or profile's reconciliation blinding; design-page presence is shown only to users with design access and is never an audit record (OS-A01).
  • Every new view maps to a capability: Monitor ("Who is offered what", which can reveal personal votes), History & corrections, Agreement (AG1, with its own navigation entry, R5c), PRISMA.
  • New capabilities at F1b: "receive and resolve study issues" and "approve PDF corrections" (recipients expand by capability, not by Administrator-group membership; NS-20); only the requester or an admin may download an export (#3335 D11, PH-25).
  • Per-reviewer evaluation for other reviewers ("Who is offered what", reviewer validity) needs the out-of-request resolver X-AUTH-RESOLVER (#3251, #3611); until it exists, Monitor shows pool-level counts by refusal reason (AP-02, D3-13d).
  • Enum ordinals are appended, never reordered.
  • Owner-session capabilities (5 October 2026; names PROPOSAL until F1b): "Exclude contributions" (O1; an admin's explicit decision by form, profile, stage or project with reason, actor, time and preview; reviewers cannot withdraw submitted contributions by leaving, and membership disable alone keeps them valid); the Deleted projects view and the restore permission (owner and project Delete holders see their deleted projects; application administrators with a system permission see all; AC ambiguity B4); the catalogue administrator application role (D2-15, authorised by role, never by project grants); a notification-settings capability for the content policy; "Reconcile own contributions (override)" (Q-36); the adjudication capability for a profile (until F1b, Reconcile on a stage that binds the profile; an assignment never grants it, RS-R53); "Apply a Study target override"; "Assess training", "Promote training evidence" and "View training results", with the training admission anti-escalation check (admission only into a permitted reviewing group); viewing AI model configurations and run provenance (RI-R47); Monitor for stage pool history and other reviewers' eligibility explanations (SP §3.13).
  • Owner-session disclosure: active contribution exclusions are part of the disclosure policy for exports and statistics (current exports omit excluded contributions by default; an exporter with rights may include them, labelled); ordinary account deletion keeps named attribution, shown with an "(account deleted)" suffix to viewers who may see identities (PROPOSAL), and identity erasure is not decided (T-POL-02); a merging user who is blinded sees aliases and may delegate without learning identities (DM-AE17); browsing a reviewer study pool never shows other reviewers' candidate decisions, answers, tallies, identities or submission times (D4-19, OS-A27); active-work impact previews show counts to everyone and names only with Monitor, never across blinding, and never grant anything (UX §3.9, ACD §3.10).

Conformance tests: Test IDs: C10-T01 to C10-T09 (acceptance criteria §7.5).

C11 — History, export and manifests

Implements: EX1, EX2, AG1–AG3, VS2 reporting. Baseline: current exports only, streamed to the browser. Open #2461/#2574 reserve AsOfDate and other modes but accept only CurrentState. OnlyCompleted is forwarded but not consumed by writers (research §1.5).

  • Modes: current (default; gold and candidates as permitted), previous versions (session and gold snapshot versions), as of a date (review-state reconstruction where history exists; coverage labels where it doesn't). Reuse the reserved export-spec modes rather than inventing a second export architecture.
  • Ordering (F1a): per-aggregate sequences order records within an aggregate. Every canonical record carries a hybrid logical clock stamp: the larger of the host clock and every stamp the command read, plus one, so a record that references another always has a larger stamp. Every study-scoped command writes its Study (CR-1), so stamps on one study increase strictly. There is no per-project commit sequence: it would serialise every commit in a project (DC-01, ADR-019's measurement). Wall-clock fields never order anything: observedAt on a revision and legacy DateTimeCreated are evidence fields with trust levels, never used for ordering or as-of selection.
  • As-of rule (F6a): as-of means "what SyRF knew at that stamp", not "what was true then". As-of(T) is offered only when T ≤ now − (transaction lifetime + expired-transaction sweep + twice the clock-skew bound + margin), and a cut at T is causally closed. Every dataset in the manifest is classified as versioned (reproducible), current-only (labelled "as at export time") or not observed. Two exports at one T are identical for versioned datasets and the same requester authority, except identities erased since, which the manifest records (D2-14; owner session: this exception applies only if an identity-erasure process is approved, T-POL-02; ordinary account deletion keeps named attribution); identity is proven by the content digests recorded in the manifest. A current export is a cut at the stamp taken when it starts. A restore adds a history-discontinuity record that manifests report (D2-13; owner session: D2-13 is a brief item with an isolated recovery rehearsal and a RecoveryManifest, BC §8.4).
  • Coverage manifest per dataset: answers, sessions, screening, gold, outcomes, study metadata, lifecycle, citations and aliases each state their basis and coverage. Dates before a project's adoption return "not observed", never the adoption snapshot. Legacy timestamps carry trust levels (DateTimeCreated is settable and stamped at construction). Owner session: "aliases" reads "merge lineage" (C21); HistoryEvent (C20) is a versioned dataset whose as-of views also wait until no stage pool sweep with an activation at or before T is running or stalled (history watermark rule, PROPOSAL); converted projects carry conversion provenance, the legacy-gap states and the tracking start for pool history (BC); contribution exclusions in force and AI model configuration and run versions are listed.
  • Mixed versions (versioning model §10): every exported answer carries (questionRef, questionVersionSeq, classSeq, optionId[], value[], responseMode?, answeredUnderVersion, qualificationPolicy); gold values carry the snapshot seq and goldNeedsReReconciliation; wide exports are generated per form version or per compatibility class with a per-cell version column, never mixing classes in a column; manifests list every definition version with its digest and the policy generations in force; adopted answers carry AuthoredUnder (Verified(v1) or Unknown).
  • Suppression: a descendant preserved under a suppressing ancestor answer or mode is omitted or carries an explicit status; it is never emitted as a live value (PH-06).
  • Usage: question-version usage is counted from revisions; form-version usage from session versions (latest explicit version per session, by category, once across stages); draft_only from drafts by base form version.
  • Extraction datasets default to studies whose required profiles are collectively Included, with an explicit option for the rest and per-row collective outcome and surplus-assessment columns (SR-17; methodology coverage).
  • Retention: whether exports are stored or regenerated is decided in the C11 ADR.
  • Blinding: for a form bound to several stages, the most restrictive bound stage's BL1 applies (Q-28). Superseded by the owner session (5 October 2026; superseded wording 4): exports apply the form-owned (annotation) or profile-owned (screening) reconciliation blinding.
  • Disclosure: authority and visibility are checked at retrieval and delivery (C10).
  • Legacy fix: making OnlyCompleted work changes legacy output, so it ships behind a flag.
  • Owner-session export content: accepted values carry AcceptedResultVersion.authority and labels follow it ("Single annotator (accepted automatically)", "Reconciled (one candidate)"); adopted hints are labelled; screening exports add decisionSourceType, aiModelConfigurationVersion, externalRunId, confidence, thresholdApplied, onTrainingInput and, on outcomes, machineContribution; the codebook lists, for screening columns, the decision source types and the AI model configuration versions used, and per answer answeredUnderVersion and qualificationPolicy (RI §3.9, RI-R29); merge-created records carry their source versions and exports carry lineage columns for tombstoned inputs (C21); reconciliation conversations stay outside candidate-answer exports (D3-25).

Conformance tests: Test IDs: C11-T01 to C11-T09 (acceptance criteria §7.5). Owner session: C11-T05 (erasure in manifests) becomes conditional on T-POL-02; the screening export columns and codebook entries follow RI-AE29 and RI-AE36.

C12 — PRISMA units, authority and report manifest

Implements: PR1, FEAT-011 constraints, amendments A–P once approved (Q-06a, Q-06b, Q-37, D4-07, D4-08, D4-11; the range read A–O until the owner session added amendment P). Owner session (5 October 2026): Q-06b, Q-33, Q-37, D4-05, D4-07, D4-09, D4-10 and D4-11 decided, so amendments B, E and F are approved (Q-06b, E1), K and M are approved (Q-37, D4-07), L is approved with its alias rule replaced by C21, and O is replaced by prepared multi-source links; amendment P (external and AI-model screening sources in FEAT-011 terms: outcome composition, the machine-assisted share and the box 3 versus box 5 question for sole-screener AI exclusions) is proposed, with C22; Q-23 and D4-08 carry-forward alignment (prepared multi-source links, grouping deferred); Q-17, Q-16, D4-12 and the PRISMA box mapping for pool history versus review through the stage are specialist inputs (T-SI-01, T-SI-02, T-SI-05); detail in RI.

  • Units stay distinct: Citation (immutable import occurrence with source type), Publication (system bibliographic identity; privacy rule in amendment L.7), Report (full-text identity; amendment B), Study (project reviewable unit; StudyLink groups collate reports of one study, amendment O), animal populations and cohorts (never PRISMA units). Owner session: reports, exports and screens label imported references, source documents and Studies; a report identity is a sourceDocumentKey with its basis on StudyVersion.referenceLinks[]; every snapshot carries reportIdentityCoverage (Established, Partial, Not established) and, while grouping is deferred, says "one report per Study assumed (identity not verified)" where identity is not established; StudyLink grouping of distinct reports is deferred (D4-08; RI-R01 to RI-R03).
  • Write-shaping parts, frozen at F3 with amendments A and H (before R3a writes them): unit identities; the per-profile screening outcome with route provenance instead of a single stage ID; authority values {CandidateAgreement, Reconciled, Admin with an override audit, Imported with an independence declaration, LegacyUnknown}; results including Unsure (D4-01), never Excluded; a structured reason with coverage status (primary versus several counted reasons is Q-22, so the shape must allow both until it is answered) carrying the primary-reason rule (D4-13); the StudyEnteredPool event (FEAT-011's pool-entry event), written to StudyPoolLedger with filter/profile versions, separate from personal admission and batches. Calibration records (D4-04) are never pool-entry or screening events. Owner session (5 October 2026): the authority values are superseded by finalSource ∈ ProfileRule, Adjudicated, MergeResolved plus the composition fields machineContribution and externalHumanContribution (mapping: CandidateAgreement → ProfileRule; Reconciled → Adjudicated; Imported → ProfileRule or Adjudicated with composition set, and Imported stays a candidate provenance kind; LegacyUnknown removed with Q-35; Admin → no value unless an outcome override is created; RI §3.13); the outcome gains resolutionState and only Included and Excluded are definite; Q-22 is decided-amended (the primary reason is template and reporting guidance and several reason questions are supported; distinct excluded Studies are counted apart from overlapping reason counts); StudyEnteredPool is renamed WorkFirstReleased and written as a C20 HistoryEvent, and stage pool membership (StagePool*) is a separate C20 dataset; calibration becomes training, whose records are never pool, release, screening or PRISMA events.
  • "Entering screening" (boxes 4 and 8, "made available to screeners") is defined in amendment A: protocol scope, or actual release including shared batches and personal grants. Fixtures cover early-stopped and batched reviews. Owner session: "made available to screeners" reads WorkFirstReleased; stage pool history is separate audit data; reporting prioritises actual review through the stage (measure M3, with its eligibility justification) over every-ever-in-pool membership (superseded wording 16); evidence collected elsewhere is shown as "satisfied elsewhere" and never counted as reviewed in that stage; a filter departure is never reported as a screening exclusion; pool-tracking coverage is disclosed and pre-tracking history is never fabricated; the exact box mapping is specialist input T-SI-05 and reports present the labelled measures until it is recorded (RI-R04 to RI-R09).
  • Identification part (F-P): Citation with source type; earliest-source downstream column; the Citation to Publication link record (amendment N); retrieval as fullTextStatus only, with human actions and events (amendment M); search documentation fields and searchRound (D4-05, SR-24); the search-population family extended with source type (OPS1) for statistics screens only; withdrawn searches per amendment J and D3-12; reported counts for steps done outside SyRF with their entry phase, kept separate from computed counts in every manifest (amendment K).
  • Deduplication: ASySD inside SyRF as FEAT-012 specifies, with merge as an alias, aligned with the admission service (amendment L); box 3 combines SyRF-detected and externally reported duplicates. Owner session: "merge as an alias" is superseded by C21 (one consolidated current Study, reversible unmerge); distinct counts follow merge lineage and never count tombstoned inputs as extra current Studies; Q-37 decided (imports preserved, QC sample and reviewer flags, Publication privacy); ASySD parity thresholds and the performance target are proposed, not approved and not achieved (D4-21, T-SI-04).
  • Phase mapping: a versioned per-project mapping from each profile to its PRISMA phase (title and abstract, full text, or not reported, for example a sub-study profile or the legacy compatibility profile), set in profile settings (R3b). The required profiles for the lifecycle "Included" transition (P2) are those mapped to the title/abstract and full-text phases.
  • Arithmetic identities (F6b, PROPOSAL): every snapshot satisfies, per source column (Database/Register, Other, Unclassified) and with explicit remainders shown in the manifest and the diagram footnote: I1 #31 = #3 + #5; I2 #32 = #29 (all Column 2 source types, correcting FEAT-011's #32 = #10 + #11 + #12, which drops Other records); I3 #33 = #31 + #32; I4 #34 = #33 − #7 − #8 − #9 (remainder: pending dedup review and check); I5 records_after_removal = records_screened + not yet entered screening; I6 records_screened = records_excluded + sought + unresolved at title/abstract; I7 sought = not_retrieved + assessed + awaiting retrieval or assessment; I8 assessed = excluded_with_reasons + included + unresolved at full text; I9 Σ reasons = excluded_with_reasons − reason not recorded; I10 new_studies = Σ columns included resolving StudyLink groups once, new_reports ≥ new_studies; I11 total = new + previous (D4-11); I12 total_studies_ma ≤ total_studies; I13 reported external counts reconcile per field and per search. A mismatch blocks freezing unless an administrator records an explanation in the manifest.
  • External steps (amendment K): entry phase per search or import; boxes 2–9 and 11–15 = computed + reported; #31–#34 computed only; boxes 10, 16 and 17 computed only; box 1 from previous-review records with the template variant switch.
  • Snapshots from authoritative records only (MS-11): a snapshot is computed from Citations, ExternalStepLedger entries, ScreeningOutcomes, StudyLifecycleLedger and StudyPoolLedger entries, StudyLink groups, alias sets and the PrismaPhaseMapping version at the report watermark (a hybrid-logical-clock stamp) and stored frozen (PrismaFlowSnapshot). FEAT-024 rows are never a report input. Owner session: StudyPoolLedger entries read HistoryEvent pool and review-start records and WorkFirstReleased entries (C20); alias sets read Study and merge lineage (C21); StudyLink groups are deferred; inputs add accepted ExternalScreeningDecisions, search documentation versions and the protocol record version; coverage adds report identity, pool tracking, the machine-assisted share per phase and legacy-gap labels (RI §3.2).
  • Report part (F6b): reports freeze against a manifest; amendments append; the manifest records the deduplication algorithm version, tier rules, auto versus reviewed share, QC sample and reversals (PRISMA-S item 16); the methods-summary block (PRISMA 2020 items 5–11, 16, 24) is generated from the manifest. Box 17 uses the "Synthesis inclusion" attribute recorded under the Record synthesis inclusion capability (placeholder name, A-03), owned by L12 in R5b.
  • Rule: no personal Include, extra completed work, form target, inferred cohort, imported decision with unknown independence, calibration record or extraction completion changes a PRISMA count. Owner session additions: no external or AI-model-generated decision changes a count before validated acceptance (RI-R43); no training attempt changes a count, and promoted training evidence counts only from its promotion onwards like any other live contribution (TI); no pool membership without review is counted as reviewed; machine-assisted outcomes stay distinguishable from exclusively human ones in reports, exports and the methods summary (RI-R45); previous-review counts are only ever supplied values (D4-11).

Conformance tests: Owner-session additions: RI-AE01 to RI-AE16 and RI-AE29, RI-AE36 (units, coverage, measures, the reporting priority, withdrawal, documentation, retrieval and the machine-assisted share), DM-AE22 (distinct counting by lineage, pending T-SI-05), TI-AE01 (training changes no PRISMA input). Test IDs: C12-T01r, C12-T02 to C12-T10 and C12-T11r (acceptance criteria §7.5); the owner session retires C12-T01 (the outcome authority list) for C12-T01r (outcome provenance through finalSource and the composition fields) and C12-T11 (merge as an alias) for C12-T11r (a consolidated Study counts once and tombstoned inputs never count).

C13 — Classification, populations and inference

Implements: the population/cohort decisions recorded in COMPARISON and the classification research (§2–§4), TC1, OD12 follow-ups. Entity types carry capabilities (classifies animals, structured subsets) and numbered child questions. Entity-type identities (EntityTypeId) for the seven legacy categories, cohort, outcome measure and experiment are minted at F1a as a shared-kernel value object; C1 adds capabilities and project-defined types without re-identifying anything (DD-12). Every answer carries a population reference from its first canonical write; the default whole-study population is derived deterministically from the study ID and needs no document until C1 enables classification for the project (DD-24). Each study population has a system whole-population cohort; every instance belongs to exactly one population; instance identity is the label head's ID (VB-09). Relationship/set annotations live on the parent/set with evidence (disjointness and exhaustiveness are separate claims). Shared concepts are defined once; paper-specific mappings are answers; project rules are versioned and link specific concepts. Inference is derived, explainable, withdrawable, never written back as a reported answer, and never creates counts without support. Implications such as Pregnant ⊆ Female apply without automatic strictness. Inferred cohorts are shown with their outcome associations, and conflicts are shown with their supporting provenance (C2). Population merging and cross-type count solving are follow-ups after C2.

Owner session (5 October 2026; S5, Q-18 and Q-19 decided; OS-A19). Inference ships as a beta, off by default, with an explicit project-designer opt-in, recorded as an audited project setting with the acknowledged explanation version; templates, copies and baseline conversion never enable it, and it does not switch on explicit classification recording (C1), which keeps its own enablement. It enhances ordinary annotation and reconciliation and is never a parallel reviewer workflow. Input rule: suggestions derive only from the current reviewer's own authorised snapshot (CandidateSnapshot) or a pinned AcceptedResultVersion (AcceptedResult), never from a mix of unreconciled reviewers' assertions; candidate-basis results are visible only to that reviewer and those who may see that candidate. InferenceResult is keyed by basis, rule-vector digest and engine version; when exact inputs or rules change it becomes Superseded (linking its successor), and disabling the beta or retiring a rule makes it Withdrawn; both stay as history while the project exists. Count rule: reported answers are preserved and animal counts are never invented; count statements appear only where proven. The first reasoner covers the four operators (Conjunction, Containment, Disjointness, Exhaustiveness) through ClassificationRuleVersions; bounds reasoning waits for a later approved scope. Inference is never a vote, an accepted answer or a PRISMA count (TI §3.7 to §3.9).

Conformance tests: Owner-session additions: the TI acceptance evidence for the beta opt-in, the input rule, supersession and withdrawal with history, and the count rule (TI §11). Test IDs: C13-T01 to C13-T05 (acceptance criteria §7.5).

C14 — Outcome schemas, measures and observations

Implements: OC1, OC2/ODIR1, TC1, RD16 (keep the shipped entry pattern), MIG1.

  • Supplied schemas (legacy-compatible, event-count) and project-owned custom schemas are versioned. Each schema defines series-level and observation-level fields with semantic roles, types, validators and cardinality.
  • A dedicated system schema-selection question targets schema configuration records, not reviewer-created instances (owner clarification of 27 September, recorded in the classification research).
  • Outcome measures are reviewer-created per-study entities (A-20): reviewers create them from the paper; admins never have to predefine them. Each measure carries one versioned direction across cohorts in that paper, with no context override (ODIR1); direction is a single measure-level answer, revisable and reconciled in R4c, never copied per series. Direction is never derived from numeric type and is not a validator or treatment-effect claim (OC2). The C14 ADR confirms this reading before O1, or raises it with Chris.
  • The legacy-compatible schema enables mapping, never automatic migration. Canonical forms admit quantitative extraction only from O1. Existing outcome entry (matrix, cell dialog, spreadsheet, graph) is kept and extended.
  • Extraction provenance (PROPOSAL, SR-06; E90): every observation carries an extractionMethod role ∈ {reported, graph-estimated, calculated, author-supplied, unknown} and a series-level dataSource note (table, figure, page); graph-estimated is the default when a PDF graph region is linked.
  • Unit vocabulary: a project unit vocabulary (controlled list with SI-aware labels and free-text fallback, seeded from a CAMARADES list); the validator "same measure, different unit" warns at Save and blocks binding at reconciliation (R4c).
  • Dispersion catalogue and legacy-compatible fields (before Q-17 closes; E12): average {mean, median, other}; dispersion {SD, SEM, 95% CI lower and upper, IQR Q1 and Q3, range min and max, none reported}; n at observation (default "same as cohort n", with provenance); events and total for dichotomous outcomes; time with unit. Dispersion is never converted on export. "Variation" (OC1) means the dispersion role and its catalogue value.
  • Domain validators (AC-O1-02, AC-O1-11): SD ≥ 0; SEM ≥ 0; n integer > 0; events ≤ total; time monotone within a series; CI lower ≤ average ≤ CI upper; Q1 ≤ median ≤ Q3; an SEM/SD plausibility warning (SEM × √n ≈ SD); warnings never block Save, blocking rules block Complete.
  • Sample-size rule: the analysis n is the observation-level n when recorded, else the cohort n; exports carry both and nSource; O2 never overwrites a cohort count with a series count.
  • Verified gold (D4-03): a Verification step on target-1 forms produces a gold snapshot with authority = Verified, distinct from Reconciled and from Q-29's accept-as-gold; no agreement statistic is computed for it; exports label "single extraction, verified". Superseded by the owner session (5 October 2026; D4-03 decided-amended, superseded wording 11): "one extracts, one checks" is one-candidate human reconciliation under RequireHumanReconciliation (C9); labels follow AcceptedResultVersion.authority.
  • Owner session: estimated-from-graph provenance is decided (D4-10); graph digitisation is a later decision after O1 pilots. Legacy outcome data converts under the legacy-compatible schema in each project's baseline conversion, with ValueOrDefaultUnknown where a stored value may be an untouched default (Q-05 decided-amended through R4; BC). The event-count schema waits for the scientific field specification (Q-17, T-SI-01).

Conformance tests: Test IDs: C14-T01 to C14-T06 (acceptance criteria §7.5).

C15 — Notification capture contract (C15 v2)

Implements: the 3 October scope addition; delivery for QY6/QY8 notices, RA assignment notices and LC1 alerts. Owner: the notification programme (capture, inbox, email, digests); L14 writes the specification and L8 the disclosure hook. Freeze: F1b for the contract (with C10's disclosure); kinds per feature. PROPOSAL (NS §4.1–§4.2). Baseline and catalogue: notifications integration; programme changes: programme integration §8.

  • No second notification store. Durable intents are part of C15; in-memory outboxes stay forbidden. Workflow state lives in feature aggregates and feature-owned queues, never in ReadAtUtc.
  • Kind registry. Each owning feature registers, through DI, an INotificationKind: kind, email category, scope (legacy, canonical or both), admission flag, inline recipient limit and resolver. A registry test fails the build when a kind lacks a category, resolver, label or disclosure fixtures. The eight existing kinds keep their typed fields and map to themselves.
  • Source and view. Inbox rows carry a generic Source sub-document (type, IDs, stage list, task ID). The server provides the action label, context lines, typed availability and workflow state (a NotificationView). One capture service serves every writer.
  • Occurrence identity. SourceId = SHA-256(kind | source type | source ID | occurrence key), the same for every recipient; row ID = SHA-256(SourceId | recipient). The occurrence key comes from durable identity (command ID, aggregate version, transition, publish operation ID), never a random value. Capture is a bulk upsert with $setOnInsert. Two lifecycle transitions of one source create two items; replaying an occurrence creates nothing. StudyConversation and StudyIssue are the models; reviewAccessGranted's random IDs are not.
  • Capture modes. Inline: inside the active source transaction, with at most the kind's inline recipient limit; if capture fails, the source rolls back. Recorded fan-out (C19 class (b)): the source transaction writes one durable intent (NotificationFanOut: the occurrence plus a recipient selector, either a frozen list such as a publication manifest's owners or a capability evaluated with current authority at expansion); a leased, idempotent worker writes rows in bounded batches and records progress. Above the threshold (PROPOSAL: 200 recipients) recorded fan-out is mandatory. Time-driven notices (assignment expiry warnings, LC1 reminders) are domain transitions run by a scheduler that writes a marker on the aggregate and captures inline.
  • Admission. Capture happens only when the kind's flag is on, its scope matches the project mode, and the project is admitted for notifications (per-project notification admission, an R0 enrolment scope). Inbox reads stay available whenever saved items exist, whatever the capture admission.
  • Disclosure. INotificationDisclosurePolicy runs after every resolver, for HTTP reads and both email processors, given the channel (inbox, email, digest), the recipient's role and the stages' BL1 and VS1 settings. Every channel: never candidate answers, personal votes, other raisers' concerns, or a raiser's identity where blinding applies; reviewer references are BL1 aliases from one stage-owned alias source. Email and digest: title, project name (D3-22) and link only; never study titles, aliases or free text. Fixtures cover each channel and the candidate, reconciler, admin, revoked and blinded roles. Superseded by the owner session (5 October 2026; O2, D3-22 decided, OS-A26): reviewer references are context-local aliases under the blinding of the relevant form or profile; emails and digests follow the project's versioned NotificationContentPolicy, read after the resolver and the disclosure policy and checked at send time: project name (on, active members), Study title and short bibliographic context (on, recipients who may view the Study), actor reference (role or alias; names only where the recipient may see identities and blinding does not apply), answer values and free text (off by default, configurable, shown only where the recipient may see them and blinding permits), and a link that rechecks access in SyRF. The policy only narrows what disclosure allows; a recipient may choose minimal emails and never widen the policy; sent email cannot be recalled (AC §3.5).
  • Recipients are expanded when a row is written (or when a fan-out intent is expanded); the actor is excluded; per-raiser notices go to the raiser only. Feature queues, computed at read time, reach people granted after an event. Every release passes with every notification flag off.
  • Near claims (RT-25). No notice per routine claim; one workload notice per reviewer per plan change; revocation events keyed by claim scope.
  • Version skew. Preferences accept unknown keys and treat missing keys as off; the client sends back keys it does not render; dispatch, discovery and digests look up the kind's category. An unknown kind leaves its ledger row ready (never terminal Suppressed); that behaviour ships one deploy before the first new kind.
  • Enablement. An operator delivery halt pauses dispatch without cancelling it; notificationEmail declares its dependency on notificationInbox; G-NOTIF, per environment and kind family, precedes any enablement outside the e2e stack and Mailpit (D3-21). Owner session: D3-21 is a brief item with ACD §3.9's controls (Chris approves each environment and kind family; per-project notification admission; Mailpit outside production; a global and per-family delivery pause whose paused items keep their send-time checks); per-project email mute (NotificationEmailPreferences muted projects) stops immediate and digest email while inbox rows, the badge and My work counts stay (D3-24); notice resolution (ResolvedAtUtc, resolution) keeps history and makes the unread count "unread and unresolved" (D3-23 brief item). The content policy and per-project mute are prerequisites before any email category is enabled outside Mailpit. No notification delivery is authorised by the owner session.
  • Owner-session kinds (capture only). Generated session versions and target changes (RD), merge conflict delegation and merge or unmerge outcomes (DM), pool departures affecting started work and continuation-setting changes (SP), adjudication assignment and claim releases (RS), external run acceptance affecting active reviewers (RI), contribution exclusion and project deletion and restoration (AC). Each kind registers through the kind registry with disclosure fixtures; capture follows recorded fan-out where recipients exceed the inline limit.
  • Ownership. The notification programme keeps capture, inbox, email and digests. StudyConversation moves to L6 at R4a; study issues move to Study Management and checked PDFs to the PDF programme (NS-19). Operations hosted in PM capture notices, so PM receives the capture capability as an R0 item (E59).

Conformance tests: C15-T01 to C15-T11 (acceptance criteria §7.5) for every release that adds a kind (the NS review's AC-C15-01 to 09 are C15-T01 to T09; AC-C15-10 is C15-T11 with AC-ALL-04 (d)). Owner session: the AC acceptance evidence for the content policy, mute and resolution (ACD §11; AC-ALL-30 is replaced) applies to every email category before enablement.

C16 — Compatibility floor, admission and reader/writer compatibility

  • Floor (E16, E48): every embedded type the programme may extend captures unknown elements and writes them back; ignoring alone is never enough. ScreeningInfo, ExtractionInfo, SessionTally and StudyBulkUpdateLock gain no fields; no field is added inside a persisted computed collection; schema-version-conditional serialisation is audited. Canonical facts live in top-level Study and Project fields or in new collections. R0 also ships reader logic: the SessionTallies getter and the claim pipeline merge the canonical summary's per-stage projection, and an IReviewMembershipFacts seam with shared predicate fragments lets pool, capacity and readiness checks read canonical membership, all inert until a canonical writer exists. A writer floor (ServiceVersionFloor) refuses canonical commands while any instance runs below R0. Floor steps repeat before R2b, R3a and P1, and before C1 or O1 where they add embedded fields. Flag-off stops new writes and enrolment but keeps saved work readable. Owner session: the floor step before P2 adds state = Tombstoned to the shared pool, capacity and list predicate fragments so legacy readers exclude tombstoned Studies and every inventoried legacy writer refuses them (DM-R20, DM-AE20); the composite write guard gains the project deletion marker beside the bulk-lock and ownership guards (ACD §3.3); Project.deletionState and the Study fields of C21 follow the N-1 capture rule.
  • Ownership as data, enforced on the documents writers write (E49): a CanonicalScopes marker on Study and Project, checked in legacy aggregate methods (one document write with the Audit.Version CAS, with or without a transaction), by a composite registered IAggregateWriteGuard for generic and direct writers (composed with the bulk-lock guard and covered by the architecture test), and by project-wide pre-checks. pmCanonicalOwnership is the audited registry, reconciled with the markers. Markers on existing scopes are set through ADR-020's lock, verify, stamp and release protocol. Flags and enrolment gate only new admission, never ownership.
  • Admission service: one server-authoritative per-project admission service (the CanonicalEnrolment record) read by API and web, with an audited admit/remove action and a rule for new projects. Environment-wide flags owned by other programmes are settled per flag (Q-25). It is never FEAT-024's statistics allowlist (next bullet).
  • Admission record versus statistics eligibility (MS-24, DC-21): R0's admission record is never the FEAT-024 allowlist. FEAT-024's durable eligibility (#3524) is built after C16 freezes and shares the record shape and audit, with statistics eligibility read inside the transaction by FEAT-024's gates. R0 refuses to admit a project that is allowlisted for FEAT-024 writes but not in fold mode.
  • Admission scopes: canonical forms and profiles; per-project notification admission (NS-04); per-project AF2, shell and eligibility admission (DS-04); the binding-scope tracking pilot (D3-16). The flag overhaul's P7 per-project targeting keys to the same record (PH-14).
  • Compatibility mechanisms are named separately: extra-element capture plus reader logic (this floor), the fold protocol window, and per-family catalogue versions with the configuration digest (MS-09; C8). Existing floors are reused: ServiceVersionFloor, ADR-019's storage-version tripwire with its allowlist guard, and ADR-011's writer-floor precedent (PH-29).
  • Rollback: each release ADR records the minimum rollback image per service, rehearsed by an image rollback with canonical data present. After canonical writes, rollback is canonical-aware (forward recovery or read-only containment), never a destructive down-migration (screening research, §5). Binaries below R0 are not a rollback target once canonical data exists. A release that changed a statistics writer, family or protocol follows FEAT-024's rollback order (MS-16). Owner session (R4; OS-A14, OS-A15): every project converts to the faithful baseline, first in opt-in trials in staging, then production pilots, then universal waves that include completed and inactive projects; a project with an unresolved conversion issue is quarantined and remediated toward the universal target, never force-converted lossily, and legacy status is temporary. Each conversion has a routing-rollback window that closes at the first canonical write: firstCanonicalWriteAt on the ownership registry is set by CAS in the first canonical command, and routing rollback requires it to be null under the same CAS; afterwards recovery is forward or read-only containment, never a flattening into legacy. Retiring legacy writers (R7) needs its own verified milestone. No migration execution is authorised (BC §4.8, §4.9, §10).
  • Inventory: every writer and reader with its canonical-scope behaviour (route, refuse or adapt) (consistency model §6.5; migration §1), including:
  • every UpdateMany on pmStudy with its version-bump status (verified on main eb93caffa): the question-delete cascade (StudyRepository.cs:1306-1319) and the three inclusion-recalculation updates (StudyRepository.cs:1619-1651), neither of which bumps Audit.Version, and the bulk-update lock release (MongoBulkStudyUpdateStudyWriter.cs:313-320), which does. Each refuses canonical scopes through the CanonicalScopes marker or is adapted;
  • the tracking Study writers (RT-08): the hub's join, leave, dirty/clean, disconnect and prior-study release; the PM idle, suspension and liveness consumers; the claim pipelines and typed admission; the direct-navigation claim; the screened-reservation release; the guarded settings save's "Apply anyway" revocation; the reservation restore on session deletion. Tracking readers: the presence snapshot and FEAT-024's availability calculators. Each has a route, refuse or adapt decision, and R0's floor makes the tally getter and claim pipeline merge canonical counts (RT-07);
  • the notification stack's Study writers (NS-08): study-issue acceptance (#3945; Title, Abstract, Year, DOI, Url) and checked-PDF approval (#3947; PdfRelativePath and the bulk-PDF delivered fields). Both are version-guarded and lock-aware today; for admitted projects after P2, a bibliographic correction appends a correction event and re-runs DOI/PMID matching, and a PDF approval records a P1 retrieval event;
  • 3939's batch writers (plan, membership, access) and #3941's capture paths, once merged.

  • Flags (E75): a flag read in both hosts is delivered to both, with a cross-host agreement check before enablement; no gate or evidence relies on runtime overrides until #3975 is fixed.
  • Job families (PH-15): every new background job family (publication phase 2, adoption backfills, retroactive deduplication, expiry, lifecycle transitions, outcome recomputation, notification fan-out expansion, batch-opening evaluation) gets an authority-transition M5/P9 classification and broker permission rules in its release ADR.
  • One writer host per canonical collection, following the architecture review's direction.
  • Every release states its flag decision, as the repository rules require.

Conformance tests: Test IDs: C16-T01 to C16-T08 (acceptance criteria §7.5). Owner session: the BC acceptance evidence for routing rollback before the first canonical write, forward recovery after it, quarantine and parity (BC §11), and DM-AE20 for the tombstone predicate.

C17 — Information architecture, coexistence, overview and settings DTOs

  • Navigation (Q-13; details in the UI comparison §4): Overview (project dashboard with setup progress, keeping the Project setup checklist footer with readiness-based content from R2a); Review (per-stage review); Design (questions, entity types, concepts & rules, outcome schemas, forms, screening profiles); Stages (per stage: overview, steps and settings, monitor); one Reconcile entry per study × form task; Members & groups; Data (export, history, agreement, PRISMA); Project settings (including the Workflow version panel). "Library" stays with Study Management; the duplicate review queue and the merge or split wizard live there (P2). One owner per route group, recorded in the route inventory (UX strategy §3.2).
  • My work (PROPOSAL, pending D3-07; NS-07): a project-level surface that is the reviewer's and reconciler's landing inside a project, listing every actionable item by role (to review by step, needs your attention, reconciliation, requested reviews, your queries, awaiting your approval) with the four feature-owned queues as filters and the inbox as history; a global app-bar badge whose counts are computed at read time over the queues and admission-based work, with no notification dependency; a cross-project "My work" tab beside "Pending Projects"; an admin banner on the project overview for pending LC1 requests. Rows deep-link to the task identity (RE4) and use stage-owned aliases (BL1); an item resolved by someone else leaves the list and stays in history (pending D3-23). Release: R3c (badge, banner, changes awaiting approval), R4a (surface, assigned work, requested reviews), R4b (concerns). The #2621 cross-project landing is post-GA with its own owner. Owner session (D3-07 decided): rows use context-local labels under form-owned or profile-owned blinding with no alias continuity across Studies (the stage-owned aliases are superseded); My work, the cross-project tab and the global badge work even when notifications are muted; rows add saved work after pool departure, merge conflict tasks, training attempts, adjudication for assigned groups, external runs awaiting acceptance and conversion findings; counts are computed at read time; D3-23 is a brief item (UX §3.5).
  • Coexistence: navigation per project mode (classic or versioned, names pending D3-03), the question editor's two modes (legacy API and canonical), and legacy labels, until the GA milestone and adoption. The minimum shared chrome (app bar, badge, inbox, rail geometry and states, Overview, Members & groups, Data › Export, Project settings, status chips, page shell and state, job language, copy deck terms) is identical in both modes; the workflow version badge appears in both; legacy chrome and shared pages are restyled under D3-06.
  • DTOs: overview and settings DTOs carry gate status, sufficiency and work status separately; stage overviews show bound forms, targets, steps, gates, readiness and batch frontier, never duplicated stage copies of shared evidence. Every read model declares its consistency regime (in-transaction projection, materialised rows, or computed at read), and every count or status DTO carries a freshness label (fresh from a materialised read, authoritative from a pinned fence read, rebuilding, or not observed, with its asOfStamp) and, for derived records, the definition-version vector it was evaluated under. Gates read only authoritative or fence-verified sources (DD-21). The UI shows "as of [time]" and "updating" from these labels and never shows a stale count as fresh or a count without a real numerator. "Who is offered what" is pool-level until X-AUTH-RESOLVER (D3-13).
  • Dockview layouts: saved layouts are stored per reviewer per capability slot (screening, annotation, combined), and the API validates allowed panel keys and one instance of each capability panel. A layout-contract amendment (capability keys per step kind, new panel keys for history, population context and reconciliation, and migration of saved version-2 layouts) is agreed with the layouts owner at F1c, before R2a's history panel.
  • AF2 extension points (step host, history panel, outdated and provenance markers, population context, outcome-schema entry, save-status indicator slot, conflict screen slot, the VersionedAnnotationFormDataSource port, and the Needs-updating presenter contract: fromVersion, toVersion, treatment, reason, guidance, and the prior value rendered with fromVersion's labels; E44) are agreed with the AF2 owner and merged as code at F1c, before L5 consumers build.
  • UI standard: every new or updated screen is consistent, modern and built with Material 3, following FEAT-023's semantic contract so it renders correctly before and after that programme's cutover (acceptance criteria §3, UI-1 to UI-11). The notification stack's inbox and preferences screens meet the standard before testers see them; its conversation, issue and PDF screens before production (NS-10, D3-01).
  • Terminology and copy contract (F1c): one copy deck (one definition per term, internal name, "never use"), implemented as typed message constants per feature with a shared core-terms file, a banned-string and import guard spec, and a user-guide glossary parity check in docs CI (UX strategy §5). Core terms pending D3-03: "Save progress", "Complete", "Changes kept, not yet saved", "Needs updating", "Outdated answers", "Fix", "Accepted answers (gold standard)", "Screening result"; plus "Update to version N", "Unpublished", the reviewer progress vocabulary (your work, available to you, waiting on others, locked by a step, enough reviewers), the slot vocabulary (review slot, held, released, offline, enough reviewers; the D2-07 rule copy), a distinct term for each kind of draft, the error and recovery copy for every C18 typed outcome, and one alias scheme across candidate cards, threads, history, presence and exports. v10's "Save draft" and v4's "All changes saved" are banned strings. Owner session (D3-03 and D3-04 decided with wording flexibility, U1): "Changes kept, not yet saved" and "Autosaved, not yet submitted" are superseded by "Draft auto-saved" and "Version checkpoint saved" (illustrative; the distinction from completion is fixed, the words may iterate); the alias scheme is context-local per reconciliation session (C9); new terms come from the specifications ("Saved work", "No longer in this stage", "Waiting for the team's screening result", "Enough reviewers are already working on this", "Stopped by exclusion", "Already sufficiently reviewed", "No review is recorded", "Single annotator (accepted automatically)", "Use accepted answer", "AI-model-generated screening decision"); "model decision" is a banned string (RI-AE20).
  • Active-work impact preview DTO (owner session). One shared preview shape for every admin action that affects people working now: what changes; who is affected (counts for everyone, names only with Monitor and never across blinding); what is kept (drafts and submitted work); what will be released (temporary reservations only); dependent results whose inputs change; the notices that will follow. The command recomputes the digest at commit and refuses with "The impact changed since you reviewed it" if it moved. Apply anyway appears only where temporary reservations conflict, names exactly what it releases and never bypasses permissions, allocation constraints or invalid configuration. Producers: RD, DM, SP, RS, RI, AC and BC (UX §3.9, ACD §3.10).
  • Device support (owner session; D3-05 decided). Large and complex forms support full annotation and screening on phones, tablets and desktops at launch, with accessibility, touch, virtual scrolling, diff autosave and whole-form validation; the largest project is an acceptance case. PWA caching and offline writes are beyond the MVP and not authorised (UX §3.3, §3.11).

Conformance tests: Test IDs: C17-T01 to C17-T06 (acceptance criteria §7.5). Owner session: the UX acceptance evidence for status labels, device coverage, the impact preview pattern and the copy deck (UX §11).

C18 — Concurrency, transactions and idempotency

Implements: PS3 (an exact publication boundary), SL2 and SL3, LC1 (no admission into a Completed stage), RA1–RA4 (editor and assignment races), GS1 (the gold pointer), EX1 (reproducible exports). Owner: L1 Engine with L0. Freeze: F1a. The full design is the consistency model §2, §4, §5, §10 and §11.

  • Per-study serialisation (CR-1): every canonical command that changes evidence, gold, outcomes, capacity claims or any fact in the Study canonical summary writes its Study in the same transaction (an Audit.Version CAS, the summary, the study clock). Different studies never conflict.
  • No hot document (CR-2): no per-project or per-form document is written by interactive commands: no project commit sequence, no per-save Project token, no FEAT-024 transactional point mode for enrolled projects.
  • Options (CR-10): snapshot read concern, primary, majority write concern with journal, maxCommitTime and a command deadline.
  • Re-execution: a definite abort re-executes the whole command from a fresh snapshot with jittered backoff. Retries are free when Study moved only through maintenance writes (fold, claim and idle tokens, capture moves). StaleBase is returned only when the command's own business base moved.
  • Command ledger (CR-6): one command-bearing record per command with a unique (ProjectId, CommandId), its result IDs and a request digest; lookup first; a digest mismatch is refused; an indeterminate commit returns OutcomeUnknown. FEAT-024 receipts correlate through OperationId = CommandId only.
  • Commands carry what they observed (CR-5): bases, snapshot IDs, input etags, query targets and draft etags; a retry never substitutes "current".
  • Cache rule (CR-9): deciding reads never come from the shared repository cache; existing aggregates use non-upsert saves (#3985).
  • Natural keys (CR-11): deterministic IDs; a DuplicateKey is a reload and CAS; collections and indexes are created at start-up, and pmStudy indexes are built through the operator route.
  • Ordering (CR-7): per-aggregate sequences plus an HLC stamp on every canonical record; as-of reads only beyond the watermark (C11).
  • Typed outcomes: one frozen catalogue (consistency model §10.3); never a 500. Owner session: the catalogue gains InputsChanged, ActiveWorkChanged, StudyConsolidated (C21), ContinuationRestricted, TerminatedByExclusion (C6) and GoldChanged (C9); the other new names in the domain model §6.3 are PROPOSALs. Generated session versions use deterministic IDs per (session, operation, generation) and CAS on the session head, so a replay or a race with a reviewer's Save never duplicates or overwrites.
  • Budgets: CanonicalCommitCommandBudgetTests; the write-path gate per D1-08.
  • Prerequisites: #3985 and #3973 (D1-02).

Conformance tests: C18-T01 to T04, C5-T08 (owner session: C5-T08r), C18-T06 and C18-T07 (the DC review's AC-DC-01 to 04, 08, 11 and 12); the screening research's cases A8, A13 and A14; the CR-1 architecture test; the stamp-collector test. Test IDs: C18-T01 to C18-T11 (acceptance criteria §7.5).

C19 — Durable effects and events

Implements: C15 capture, LC1 alerts, QY6 and QY8 notices, RA notices, publication phase 2, adoption and merges. Owner: L1 Engine with L14 and the notification programme. Freeze: F1a. The full design is the consistency model §7 and §9.

  • Three classes (CR-8): (a) derived on read; (b) a durable intent written in the commit transaction and handled by a leased, idempotent dispatcher (the claim-revocation outbox pattern) or by an operation record; © a best-effort hint (SignalR, change streams) that never carries correctness.
  • Operations (CR-4): ADR-020-shaped records with a lease, a generation, a stable cursor, chunks and a final pass; one active per scope; limits with a stalled state.
  • Fences (CR-3): a scoped fence on the scope's head; a drain of at least the transaction lifetime plus the expired-transaction sweep plus a margin; action in a pinned snapshot; release by the operation, by lease expiry or by an audited operator action.
  • Notifications: inline capture (bounded) or recorded fan-out (a durable intent plus a leased expander); time-driven notices through scheduler markers on the aggregate; deterministic SourceId and row IDs with $setOnInsert. No second notification store; durable intents are part of C15; in-memory outboxes stay forbidden.
  • In-process IDomainEvent: only for loss-tolerant, same-process effects, and only after #3973.
  • Change streams: hints only, because an invalid resume token restarts from now.
  • Event catalogue: in the domain model §6.2.
  • Owner session (5 October 2026). Stage pool events (StagePoolEntered, StagePoolDeparted) and WorkFirstReleased are facts written in the commit transaction of the change that caused them; the stage pool sweep after a filter activation and the filter-input preparation are operation records (class b); readiness re-evaluation after pool, outcome, accepted-answer, target and setting changes is a durable intent (class b) (C20). Merge and unmerge use staging as an operation and one activation transaction; notifications, claim revocations, the FEAT-024 staged rebuild and pool evaluation follow through durable intents and never expose partial authoritative state (C21). External run acceptance, contribution exclusion, project deletion and restoration, batch additional-review requests, bulk acceptance and training promotion are operation records with per-Study transactions. Live design-draft updates and presence are class © hints only.

Conformance tests: C18-T05, C19-T01, and C15-T01, T02 and T08 (the DC review's AC-DC-09 and 10; NS's AC-C15-01, 02 and 08). Test IDs: C19-T01 to C19-T05 (acceptance criteria §7.5).

C20 — Structured history events

Implements: consolidation §3 "Structured historical justification" (a firm owner requirement); Q-15 as replaced by the stage filter model; the targeted pool-membership history, eligibility explanation, historical pool coverage, explicit entry justification and structured events amendments (OS-A07 to OS-A11); D3-13 (distinct structured activity events, brief item). Owner: L4 Workflow with L11 History and L1 Engine. Freeze: F1a for the envelope, storage, idempotency, ordering and the adapter list; F3 for the stage-pool, release and eligibility event types. Content is owner requirement; shape, names and storage are PROPOSALs. Added by the owner session (5 October 2026). The full design is SP §3.5, §3.8, §3.12 to §3.14.

Purpose. An admin can explain why a Study was available, reviewed, not reviewed or no longer available, without assuming that the platform failed. C20 defines one versioned, queryable envelope for history facts that no existing immutable record carries, and adapters that read the existing immutable records into the same shape, so nothing is copied and source history never changes. It is not event sourcing: current state keeps its own authoritative records.

Parties. Writers: every command or operation that changes a filter input (screening decision submit and correction, adjudication, gold publication and target-one acceptance, imports, merge and unmerge through C21, search withdrawal and reinstatement, lifecycle changes, contribution exclusion, profile and form publication phase 2, external screening acceptance through C22), the stage pool sweep, batch openings and personal grants, the first start of a session through a route, and baseline conversion. Readers: the admin eligibility explanation, pool history queries, the reporting measures of C12, as-of exports under C11 and the integrity checker. Admission, selection, counts and readiness are never readers.

Envelope (logical, illustrative).

Field Content
eventId CSUUID, deterministic: SHA-256 over (event type, project, idempotency key)
eventType, family, schemaVersion Closed type set extended only through C20; family PoolTransition, WorkRelease, ReviewerEligibility, ReviewActivity, Configuration; an integer schema version per type, old versions readable forever
projectId, studyId, lineage Always present for stored types; lineage names the StudyMerge or StudyUnmerge and related Study IDs where identity changed
stageId, stepId, activity, subjectReviewerId Structured and indexed; stage identity and event type are queryable fields (owner requirement)
actor {kind: Member, SystemRule, AIScreeningModel, ExternalSource, Operator; id}; an AI screening model is a source identity, never a member login
effectiveAt, recordedAt {hlc, utc} each: when the causal change became current, and when the record was written
cause {kind, commandId or operationId, causeRecordRefs}; kinds Import, ScreeningOutcomeChanged, AcceptedAnswerChanged, FilterVersionActivated, StageActivated, StudyMerged, StudyUnmerged, SearchWithdrawn, SearchReinstated, LifecycleChanged, ContributionExcluded, ProfilePublicationApplied, FormPublicationApplied, ExternalScreeningAccepted, TargetChanged, BatchOpened, PersonalGrant, AssignmentCreated, ReviewerAction, TrackingBaseline, BaselineConversion
sourceVersions Filter, stage settings, profile and form versions, outcome and accepted result versions, regime, batch plan, capacity and continuation setting versions, as relevant
before, after, reasonCodes, clauseEvaluation Pool events: {member, episodeSeq}; ordered closed reason codes; a tree {nodeId, kind, result (True, False, Unknown), inputs [{kind, ref, version, observedValue}], children} mirroring the filter
coverage, seq, explanationText Complete, BaselineAtTrackingStart, ReconstructedFromRetainedInputs, NotRecordedInLegacy, CurrentSnapshotOnly; a per (Study, stage) monotonic sequence from the tracking marker; optional plain text that never replaces the structured fields

Rules.

  1. Stored types. StagePoolBaselineMember, StagePoolEntered, StagePoolDeparted, WorkFirstReleased (renamed from the round-2 StudyEnteredPool so that it no longer clashes with stage pool entry; exactly one per Study and stage; releaseKind ∈ SharedBatchOpened, PersonalBatchGrant, ExplicitAssignment, UnbatchedAvailability, InheritedThroughMerge), ReviewStarted (payload ReviewStartEligibility), and the conversion types BaselineConverted, ConversionRolledBack and ConversionQuarantined. Other event names in the specifications are adapters over the immutable record that already carries the fact (session versions, decision revisions, outcome history, adjudication versions, accepted result versions, stage settings versions, lifecycle and change-request entries, assignments, StudyTargetOverride, ContributionExclusion, StudyMerge, StudyUnmerge, search withdrawals, external screening runs), or new types added at the freeze, which lists which.
  2. Entry justification (owner amendment). Every StagePoolEntered records the effective and recorded time, the exact filter version and the full clause tree marking satisfied groups and clauses, the supporting input versions, the causal change with its command or operation ID, and the actor where one exists. It records filter eligibility only; permission, allocation and capacity eligibility to review belong to ReviewStartEligibility.
  3. Departures. Each StagePoolDeparted carries the failing clauses, the causal change and reason codes from the closed set (SCREENING_OUTCOME_EXCLUDED, SCREENING_OUTCOME_CHANGED, ACCEPTED_ANSWER_NOT_MATCHING, ACCEPTED_ANSWER_ABSENT, CLAUSE_UNKNOWN, FILTER_RECONFIGURED, STUDY_NOT_CURRENT_MERGED, STUDY_NOT_CURRENT_UNMERGED, HIDDEN_BY_SEARCH_WITHDRAWAL, LIFECYCLE_NOT_ACTIVE). A departure is labelled a screening exclusion only when that is the actual failing input; a filter failure is never automatically a screening exclusion. Leaving a pool never erases the evidence that caused it.
  4. Episodes. An entry or baseline membership opens an episode for the Study in that stage and the next departure closes it. A re-entry opens a new episode and never creates a second distinct Study.
  5. Where events are written. In the transaction that changed the evidence: every filter input changes through a Study write (CR-1), so the command compares the tracking marker (stagePoolTracking[]) with the new evaluation and records the difference in the same commit, first catching up any pending filter-version transition. Only filters whose dependency set contains the changed profile or question are evaluated (targeted reevaluation). A filter activation writes a sweep operation record; the sweep records transitions with the activation stamp as effectiveAt and the item's stamp as recordedAt, and finds newly matching Studies as well as departing ones. Autosave, drafts and page queries write no event and evaluate no filter. Claims, offers and refused page queries are not retained as history.
  6. Idempotency. StagePoolEntered and StagePoolDeparted: (Study, stage, cause command or operation ID, filter version, episode). StagePoolBaselineMember: (Study, stage, tracking start ID). WorkFirstReleased: (Study, stage). ReviewStarted: (session, route stage, route step). Inserts use $setOnInsert; a duplicate key is success, so retries, re-executions and operation takeovers never duplicate an event.
  7. Ordering. By effectiveAt.hlc, then studyId, stageId and seq. Stamps and sequences on one Study increase strictly; a sweep that reaches a Study after a later evidence change has already recorded the transition never inserts out of order.
  8. Current reads never trust history. Admission, selection, counts and readiness read authoritative current inputs or a cache proven current, never pmHistoryEvent or the tracking marker (an architecture test enforces it). History explains the past and is not a second source of current truth.
  9. Baseline and coverage. Tracking for a new canonical stage starts when it first becomes Active (StagePoolEntered, cause StageActivated). StagePoolBaselineMember is used only when a pool existed before tracking could observe it (baseline conversion, or the first release of history for an earlier canonical stage), with the tracking start as effectiveAt, coverage BaselineAtTrackingStart and no invented earlier time or cause; earlier history is labelled (NotRecordedInLegacy for converted legacy stages). When a Study was eligible and nobody reviewed it, the explanation says "No review is recorded" and invents no cause.
  10. Review start. ReviewStartEligibility is written once per session and route at the first start (first autosave, first explicit Save, or the decision itself) with route, pool basis, step basis, allocation basis, availability basis (NotEnforced (tracking off) where tracking is off) and the admission digest, outside the Study transaction when the start is an autosave. Opening a Study without editing writes nothing. Continuation after an exclusion or departure appears as the admissionBasis on later versions (C5).
  11. Queries. Entered, exited, ever in the pool during a period, membership as of T, episodes per Study, departure reasons (overlapping and labelled, never summed into a distinct total) and reviewed through the stage (a ReviewStarted or completed version routed through the stage; evidence collected elsewhere is "satisfied elsewhere"). Identity modes RecordedIdentity and ConsolidatedLineage; which mode a PRISMA box uses is specialist input T-SI-05. Start with indexed queries; a rebuildable episode projection only if the benchmark needs it, rebuilding identically.
  12. As-of. An as-of view at T needs the C11 watermark and no stage pool sweep with an activation at or before T still running or stalled (PROPOSAL). Frozen report snapshots store their result and watermark.
  13. Access and blinding. Stage pool history and other reviewers' eligibility need the Monitor capability; reviewers see their own starts and the explanations for their own availability; actors and reasons render under the form's or profile's blinding.
  14. Storage (PROPOSAL). One append-only pmHistoryEvent collection, replacing the planned pmStudyPoolLedger, with indexes {projectId, stageId, eventType, effectiveAt.hlc}, {projectId, studyId, effectiveAt.hlc} and {projectId, subjectReviewerId, eventType, effectiveAt.hlc}; inserts only; no TTL; retained while the project exists, including the reversible deleted state (permanent erasure is the unapproved T-POL-01). The F1a storage ADR may split families into collections.

Conformance tests (drawn from the specifications' acceptance evidence; the acceptance criteria §7.5 rows are added by the acceptance update; budgets are proposed, not approved):

Test Evidence Source
C20-T01 A decision under profile P evaluates only filters whose dependency set contains P, and evaluates the whole filter SP-AE05
C20-T02 Autosave, draft saves and page queries write no pool events and evaluate no filter SP-AE06
C20-T03 Self-departure: the valid submission commits, the outcome changes, one StagePoolDeparted names the command, the decision revision, SCREENING_OUTCOME_EXCLUDED and the clause tree; evidence is intact; no new offers follow; started work appears as saved work SP-AE07
C20-T04 Re-entry opens episode 2; the "entered" query returns the Study once with both episodes SP-AE08
C20-T05 A filter edit's preview counts equal the events the sweep records; a Study matching only the new version is entered SP-AE09
C20-T06 At least 1,000 randomised interleavings of a filter activation and an evidence change on one Study yield the filter transition before the evidence transition, with no duplicates SP-AE10
C20-T07 Retries, re-executions and operation takeovers create no duplicate events SP-AE11
C20-T08 An architecture test proves that admission, selection, counts and readiness never read pmHistoryEvent or the marker; selection uses the new filter while the sweep still runs SP-AE12
C20-T09 Sweep events carry the activation stamp as effectiveAt and the item stamp as recordedAt; an as-of request is refused while an earlier-activated sweep runs SP-AE13
C20-T10 Every StagePoolEntered has a filter version, a clause tree marking satisfied nodes, input versions, a cause and, where applicable, an actor (schema validation over fixtures) SP-AE14
C20-T11 Tracking start writes one StagePoolBaselineMember per current member with coverage BaselineAtTrackingStart and no earlier time SP-AE15
C20-T12 Departure reasons classify correctly for screening Exclude, other outcome change, accepted-answer change, Unknown, reconfiguration, withdrawal, merge, unmerge and lifecycle fixtures SP-AE16
C20-T13 The entered, exited, ever-in-pool, as-of, episode, reason and reviewed-through-stage queries match fixtures including re-entries and merges, within a measured p95 budget at 100,000 Studies (target proposed, not approved) SP-AE17
C20-T14 RecordedIdentity and ConsolidatedLineage give the fixture counts on a merge and unmerge fixture SP-AE18
C20-T15 ReviewStartEligibility is written once per session and route at first start with every field group; with tracking off the capacity basis reads NotEnforced (tracking off) SP-AE19
C20-T16 Every filter-input writer records transitions, one test each: decision submit, correction, adjudication, gold publication, target-one automatic acceptance, import, merge, unmerge, withdrawal, lifecycle, contribution exclusion, profile publication phase 2 and external screening acceptance SP-AE44
C20-T17 Conversion writes StagePoolBaselineMember for every Study in each converted pool with filter justification and conversion-time effectiveAt; reports disclose the pre-conversion gap BC-AE22
C20-T18 Training attempts write no pool, WorkFirstReleased or start events for live work TI-AE01

C21 — Duplicate consolidation and reversal

Implements: consolidation §2; D2-12 (replaced; superseded wording 2); Q-37 (merge part); OS-A29; PRISMA amendments D and L as amended; Q-02 (merge part). Owner: L12 PRISMA (deduplication) with L1 Engine. Freeze: F-P, after the current evidence view's performance and consistency proof; delivered by P2a (Study state, StudyVersion, unreviewed duplicates, the view shell), P2b (reviewed duplicates, conflict tasks, delegation, target confirmation, unmerge carry-forward) and P2c (accepted result and adjudicated outcome conflicts). Shapes and names are PROPOSALs. Added by the owner session (5 October 2026). The full design is DM. It replaces C1's "Merge and split" row.

Purpose. When two or more Studies are the same study, a merge produces one consolidated current Study with consolidated metadata, reference links and current review associations; the originals stay unchanged as history; an unmerge reverses the merge as a new action without erasing it.

Parties. Initiators: the duplicate review queue (ASySD AutoConfirmed and ProbableDuplicate groups, including the QC sample), a reviewer's "Flag as possible duplicate of…", an admin's library selection, and the system for unreviewed duplicates. Resolvers: the merging user, a delegated original reviewer, a reconciler with Reconcile on the form, an eligible adjudicator. Consumers: evidence (C1, C5), pools and history (C20), reconciliation (C9), statistics (C7 and FEAT-024), reporting (C12), exports (C11), notifications (C15).

Logical model (illustrative).

Element Content
Study parent state ∈ Current, Tombstoned; currentVersionId; tombstone {reason (ConsolidatedByMerge, ReversedByUnmerge), operationId, at, actor, successorStudyIds}; consolidatedInto for redirects. Changed only by activation, by CAS on Audit.Version
StudyVersion Immutable (studyId, seq): displayed bibliographic fields, each {value, origin, decidedBy, decidedAt, confirmation} with origin InheritedFromReference, SelectedFromReference, ManualOverride or SystemRule; referenceLinks[] and sourceDocumentLinks[]; references never move or change
StudyMerge Header: inputs with {studyId, studyVersionId, evidenceWatermark, evidenceDigest}, the reserved consolidated Study ID, status (Draft, AwaitingResolution, ReadyToCommit, Staging, Committed, Abandoned, Failed), entry point, confirmations, the draft consolidated StudyVersion, active-work digest, actors and times. Items: every evidence item with exact source versions, treatment (CarryForward, Resolved(task), NotCarried(reason)) and resulting records. Immutable once Committed
MergeConflictTask Kinds: same-reviewer form sessions, same-reviewer screening decisions, conflicting accepted results, conflicting adjudicated outcomes, differing reviewer targets, differing bibliographic fields or attributes. Exact inputs, assignee, status (Open, Delegated, Resolved, Stale, Withdrawn), resolution, resolver and time, delegation record
Merge-created records MergeCarriedForward and MergeResolved session and profile-session versions; carried results (origin = MergeCarriedForward, original authority kept) and MergeResolved results; the merge-basis StudyTargetOverride; the recomputed screening outcome, with a single input's adjudicated outcome carried as the final facet; UnmergeCarriedForward records on unmerge
CurrentEvidenceView Study.currentEvidence: per form the effective target and source, sessions with status, standing and origin, the current accepted result with authority, origin and an "inputs changed" flag; per profile decisions and outcome; lineage
StudyUnmerge The merge and consolidated Study; the restored Studies with new StudyVersions; items for every post-merge item with a lineage suggestion and a choice CarryTo(studyId) or LeaveOnHistorical; warnings; resulting records

Rules.

  1. One consolidated current Study (owner decision). Inputs become tombstoned history: never allocated, listed, offered or counted in current totals, and always readable in history, as-of exports and audit. "Historical" never means corrupt or deleted. The consolidated Study is a new identity reserved when the merge is created (PROPOSAL, option A; a survivor identity is the alternative, a brief decision).
  2. Inputs are never edited. Activation changes only each input's parent state fields; their references, sessions, decisions and accepted results stay exactly as they were. Only current state is copied, with provenance to the exact source versions; full histories stay on the inputs. Exposure and initial-observation markers are copied from the sources and a merge resolution is never a new independent observation. Drafts are never carried.
  3. Preview first. Inputs with exact versions, the evidence inventory per form and profile, every conflict, target differences, the suggested bibliography and active work are shown before anything commits.
  4. Conflicts are resolved before commit. Same-reviewer conflicts and conflicting accepted results use a reconciliation-like view in which agreeing compatible answers populate the controls and conflicts sit side by side; answers and completion status are resolved together and a resolved Complete still passes validation. The merging user chooses among the inputs' values or leaves an answer unanswered and never types a new value into a reviewer's session (PROPOSAL). Differing adjudicated outcomes need an eligible adjudicator or "no adjudication carried".
  5. Delegation and the actual resolver. The merging user may delegate a candidate conflict to the original reviewer, who receives a task naming the merge and the exact inputs and sees only their own submissions. The actual resolver is recorded; an admin's choice is never presented as the reviewer's. A changed input makes a task Stale. Commit is refused while any task is open or stale, and pending tasks stay visible with their assignee (names only to users allowed to see them).
  6. Targets. Where effective targets differ, the authorised merger confirms the consolidated effective target, applied through a StudyTargetOverride version with basis MergeConfirmation(mergeId). Qualifying reviewers count once; no target is double counted and no accepted result is promoted automatically.
  7. Active work. Active reviewers, reconcilers, interruptions, drafts, reservations and dependency changes are shown before confirmation and rechecked at commit (ActiveWorkChanged). Busy Studies are not refused. Drafts are kept; a save to a tombstoned input is refused with StudyConsolidated and a redirect, and "Continue" applies the kept draft explicitly on the consolidated Study.
  8. Atomic activation. Staging is a resumable operation whose records stay invisible under the reserved ID. Activation is one transaction: read every input in its snapshot; require Current, the recorded StudyVersion and evidence watermark (maintenance-only Study writes never count as a change) or refuse with InputsChanged and mark affected tasks Stale; refuse with Locked under a bulk-update lock; insert the consolidated Study with currentEvidence; tombstone each input by CAS and remove its claims; freeze the manifest; write StudyMerged and StudyTombstoned and the durable intents. A failure leaves the originals current and nothing partial visible. A Study is an input to at most one active merge (unique partial index).
  9. After activation. Notices go once per recipient under the notification content policy and blinding; inputs depart pools with STUDY_NOT_CURRENT_MERGED and the consolidated Study enters the pools whose filters it matches (cause StudyMerged), with WorkFirstReleased (InheritedThroughMerge) for each stage where an input was already released; stage status changes only through readiness rules and a manually completed stage stays completed (Q-02); reconciliation tasks on inputs freeze with drafts kept and a task exists for the consolidated Study once it has a qualifying candidate; FEAT-024 families rebuild under their staged fence.
  10. Outcomes. The candidate facet is recomputed over the consolidated decisions. A single input's adjudicated outcome is carried as the final facet, flagged "inputs changed" when the consolidated decisions differ, until an eligible adjudicator reconsiders it (RS-R58). A pending adjudication is not an outcome.
  11. Unmerge. A new immutable action on a Current consolidated Study that is not an input of a later merge (a chain is reversed from the latest merge first). It tombstones the consolidated Study (ReversedByUnmerge), returns each input to Current with its lifecycle restored, and never erases the merge. Every post-merge item needs an explicit choice of one restored Study or the historical merged Study; "both" is refused; moved items carry provenance; left items stay readable in the merged history. Accepted results whose inputs change are warned about, kept, and replaced only by explicit action.
  12. Bibliography. With one reference and no override the Study shows that reference's values transparently; a selected reference value or a manual override takes precedence; each field keeps value, source reference and version, actor, time and rule or confirmation; references never change; a cross-project Publication value never changes a Study's fields silently.
  13. Duplicates only. Distinct investigations and distinct reports are never merged silently; "Distinct report" and "Not a duplicate" are explicit queue outcomes, never re-queued for the same pair and algorithm version; grouping distinct reports is deferred (D4-08).
  14. Automatic consolidation runs only for unreviewed duplicates (no explicit version, decision, accepted result, draft or claim on either input; drafts PROPOSAL), with the bibliography picked by the system rule and recorded SystemOnly; anything else is admin-reviewed.
  15. Current evidence view. A stored, rebuildable projection written in the same transaction as every canonical command that changes current evidence and by every activation; it takes over the per-form member list of the canonical summary; size, write cost, rebuild parity and list-read cost are proved before its design freezes (owner requirement); a gate reads it only when its definition-version vector is current.
  16. Coexistence. The R0 floor step before P2 adds the tombstone predicate to the shared pool, capacity and list fragments; every inventoried legacy writer refuses a tombstoned Study. No merge runs on a project before it is enrolled or converted. A project-level switch that stops new merges while keeping unmerge available is the proposed kill switch (PROPOSAL).
  17. Separate from recovery. Merge reversal is never disaster recovery (D2-13, BC). Imports are preserved; cross-project identities never appear in a preview (amendment L.7); ASySD parity and performance thresholds are proposed, not approved (D4-21, T-SI-04).

Conformance tests (drawn from DM §11; rows added to acceptance criteria §7.5 by the acceptance update; budgets are proposed, not approved):

Test Evidence Source
C21-T01 Failure injected at every write of staging and activation leaves either the originals current with no consolidated Study visible, or the consolidated Study current with every input tombstoned and the manifest committed DM-AE01
C21-T02 A Save on an input after the preview makes activation refuse; originals stay current; affected tasks become stale DM-AE02
C21-T03 A save to a tombstoned input is refused with a redirect and the draft kept; "Continue" applies it explicitly on the consolidated Study DM-AE03
C21-T04 Commit is refused while any conflict is open or stale; pending conflicts are listed with their assignee DM-AE04
C21-T05 A delegated reviewer receives a task naming the merge and exact inputs and is recorded as resolver; an admin resolution records the admin DM-AE05
C21-T06 Agreeing compatible answers are prefilled; conflicts are side by side; a resolved Complete passes validation or is refused DM-AE06
C21-T07 A reviewer on two inputs counts once on the consolidated Study × form; different reviewers form a union; no target double count; no automatic result promotion DM-AE07 (FX-PRISMA-07a retired for FX-PRISMA-07ar)
C21-T08 The confirmed effective target is applied through a merge-basis override and recorded in the manifest DM-AE08
C21-T09 Every merge-created record links exact source versions, the merge, the choices, the actor and the time DM-AE09
C21-T10 Tombstoned inputs are absent from pools, allocation, lists, current totals and statistics, and present in history, as-of exports and audit DM-AE10
C21-T11 The current evidence view equals a rebuild after every merge, unmerge and ordinary command; list reads stay within a measured budget DM-AE11
C21-T12 With no post-merge work, an unmerge restores every input's evidence digest-identical to its pre-merge state; the merge record is intact DM-AE12
C21-T13 Every post-merge item needs one choice; the API refuses "both"; moved records carry provenance DM-AE13
C21-T14 An unmerge warns about results whose inputs change, keeps existing versions and replaces only by explicit action DM-AE14
C21-T15 A single reference displays transparently; overrides take precedence; field provenance is complete; references are byte-unchanged DM-AE15
C21-T16 "Distinct report" leaves both Studies current and merges nothing DM-AE16
C21-T17 A blinded merging user sees aliases and can delegate without learning identities; a delegated reviewer sees only their own submissions DM-AE17
C21-T18 After commit each affected reviewer and reconciler gets one notice following the content policy DM-AE18
C21-T19 A manually completed stage stays completed after a merge; automatic stages re-evaluate; pool events carry the merge as cause DM-AE19
C21-T20 Every inventoried legacy writer refuses a tombstoned Study through the floor predicate DM-AE20
C21-T21 Automatic consolidation of a large import stays within a measured budget DM-AE21
C21-T22 PRISMA distinct counting follows merge lineage once T-SI-05 fixes the box mapping DM-AE22 (pending T-SI-05)
C21-T23 An unmerge is refused on a consolidated Study that is an input of a later merge until that merge is reversed DM-AE23
C21-T24 A single input's adjudicated outcome is carried and flagged; differing adjudicated outcomes block commit until resolved or "no adjudication carried" DM-AE24

C22 — External and AI-model screening sources

Implements: E3 (D4-09, D4-10 and D4-14 decided-amended, with the AI expansion, model metadata ownership, source identity and terminology amendment, OS-A20); S1 for model Unsure (OS-A16); superseded wording 14 ("model decision") and 17 (every target-counted contribution mapped to a SyRF reviewer). Owner: L3 Screening profiles with L12 PRISMA and the external and AI screening lane (proposed ID XS1). Freeze: F5 reserves the ScreeningSourcePolicy slot in the profile-version shape (refused if populated before XS1); the contract freezes before XS1 starts. A new flag, default off, with per-project opt-in (PROPOSAL name externalScreeningSources), because it changes authoritative outcomes, spans API and PM and needs a kill switch. Shapes and names are PROPOSALs. Added by the owner session (5 October 2026). The full design is RI §3.11 to §3.14, W7 to W12.

Purpose. A project can import screening decisions made outside SyRF by an AI screening model, an external human reviewer or a non-AI tool, and count them under an explicit, versioned profile policy, with full provenance, no fake human login and no hidden extra votes.

Parties. The project (describes its models), the publisher (pins configuration versions and policies in a profile version), the importer (an authenticated user who uploads and validates a run), the accepter, adjudicators (who resolve model Unsure and ties), and consumers: outcomes and pools (C20), reporting (C12), exports and the codebook (C11), agreement (R5c), statistics (C7).

Logical model (illustrative).

Element Content
AIScreeningModelConfiguration (projectId, configurationId, seq) immutable versions: model name, provider, model version or artifact reference, intended use, label vocabulary and the mapping of each label to Include, Exclude or Unsure, project-supplied thresholds, the training-set context (a description and, where known, the frozen list of training and evaluation Studies with exact human decision versions), default run context, documentation links, and an explicit list of metadata marked "not supplied". The head points to the current version for new references only
ScreeningSourcePolicy Part of the immutable ScreeningProfileVersion: per allowed source, its type (AIScreeningModel, ExternalHumanReviewer, ExternalNonAITool), the exact configuration version (AI) or a source descriptor, the role (ContributingVote or SoleScreener), the scope, the label mapping in force and the Unsure routing
ExternalScreeningRun One delivery: source and policy entry, configuration version, source run ID, SyRF run ID, supersedesRunId, profile version and mapping, importer, imported-at and source timestamps, dataset provenance, file digest, row counts, per-row validation results, state (Previewed, Validated, Accepting (n of N), Accepted, Rejected, Superseded)
ExternalScreeningDecision (projectId, profileId, sourceKey, studyId) with a version sequence: original label, mapped decision, confidence or score and threshold where supplied, the source record identifier and how it resolved to a current Study (including any merge-lineage path), onTrainingInput and onEvaluationInput, explicit missing-metadata markers. Only the latest accepted version is current
Outcome composition On ScreeningOutcome: machineContribution ∈ {None, Contributing, Sole} and externalHumanContribution, derived at commit; finalSource stays ProfileRule (resolution under the policy) or Adjudicated (a human resolution)

Rules.

  1. Terminology (owner decision). Documents and user-facing attribution say "AI-model-generated screening decision" and "AI screening model". "Model decision" is banned. Non-AI external sources keep their real source type.
  2. Source identity (owner decision). The machine source has its own identity, separate from the importing user. It has no login, membership or permission; attributing a decision to it grants nothing. Importer and accepter are recorded separately from the source.
  3. Metadata ownership (owner decision). The project keeps versioned model configurations; anything not supplied is marked; every change creates a new attributable version; profile versions, runs and decisions reference an exact version.
  4. Policy in the profile version. A profile version pins the exact configuration version and its source policy. A policy change is a new profile version through the Q-26 impact process (C4); earlier decisions and outcomes keep the profile version they were accepted under; adding or removing a source, or changing its role or scope, counts as an eligibility and selection-method change and needs a protocol amendment entry (RI-R22, PROPOSAL; D4-05 for the amendment rule).
  5. Roles. A source counts only under its declared role and scope. As a contributing vote, an AI-model-generated decision follows the profile's versioned sufficiency, conflict and Unsure rules with their bounded escalation; there is no hard-coded extra vote. As a sole screener, Include and Exclude become machine-only outcomes.
  6. One current decision per source. Reruns and corrections create new versions of the same source's decision; a source holds at most one current decision per Study and profile, so repeated outputs never become extra independent screeners.
  7. Explicit mapping. Each label maps explicitly to Include, Exclude or Unsure; a row whose label has no mapping is refused at validation. Thresholds are the values the project supplies; SyRF sets no default threshold.
  8. Unsure and human resolution. Under a sole-screener policy a model Unsure is unresolved and enters the profile's adjudication step as an AdjudicationTask with the sole-source AI Unsure trigger; not-excluded availability never makes it a collective Include, and pending adjudication is not an outcome. A human resolution creates a new attributable outcome whose inputs are the exact version of the AI-model-generated decision and any other candidate versions; the imported decision is never changed.
  9. Import validation. Imports are previewed, validated and idempotent by source, source run ID and file digest. Each source record resolves to a current Study with recorded provenance (SyRF ID, DOI, PMID or an importer-confirmed title match); an identifier of a tombstoned original resolves through merge lineage and records the path (C21). Unmatched rows are reported and never create Studies.
  10. Acceptance. Imported decisions affect current outcomes and pool filters only after validated acceptance under the declared policy, and only for Studies and profile versions that are current under the ordinary eligibility, publication and history rules. Acceptance is a resumable operation with one Study-scoped transaction per Study keyed by (run, Study, decision version), so a retry never duplicates and no half-accepted Study exists. Each changed outcome writes pool events with cause ExternalScreeningAccepted and actor kind AIScreeningModel or ExternalSource (C20); affected active reviewers are notified (capture only).
  11. Training-set context. Outputs on a configuration's training or evaluation inputs are flagged on each decision; they are never independent validation of the model and never add the underlying human decisions again; by default they do not count toward sufficiency or agreement (PROPOSAL).
  12. Reporting. Reports, exports and the methods summary keep machine-assisted outcomes distinguishable from exclusively human outcomes through the composition fields; PRISMA manifests show machine contribution per outcome and the machine-assisted share per phase; the methods summary reports model name and version, role, thresholds as supplied, training-set description and Unsure handling. Whether machine-only exclusions belong in box 3 or box 5 is specialist input T-SI-05. An external screening count is refused for records that already have accepted external or AI decisions at that phase (PROPOSAL extension of amendment K rule 6).
  13. Agreement. Human independent, human informed, external human and machine classes stay apart; no metric mixes them without an approved statistical definition (T-SI-02).
  14. Disclosure. A permission-aware page shows model configurations, the profile versions and runs that use them, and each decision's provenance; exports and the codebook expose the same method details, including the configuration and run versions used.
  15. Scope boundaries. Mapped human annotation-answer imports are a separate lane (XA1) and keep D4-14's mapping rule: target credit only when mapped to a SyRF reviewer, Imported candidate provenance, excluded from default independence statistics, never gold automatically. Machine prioritisation stays out of scope. No importer is activated by the owner session; XS1 needs its own brief, gate and flag, and no production pilot starts without its own approval.

Conformance tests (drawn from RI §11; rows added to acceptance criteria §7.5 by the acceptance update):

Test Evidence Source
C22-T01 A copy-deck guard rejects "model decision" in user-facing strings of the XS1 folders; attribution reads "AI-model-generated screening decision" RI-AE20
C22-T02 No account, membership or grant exists for any AI source; authenticating as one is impossible by construction; importer and accepter are stored separately RI-AE21
C22-T03 After a configuration moves to version 2, decisions accepted under version 1 still reference version 1 in the UI, exports and codebook RI-AE22
C22-T04 Changing a source policy creates a new profile version through the Q-26 impact flow; earlier outcomes keep their profile version RI-AE23
C22-T05 Re-uploading the same file returns the existing run and writes nothing; unmatched rows create no Study; tombstoned identifiers resolve through merge lineage with the path recorded RI-AE24
C22-T06 A rerun replaces the source's current decision on each Study; the number of contributing sources per Study is unchanged RI-AE25
C22-T07 Sole-screener fixture: Include and Exclude become machine-only outcomes; Unsure creates an adjudication task and stays pending; the adjudicated outcome lists the imported decision version as input and that decision is unchanged RI-AE26
C22-T08 Contributing-vote fixtures cover the model plus one and two humans under the profile rule, including bounded escalation, with no extra vote RI-AE27
C22-T09 Outputs on training inputs are flagged and excluded from sufficiency and agreement by default RI-AE28
C22-T10 PRISMA manifests, screening exports and the methods summary show machine contribution per outcome and the machine-assisted share per phase RI-AE29
C22-T11 Agreement output keeps human independent, informed, external human and machine classes separate RI-AE30
C22-T12 A validated but unaccepted run changes no outcome and no pool; acceptance writes pool events with cause "accepted external screening decision" RI-AE31
C22-T13 Fault injection during acceptance followed by resume yields exactly one current decision per Study and no duplicate events RI-AE32
C22-T14 The methods summary reports model name and version, role, thresholds as supplied, training-set description and Unsure handling RI-AE36
C22-T15 The model metadata page refuses users without the view capability and shows configuration versions, using profile versions, runs and decision provenance to those with it RI-AE37
C22-T16 An external screening count for records with accepted external or AI decisions at that phase is refused RI-AE11 (refusal part)
C22-T17 A source-policy change without a protocol amendment entry is refused before any write RI-AE15