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¶
- 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).
- 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).
- 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).
- 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).
- The server is authoritative. Every read and command checks scope, permission, admission and blinding. UI hiding is never a control.
- 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):
Annotationsubclasses (bool, int, decimal, string, plus arrays) are mutable and embedded inStudy, with client-supplied stable IDs and aStageIdthat 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. Screeningis 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, theSessionTallysums andScreeningInfo'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,ExtractionInfoandSessionTallyhave no extra-element capture.Entitysubclasses 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
commandIdreturns the original result from the command ledger; a different request digest under the same ID is refused (CommandDigestMismatch); an indeterminate commit returnsOutcomeUnknown, 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.Versioncompare-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:
AnnotationQuestionis embedded in Project and edited in place. Its fields are atAnnotationQuestion.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(autoUpdateapplies 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.autoUpdateis 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_onlycounted 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
policyDerivedrevision 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 (kindPublicationGenerated). For each affected session whose latest explicit version pins an older form version in a category the admin chose to treat:autoUpdatewith 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;requireReansweron an answered question and a new required question underrequireAnswerBeforeCountingre-pin and leave the session incomplete, so a completed session stops qualifying. No version is generated where every changed question isdoNothing, where only the target or a policy changed, undercountEarlierCompletes, 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 tablePROPOSAL, whetherautoUpdategenerates 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
doNothingthe 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 ondraftVersion, 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):
reviewEligibilityPolicyandproportionalStudyAllocationare 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
requestedReviewclaim 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); underCollectiveIncludeRequiredthe 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) andQuestionVersionAnswers(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_onlycounts 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):
ProjectQuestionresolves canonical questions, not onlyProject.AnnotationQuestions; the canonical designer readsQuestionVersionAnswers(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
pinnedStatisticsReadblock (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.jsonhas 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
PATCHunder 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.
ProjectAuthorityEvaluatoris 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
PROPOSALuntil 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:
observedAton a revision and legacyDateTimeCreatedare 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 aRecoveryManifest, 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 (
DateTimeCreatedis 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 andgoldNeedsReReconciliation; 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 carryAuthoredUnder(Verified(v1)orUnknown). - 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_onlyfrom 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
OnlyCompletedwork changes legacy output, so it ships behind a flag. - Owner-session export content: accepted values carry
AcceptedResultVersion.authorityand labels follow it ("Single annotator (accepted automatically)", "Reconciled (one candidate)"); adopted hints are labelled; screening exports adddecisionSourceType,aiModelConfigurationVersion,externalRunId,confidence,thresholdApplied,onTrainingInputand, on outcomes,machineContribution; the codebook lists, for screening columns, the decision source types and the AI model configuration versions used, and per answeransweredUnderVersionandqualificationPolicy(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;
StudyLinkgroups 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 asourceDocumentKeywith its basis onStudyVersion.referenceLinks[]; every snapshot carriesreportIdentityCoverage(Established,Partial,Not established) and, while grouping is deferred, says "one report per Study assumed (identity not verified)" where identity is not established;StudyLinkgrouping 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
StudyEnteredPoolevent (FEAT-011's pool-entry event), written toStudyPoolLedgerwith 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 byfinalSource∈ProfileRule,Adjudicated,MergeResolvedplus the composition fieldsmachineContributionandexternalHumanContribution(mapping: CandidateAgreement →ProfileRule; Reconciled →Adjudicated; Imported →ProfileRuleorAdjudicatedwith composition set, andImportedstays a candidate provenance kind; LegacyUnknown removed with Q-35; Admin → no value unless an outcome override is created; RI §3.13); the outcome gainsresolutionStateand onlyIncludedandExcludedare 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);StudyEnteredPoolis renamedWorkFirstReleasedand written as a C20HistoryEvent, 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 inputT-SI-05and 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
fullTextStatusonly, with human actions and events (amendment M); search documentation fields andsearchRound(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 dropsOtherrecords); I3#33 = #31 + #32; I4#34 = #33 − #7 − #8 − #9(remainder: pending dedup review and check); I5records_after_removal = records_screened + not yet entered screening; I6records_screened = records_excluded + sought + unresolved at title/abstract; I7sought = not_retrieved + assessed + awaiting retrieval or assessment; I8assessed = excluded_with_reasons + included + unresolved at full text; I9Σ reasons = excluded_with_reasons − reason not recorded; I10new_studies = Σ columns includedresolvingStudyLinkgroups once,new_reports ≥ new_studies; I11total = new + previous(D4-11); I12total_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,
ExternalStepLedgerentries,ScreeningOutcomes,StudyLifecycleLedgerandStudyPoolLedgerentries,StudyLinkgroups, alias sets and thePrismaPhaseMappingversion at the report watermark (a hybrid-logical-clock stamp) and stored frozen (PrismaFlowSnapshot). FEAT-024 rows are never a report input. Owner session:StudyPoolLedgerentries readHistoryEventpool and review-start records andWorkFirstReleasedentries (C20); alias sets read Study and merge lineage (C21);StudyLinkgroups are deferred; inputs add acceptedExternalScreeningDecisions, 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 inclusioncapability (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 anextractionMethodrole ∈ {reported,graph-estimated,calculated,author-supplied,unknown} and a series-leveldataSourcenote (table, figure, page);graph-estimatedis 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 underRequireHumanReconciliation(C9); labels followAcceptedResultVersion.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
ValueOrDefaultUnknownwhere 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
Sourcesub-document (type, IDs, stage list, task ID). The server provides the action label, context lines, typed availability and workflow state (aNotificationView). 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.StudyConversationandStudyIssueare 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.
INotificationDisclosurePolicyruns 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 versionedNotificationContentPolicy, 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;
notificationEmaildeclares its dependency onnotificationInbox; 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 (NotificationEmailPreferencesmuted 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.
StudyConversationmoves 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,SessionTallyandStudyBulkUpdateLockgain 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: theSessionTalliesgetter and the claim pipeline merge the canonical summary's per-stage projection, and anIReviewMembershipFactsseam 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 addsstate = Tombstonedto 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.deletionStateand the Study fields of C21 follow the N-1 capture rule. - Ownership as data, enforced on the documents writers write (E49): a
CanonicalScopesmarker on Study and Project, checked in legacy aggregate methods (one document write with theAudit.VersionCAS, with or without a transaction), by a composite registeredIAggregateWriteGuardfor generic and direct writers (composed with the bulk-lock guard and covered by the architecture test), and by project-wide pre-checks.pmCanonicalOwnershipis 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
CanonicalEnrolmentrecord) 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:
firstCanonicalWriteAton 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
UpdateManyon pmStudy with its version-bump status (verified onmaineb93caffa): the question-delete cascade (StudyRepository.cs:1306-1319) and the three inclusion-recalculation updates (StudyRepository.cs:1619-1651), neither of which bumpsAudit.Version, and the bulk-update lock release (MongoBulkStudyUpdateStudyWriter.cs:313-320), which does. Each refuses canonical scopes through theCanonicalScopesmarker 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;
PdfRelativePathand 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 (
freshfrom a materialised read,authoritativefrom a pinned fence read,rebuilding, ornot observed, with itsasOfStamp) 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
VersionedAnnotationFormDataSourceport, 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.VersionCAS, 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,
maxCommitTimeand 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).
StaleBaseis 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 throughOperationId= 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) andGoldChanged(C9); the other new names in the domain model §6.3 arePROPOSALs. 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
stalledstate. - 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) andWorkFirstReleasedare 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.
- Stored types.
StagePoolBaselineMember,StagePoolEntered,StagePoolDeparted,WorkFirstReleased(renamed from the round-2StudyEnteredPoolso that it no longer clashes with stage pool entry; exactly one per Study and stage;releaseKind∈SharedBatchOpened,PersonalBatchGrant,ExplicitAssignment,UnbatchedAvailability,InheritedThroughMerge),ReviewStarted(payloadReviewStartEligibility), and the conversion typesBaselineConverted,ConversionRolledBackandConversionQuarantined. 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. - Entry justification (owner amendment). Every
StagePoolEnteredrecords 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 toReviewStartEligibility. - Departures. Each
StagePoolDepartedcarries 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. - 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.
- 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 aseffectiveAtand the item's stamp asrecordedAt, 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. - Idempotency.
StagePoolEnteredandStagePoolDeparted: (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. - Ordering. By
effectiveAt.hlc, thenstudyId,stageIdandseq. 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. - Current reads never trust history. Admission, selection, counts and readiness read
authoritative current inputs or a cache proven current, never
pmHistoryEventor the tracking marker (an architecture test enforces it). History explains the past and is not a second source of current truth. - Baseline and coverage. Tracking for a new canonical stage starts when it first becomes Active
(
StagePoolEntered, causeStageActivated).StagePoolBaselineMemberis 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 aseffectiveAt, coverageBaselineAtTrackingStartand no invented earlier time or cause; earlier history is labelled (NotRecordedInLegacyfor converted legacy stages). When a Study was eligible and nobody reviewed it, the explanation says "No review is recorded" and invents no cause. - Review start.
ReviewStartEligibilityis 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 theadmissionBasison later versions (C5). - 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
ReviewStartedor completed version routed through the stage; evidence collected elsewhere is "satisfied elsewhere"). Identity modesRecordedIdentityandConsolidatedLineage; which mode a PRISMA box uses is specialist inputT-SI-05. Start with indexed queries; a rebuildable episode projection only if the benchmark needs it, rebuilding identically. - 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. - 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.
- Storage (
PROPOSAL). One append-onlypmHistoryEventcollection, replacing the plannedpmStudyPoolLedger, 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 unapprovedT-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.
- 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). - 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.
- 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.
- 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". - 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). - Targets. Where effective targets differ, the authorised merger confirms the consolidated
effective target, applied through a
StudyTargetOverrideversion with basisMergeConfirmation(mergeId). Qualifying reviewers count once; no target is double counted and no accepted result is promoted automatically. - 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 withStudyConsolidatedand a redirect, and "Continue" applies the kept draft explicitly on the consolidated Study. - 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 recordedStudyVersionand evidence watermark (maintenance-only Study writes never count as a change) or refuse withInputsChangedand mark affected tasksStale; refuse withLockedunder a bulk-update lock; insert the consolidated Study withcurrentEvidence; tombstone each input by CAS and remove its claims; freeze the manifest; writeStudyMergedandStudyTombstonedand 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). - After activation. Notices go once per recipient under the notification content policy and
blinding; inputs depart pools with
STUDY_NOT_CURRENT_MERGEDand the consolidated Study enters the pools whose filters it matches (causeStudyMerged), withWorkFirstReleased(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. - 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.
- Unmerge. A new immutable action on a
Currentconsolidated 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 toCurrentwith 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. - 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
Publicationvalue never changes a Study's fields silently. - 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).
- 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 recordedSystemOnly; anything else is admin-reviewed. - 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.
- 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). - 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.
- 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.
- 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.
- 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.
- 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). - 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.
- 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.
- 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.
- Unsure and human resolution. Under a sole-screener policy a model Unsure is unresolved and enters
the profile's adjudication step as an
AdjudicationTaskwith 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. - 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.
- 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
ExternalScreeningAcceptedand actor kindAIScreeningModelorExternalSource(C20); affected active reviewers are notified (capture only). - 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). - 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 (PROPOSALextension of amendment K rule 6). - Agreement. Human independent, human informed, external human and machine classes stay apart;
no metric mixes them without an approved statistical definition (
T-SI-02). - 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.
- 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,
Importedcandidate 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 |