Skip to content

Source and status inventory

Temporary planning evidence; planning only. This page records what exists on main, what exists only in open PRs, what is documented but not built, and which existing documents conflict with the latest owner decisions.

How it was gathered:

  • Baseline: main = origin/main = remote main = 78c6d097d (3 October 2026, 01:35 UTC), confirmed with git rev-parse and git ls-remote.
  • Re-checked at 2949ca3a7 (03:39 UTC) and c59d9d0f1 (04:47 UTC, the remote main at the last check). The changes since the baseline are FEAT-024 fold slice 6 (#3948, #3949), the FEAT-024 question-answer staleness fix (#3955), an identity registration fix (#3954), auth-migration S30 documents (#3930) and the generated API client. Among them, a refactor of the reservation claim-stage writes keeps claims keyed by stage and investigator. No other code area this plan relies on changed.
  • Read-only sub-agents (Opus) inspected code and documents; their reports are summarised here with file and line references.
  • Load-bearing security and data claims were re-checked directly (marked re-verified). After the adversarial reviews, their new code claims were spot-checked directly too (marked re-verified after review).
  • PR states were read live with gh at about 04:52 BST (03:52 UTC), rechecked at 05:48 BST, and refreshed for the programmes in programme integration at 15:18 BST (main de3e98c59; cluster-gitops origin/main ea972fd6).

Limits: no runtime checks, no database reads, and no reading of runtime flag overrides; flag values in environments come from cluster-gitops values.yaml and may differ live. "UNVERIFIED" marks anything that couldn't be confirmed.

Changes since the earlier research baseline (5861b5844, 2 October): FEAT-024 fold slices 4, 5 and 6 (#3925, #3926, #3948, #3949), batch risk of bias (#3931), auth-migration documents (#3930) and two E2E fixes. No change to questions, sessions, screening, reconciliation, outcomes, exports or permissions.

1. The facts that most constrain the plan

  1. No versioning exists for questions, forms, sessions or answers. Questions are edited in place inside the Project document, and system questions are rebuilt from code on every read (Project.cs:109-110, 223-247). The QM v2 domain exists only on dormant PRs (#2461, #2572–#2575); searching src for AQVersion, StageQuestionSet or SessionVersion finds nothing.
  2. Deleting a question hard-deletes every answer to it and its descendants across the project. The atomicity gap is acknowledged in the code (issue #3088) — ProjectManagementService.cs:201-222, re-verified.
  3. Answers already belong to reviewer + question across stages, but sessions are per stage. A save removes all of the caller's answers to any question in the stage's form, whatever stage they were saved in, then adds the submitted ones (ExtractionInfo.cs:183-194). There is one session per (study, stage, reviewer, reconciliation flag), and only one reconciliation session per stage whoever the reconciler is (ExtractionInfo.cs:202-208). A session is a filtered view (AnnotationSession.cs:149-164). Saving a shared question in stage B silently changes what stage A's session shows (the "little DOMS" investigation).
  4. No drafts, autosave or immutable history on the server. Complete is a status flag; reopening is a save with Incomplete. AF2 keeps drafts in memory only (annotation-form-v2.store.ts:176-179), and the web rules forbid adding per-answer server saves implicitly (src/services/web/CLAUDE.md:343-344). Reviewers can hard-delete their own session and all its answers and outcome rows (ReviewController.cs:86 → ExtractionInfo.DeleteSession).
  5. The server never enforces required answers. Optional is only ever assigned (AnnotationQuestion.cs:55, 227); validation is structural only (AnnotationRelationshipValidator.cs:23-275) — re-verified. Legacy "Completed" sessions were therefore never validated on the server.
  6. Screening is one Include/Exclude decision per reviewer per project, judged against one project-wide threshold, with StageId overwritten on re-screen (ScreeningInfo.cs:79-142, Screening.cs:33-38). ScreeningProfile, screeningOutcomes[], StudyLifecycleStatus, exclusion reasons and screening questions don't exist in code, although the root CLAUDE.md describes them in the present tense.
  7. Reconciliation exists in a legacy form.
  8. A study is ready when completed sessions ≥ SessionCountTarget.
  9. There is one shared reconciliation session per study and stage, editable by anyone with the Reconcile grant.
  10. Reconciled answers are one overwritten set per question, shared across stages.
  11. Counters are two booleans.
  12. The reconcile endpoint maps every session on the study into the response (ReviewController.cs:1586-1628, StudyDto.cs:53-58, re-verified). The agent reports the session DTO includes InvestigatorId (StatsWithIncompleteDto.cs:14-31; not independently re-checked).
  13. Reconciliation reserves nothing (StageReviewService.cs:153, re-verified after review).
  14. There are no gold-snapshot, adjudication or query entities.
  15. The reconciliation UI is read-only. reconcile/:studyId renders every candidate session as read-only cards, two per row (a third wraps). The reconciler has no form on that route, and no navigation links to it (stage-reconcile.component.html:18-46, stage.routes.ts:41-61). AF2's reconcile host is read-only by rule, stage-review and preview hard-fail on reconciliation, and the extraction and Experiment carve-outs on non-review hosts lift only in AF2 Phase 4 PR 9 (src/services/web/CLAUDE.md AF2 section, re-verified after review).
  16. Outcome direction is a per-reviewer answer copied onto rows. Direction, units, average type and error type are system questions under Outcome Assessment, and the client copies them into every outcome row; the export reads some from the row and some from the annotation (AnnotationQuestion.cs:537-661, annotation-form-submission.ts:106-109, OutcomeDataFormatRowWriter.cs:205-211). GreaterIsWorse is a non-nullable bool (OutcomeData.cs:39), and the client defaults are direction false, error type SD, average type mean and zero animals (annotation-form-outcome-topology.ts:40-43, re-verified after review), so stored values can't distinguish an answer from an untouched default. There is no outcome-measure entity and no event-count shape (TimePoint = Time/Average/Error).
  17. Stages are three flat modes plus the D7 closed configuration (ScreeningOnly, AnnotationOnly, Combined with Allow/Stop). They have an Active switch only: no steps, no completion state, no rename or delete (Stage.cs, StageReviewConfiguration.cs). The D7 grouped configuration has a reader and writer floor (#3732) but no migration tool (#3742 is a draft with no files).
  18. The review-eligibility programme is the existing admission authority. It has 14 actions, typed screening/annotation claims, a claim-revocation outbox and guarded settings PUT, all behind the default-off reviewEligibilityPolicy flag. Enabling it requires migrating legacy reservations first (Study.cs:346, re-verified after review). The browser doesn't yet read its eligibility response, and still applies #3551's universal screening-complete veto (S5 audit, #3741). Its flag reaches the API host only (env-mapping.yaml, the services: [api] block). Per session memory, Chris paused the programme on 25 September until the statistics work finishes; the repository does not record the pause (#3746 had activity on 1 October); recheck before F3.
  19. Eligibility decisions and later owner decisions.

    • Eligibility D3a ("no closure/reopening state machine") is superseded for the new stage model by LC1/RX2 (3 October) under the precedence rule.
    • Eligibility D3b ("annotation has no screening prerequisite", pinned by ReviewEligibilityPolicyTests.cs:176) becomes the behaviour of independent steps, with configured dependencies following DP6/DP7.
    • Eligibility D5 concerns excluded work (preserve new-annotation exclusion, keep saved-work resumption, no new direct-access ban). It is consistent with EW1 and the veto and carries over unchanged.

    See §6 and Q-24. 13. Groups are fixed. Only the built-in Administrator group is reachable. Custom groups exist in the domain model (ProjectSecuritySettings.cs:25-42), but no code creates them. The authorization programme gates custom groups on membership schema 1 applied in production (its gate G-D, which this plan calls X-AUTH-SCHEMA; it needs a migration runner WP-M1 that doesn't exist yet, then WP-M2) and plans their administration, including the generalised permissions dialog, as WP11 after WP9 explanations; #2224 is reference material for WP11 (its decision D10). Production is entirely schema 0. Per-member stage grants have no API writer. 14. The ownership-transfer rule is not enforced. ResourceSecurity.json makes ChangeOwner owner-only, but no endpoint uses ProjectChangeOwnerPolicy. PATCH /api/projects/{id} requires only ProjectEditPolicy (Administrator group) and Project.Update calls ChangeProjectOwnership when OwnerId differs (ProjectController.cs:365-390, Project.cs:855-883, ProjectUpdateDto.cs:17) — re-verified. The permission-update endpoints also accept owner-reserved activities (ProjectController.cs:1303-1320, per review C). This contradicts PM1's owner-only transfer (§7). 15. Materialized statistics are dark and narrower than they look. - Production has nothing; staging runs the ProjectScreening family for one pilot project and pins the fold flag on for both hosts (cluster-gitops syrf/environments/staging/{api,project-management}/values.yaml, commit c4412000 of 2 October, read at ea972fd6; the comment says "staging pilot only (Chris, 2026-10-01)" and a project still needs an explicit admin enable; whether the project is in fold mode is unverified). - Fold protocol v4; slices 0–7 merged (slice 7 docs #3962). Gate (b) was a provisional fail on a loaded host; update: it failed on latency in the idle-host rerun (Bramble, 3 October 2026, 22:38–23:01 UTC; zero statistics-caused conflicts; #3510); the soak (#3510, #3952) has not started. Enabling fold mode on the production database is refused in code (commit 89d295734). - Question-answer statistics are keyed by question only. The reserved StageQuestionVersion scope is stage-keyed and never written, so PS1's stage-free usage needs new scope kinds. - "Enough = 2" is hard-coded at three sites: StudyStats.cs:353-355, FEAT-024's AnnotationThresholds.MinimumNumberSessions (an input of the shared configuration digest) and the study-library session filter (StudyRepository.cs:1665, 1712, 1725, #3979). - FEAT-024 explicitly excludes broad agreement statistics and outcome-level statistics. 16. Several counters and claim authorities already coexist: session tallies, slot reservations (one per reviewer per stage, typed claims), reviewer presence, allocation regimes, statistics rows with pending entries, FEAT-024 source-operation receipts, the project answer tally, and bulk-update study locks (ADR-020, Study.cs:242). New work must extend these rather than add another. 17. Exports are current-state only, and deletion is disabled. As-of modes are reserved only in open #2461/#2574 and accepted only for CurrentState. Screening decisions and answers are overwritten in place, so as-of review state can't be rebuilt from current data. Search, import-job and project deletion routes fail closed with a 503 (DeletionLifecycleUnavailableException, SearchController.cs:122, 134, ProjectController.cs:410) until a reversible-deletion scheduler exists; the deletionLifecycle flag only chooses a message. Only service and repository paths still hard-delete, and StudyRepository.cs:1129-1130 says "Search deletion is disabled today" (re-verified after review). An earlier version of this page wrongly said that removing a search hard-deletes its studies. 18. No PRISMA, deduplication, Citation, Publication or lifecycle code exists. SystematicSearch lacks the phase-7 sourceType MUST. The FEAT-011 package is Approved and is the binding specification. 19. Two question editors coexist, and all default entry points lead to the legacy one. The new tabbed editor (Design/Assign/Preview) at admin/questions is guarded only by the design permission; newQuestionManagement just hides its nav link. It saves through the old schema-v0 API, locks answered questions instead of versioning them, has only seven hard-coded categories, and its 17 specs are excluded from CI (#3655). 20. AF2 is merged but off almost everywhere. annotationFormV2 is on in staging only; stageReviewRedesign and stageReviewDockview are off in every environment; production has only ever used AF1. AF2 has no autosave and no "Complete anyway". AF2 eligibility admits only annotation and combined stages, so screening-only steps aren't rendered by AF2. 21. Study's embedded value objects use strict class maps. ScreeningInfo, ExtractionInfo and SessionTally are mapped with AutoMap() and no extra-element tolerance (StudyRepository.cs:3176-3231). By contrast, Entity subclasses carry [BsonExtraElements] (Entity.cs:21) and FEAT-024's pending-statistics maps call SetIgnoreExtraElements(true) (StudyPendingStatisticsClassMaps.cs) (re-verified after review). An older binary reading a document with new fields in those three types throws rather than ignoring them, which is why R0 exists. 22. System-question 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, re-verified after review), so a published form can't pin live system questions. 23. Support impersonation has an edit mode that admits side-effecting review actions under a valid edit context (ImpersonationSideEffectAttribute, re-verified after review). Review data records the effective investigator; the canonical model adds a real-actor field (per review B; not traced end to end). 24. Saved Dockview layouts are per reviewer per capability slot (screening, annotation, combined). The API validates allowed panel keys and one instance of each capability panel (docs/architecture/dockview-layout-migration.md, re-verified after review), so new panels and step kinds need a layout-contract change. 25. Exports can unmask identities regardless of blinding. The export page lets any ExportData holder choose unblinded output ("UNMASK DATA"), independent of stage blinding and candidate isolation (per review C).

  20. Claims exist only when tracking is on, and tracking is off everywhere deployed. Claims, capacity guards and typed admission run only when ActiveReviewerTrackingEnabled && SignalRActive; the flag is unset in production, staging and preview and true in the E2E stack (appsettings.e2etest.json). Reconciliation is excluded at every tracking layer. Enabling tracking is a FEAT-024 durable reviewer-mode transition whose code (AdvanceModeEpochAsync, M15) has no caller. Presence snapshots carry claim holders' identities to every member who can view studies.

2. Implementation inventory by area (main, 78c6d097d)

Re-checked at 2949ca3a7 and c59d9d0f1; only the statistics row changed.

Area Verified on main Gaps against the plan Conflicts with decisions
Questions and editors Embedded Project._annotationQuestions; fields AnnotationQuestion.cs:107-150; conditional parents and filtered options (Target.cs, OptionInfo.cs); lookups; placement rules for new questions; in-place edit; cascade delete; same-project copy; system questions vary by SystemQuestionVersion. New editor: Design/Assign/Preview with locks, same-parent drag only, debug text left in the template. Legacy editor: create/delete only, Bootstrap. Versions, publication, library, import (in #3934 only), profile-owned questions, custom categories, re-parenting, response modes, system-question snapshots FV1–FV3 (no versions); DP4 (unknown categories refused)
Sessions and answers Per-stage sessions; stage-independent answer replacement; structural validation; SessionWriteOwnership (#3671); client-supplied IDs; hard session delete. StudyPdfCorrection (pmStudyPdfCorrection; mongodb-reference.md:103 still says pmStudyCorrection), the three BulkPdfUpload* roots inside ProjectAggregate/, the ADR-020 and M5b operation stores and the FEAT-024 fold are Study writers for R0's inventory Form identity, shared sessions, drafts, immutable versions, required-answer validation, provenance, withdrawal instead of delete SF1–SF3, SL1–SL3, PV1
Stages ReviewMode; D7 configuration types; SessionCountTarget falling back to the project threshold; AllowSelfReconciliation with no writer; workload shares on annotation-only, disabled stages; guarded review-settings endpoints (flagged); 3-step create dialog; settings page with mock study filters and mock stage permissions Steps, dependencies, routing, lifecycle, versioned settings DP6/DP7, PV2, RX2/LC1, SF2 (stage target; #3732 adds a per-stage override)
Screening Project-level method/criteria/keywords; Include/Exclude only; ReviewEligibilityPolicy (14 actions); sufficiency guard for new votes Profiles, eligibility questions, reasons, profile outcomes, derived decisions DP2–DP5, RX1
Reconciliation Legacy readiness, session, overwrite model; reconcile grant (#3565); no editor exclusion: reconciliation consumes no reservations and uses no claim or presence at any layer (StageReviewService.cs:67-70, :153, stage-review-presence-policy.ts:17, per RT-01), and "Next" picks an unclaimed study at random; AF2 reconcile host renders N read-only candidate cards for non-extraction pools Editable reconciliation form and host, task identity, gold snapshots, matching, assignment, queries, blinding policy RE1–RE5, RA1–RA5, GS1, BL1, SF4
Outcomes OutcomeData per (stage, outcome, cohort, experiment, investigator, reconciled); GreaterIsWorse a non-nullable bool; TimePoint (Time/Average/Error); duplicated NumberOfAnimals; AF2 matrix, cell editor, spreadsheet, graph assignment Measures, schemas, event counts, custom fields, versioned direction OC1, ODIR1
Permissions 25 project + 4 stage activities; owner-only ChangeOwner/AssignPermissions/Delete in the catalogue; ChangeOwner unenforced; permission updates accept owner-reserved activities; ProjectAuthorityEvaluator (dark, enforced mode only); working group×activity PermissionsDialogComponent used only for chart visibility; Membership UI is Administrator/Reviewer only; route guard typo project.editMembership (project-admin.routes.ts:36; review C judges it most likely a no-op; UNVERIFIED) Configurable groups, scoped grants UI, delegation envelope, new capabilities PM1, PM2
Statistics (FEAT-024) 10 families; fold protocol v4; slices 0–7, #3955 and #3956 merged; gate (b) failed on latency on an idle host (3 October, #3510); production fold enable refused in code; staging fold flag pinned on for both hosts (cluster-gitops c4412000; "staging pilot only"); positive-proof-only stage evidence (StageReviewStatisticsEvidence.cs:40-124); "enough = 2" inside the configuration digest New families over canonical sources (usage, question-version answers, profile grain); target-aware classification; scoped-rebuild service API PS1–PS3, SF2
Allocation, presence, claims Allocation MVP and regime provenance (#3603) merged, dark; reviewEligibilityPolicy and proportionalStudyAllocation reach the API host only (AP-08); reviewer validation blocked on #3251; typed slot reservations keyed by stage and investigator, created only when tracking is on (activeReviewerTrackingEnabled ∧ signalRActive; with it off no claim is created, saves are unguarded and EnforceAnnotationTarget does nothing, RT-02); ReviewerPresence and ReviewSessionConnection roots, both keyed by stage (presence snapshots name reservation holders, identities included, to every member who can view studies, #3892); tracking off in every deployed environment, on in E2E, and enabling it is a FEAT-024 durable reviewer-mode transition whose code (AdvanceModeEpochAsync, M15) has no caller; reconciliation excluded; maxInProgressSessions effectively on through appsettings (API true, PM false) Per-reviewer membership projection; claim contract v2; reconciliation task editor claim; production claims route; shared-form allocation SF1/SF2 (stage-keyed); RA1 (no editor exclusion)
Batches None on main; #3939 open and conflicting (lazy shared frontier, legacy-keyed completion, PM-only flag block); #3936 plan open Evidence seam; pool-entry-based membership; durable opening FEAT-026 README rejects "arbitrary sequential stage-step model" (DP6) and "a stage closure concept" (LC1/RX2)
Export and history Current-state CSV (long, wide, screening, outcome, bibliographic), streamed to the browser; blinding level option open to any ExportData holder; OnlyCompleted forwarded but unused by writers; export authorization (#3243) Previous versions, as-of, manifests, gold export, export disclosure contract EX1/EX2
PRISMA, dedup, import, deletion RIS import done (FEAT-022); reference-file screening columns call AddScreening; bulk update v2 with study locks (flagged); search/project deletion routes fail closed pending the reversible-deletion scheduler Citation, Publication, source type, retrieval status, pool entry, dedup, report; reversible deletion. FEAT-012 names pmDedupBatch (staging, 7-day TTL) and offers pmDedupAuditLog as the separate-collection option; the plan uses pmDedupAuditLedger PR1-compatible (nothing exists yet)
Setup CreateProjectWizard (basic details → screening criteria → project setup; Living Search/ML disabled); 8-task ProjectSetup checklist (first stage only, legacy links) kept in nav by a 21 September decision Guided replacement, templates, profile templates SET2 (replace the content, keep the nav placement)
Reviewer UI Legacy grid default; redesigned shell flagged; standard workspace and Dockview (flagged, "evaluation only"); equal-weight decision card; AF2 tabs, entity cards, Focus, branch tabs, numbering, action bar, outcome matrix; presence banners only; review preferences and layouts saved server-side Drafts/history UI, needs-updating, Fix, steps strip, screening renderer, compact population context, "Complete anyway" SL1–SL3, SF5, RE2 (reconciliation only)

Design system: Angular/Material/CDK ^22.1.0, NgRx 21.1.1, Dockview 8.2, Handsontable 18. The theme is a hybrid of M2 components and M3 tokens; dark mode needs themeToggle (off). Zoneless switch shipped but is off everywhere; new code must avoid new NgZone call sites.

3. Programme and feature documents

Doc status is the front-matter status. "Impl" uses Verified / Partial / Planned. Unless stated, PRs are authored by chrissena (Chris's account, used by his delivery sessions); delivery owners per lane are named at G0.

Feature / programme IDs Doc status Impl Owning PRs (author) Main conflicts
Question Management FEAT-003 In-Review (Feb) Partial (UI on legacy API) #2387 open FV1–FV3, SF1/SF2
QM v2 implementation Epic #2488 qm-v2-context Approved (Apr) Planned (dormant PRs) #2461 draft; #2572–#2575 SF1/SF2, FV2, ODIR1 (per-row direction)
Annotation versioning FEAT-001 In-Review / design session Approved (Feb) Planned — Per-stage question sets; previous-version-only checks; pendingAnswer drafts; auto-promotion
Annotation Form v2 and stage-review redesign FEAT-002 In-Review (Sep); STATUS stale Verified, default off ~40 merged; #3546, #3543, #3017, #3288 open SF1 (EntityOrder on per-stage session)
Question extensibility ADR-011; ADR-017 (only in #2812) Approved (Sep) Partial (answer labels only) #2812, #2802 open FV1 (interim definitionVersion policy)
Template/bulk import delivery map 2b–2g Planning merged (#2779) Planned #3934, #2781 (both conflicting) DP4 gap, FV1
Library/cross-project sharing QM-10, SHARE-*, D27/D36 Draft Planned — DP4 (copy, not reference)
Answer validation FEAT-017/020/027 Draft/Approved Partial #2986, #2987, #2629 open #2987 "AnnotationProfile" name collision
Category guidance AF2 rev. 2 §6.5 — Verified #3398, #3406, #3453 SF1 (per-stage override)
Reviewer layouts / Dockview contract + migration doc Approved / In-Review Verified, default off #3225, #3230, #3384… Panel model changes need a contract amendment
Stage-review design parity handover 2026-09-21 — Partial #3546 SET2 (nav placement only)
Outcomes, experiments, cohorts — No schema doc Verified (old model) AF2 phase 4 ODIR1, OC1
Classification and entity types — No main doc Planned — TC1 (categories are the legacy types)
Project templates FEAT-014 Draft (2025-12) Planned — TC1, SET2
Setup wizard and checklist FEAT-023 nav In-Review Verified M3 nav PRs SET2
M3 navigation (rail, checklist footer) navigation plan — Verified (September) merged IA changes coordinate with it
Screening profiles, annotations, stage settings, stage filtering FEAT-007/009/010/008 In-Review (Feb) Planned #2621 draft DP4, DP6, DP7
Review eligibility programme S1–S6, D1–D8 In-Review (Sep) Partial, flagged (API host only); paused 25 Sep (memory, not in the repository) Merged #3579, #3646, #3659, #3663, #3691, #3695, #3719, #3732, #3736; open #3746 (conflicting), #3742 (no files), #3741; S4-C and S6b have no PR DP6 (D3b), RX2/LC1 (D3a); D8 unmapped (D3-09)
Reconciliation FEAT-006, D1–D50 In-Review / Draft (Feb) Legacy only #3565 RE4, SF4/RE3, BL1, RE2, GS1 (auto-promotion, $unset)
PRISMA 2020 FEAT-011 Approved (Feb/Mar) Planned #2398 docs PR1-compatible; amendments A–J needed
Deduplication FEAT-012 Approved spec Planned — Tracker uses superseded ImportRecord
Reversible deletion lifecycle ADR-014 (uncommitted worktree .worktrees/bulk-pdf-deletion-lifecycle); deletionLifecycle flag ADR-014 records 12 August product decisions (24-hour grace, then physical deletion with tombstones) Not built; routes fail closed — (owner to confirm) Amendment J and QD1 (identification history); D3-12
PDF acquisition and processing Bulk PDF upload, PDF Agent, Study Management Processing, PDF corrections Various Partial, feature-off #3947 (PDF proposals) and merged work P1 retrieval status
RIS import FEAT-022 Completed Verified #2971, #3004 —
Materialized statistics FEAT-024; ADR-018/019 Approved/In-Review (STATUS stale: slice 7 and fold flag) Partial (slices 0–7 merged, dark; gate (b) failed on latency on an idle host, 3 October, #3510) No FEAT-024 PR open; #3840, #3960, #3845, #3506, #3524, #3510, #3952 open PS1–PS3 gap; fixed two in the digest
Question-answer statistics FEAT-024 family In-Review Partial (bug #3840) #3562 No version dimension
Proportional allocation FEAT-025 In-Review (STATUS stale: #3603 shown pending) Partial (dark; no human acceptance) #3327 (conflicting); #3251, #3252, #3264, #3269, #3321, #3745 open Annotation-only, stage-keyed
Active reviewer tracking ADR-008 (number duplicated) Draft; feature narrative stale (ActiveReviewSession) Verified, off in every deployed environment, on in E2E #2467, #3008, #3014, #3719; #3876 deferred; #2446 open RA1 (reconciliation excluded); SF1/SF2 (stage-keyed)
Progressive batches FEAT-026 (PR only) In-Review (PR) Planned (implementation PR conflicting) #3936, #3939 DP6, RX2 overlap; denominator decision unrecorded
Data export and as-of FEAT-013 Draft Partial #2461, #2574 EX1/EX2
Project groups and #3335 authorization FEAT-005, PGRP-*, gates G-A..G-D, WP9, WP11 Draft / handover plan Partial #2224 open (nurikarakaya; conflicting) PM2; user-guide ownership wording
Application authority transition #3335 M0–M8 Approved (2 Oct) Partial (dark) many merged Single evaluator; enforced mode
Architecture review (Oct 2026) #3961; issues #3972–#3990 Draft (PR only) Phase 0 fixes merged (#3967, #3968, #3970, #3971) #3961 (draft); #3966 parked Persistence (#3985), events (#3973), flags (#3975), MassTransit (#3986), statistics (#3987); D1-02
Feature-flag overhaul P7 per-project targeting Planning Planned — R0 admission is its domain enrolment (PH-14)
Staged search import #2612 Plan (PR, docs only) Planned #2612 (mergeable, since 1 Sep) X-IMPORT for P1/P2
Notification inbox, study attention flags notificationInbox, notificationEmail, studyAttention; reconciliationConversations (#3965) Draft (PR only) Planned on main (code in open PRs; stack E2E never run in CI) #3932 → #3947 stack; #3965 RE4 (stage binding), BL1, VS1 (#3944; addressed in #3965, not yet merged), QY gap
Keyword highlighting FEAT-025 (duplicate ID) In-Review Verified, off merged —
Bulk update with study locks ADR-020, FEAT-016 Approved Partial, flagged merged Every review write must honour locks
Reviewer no-work page redesign #2412 PR only Planned #2412 (conflicting) Wording overlap with lifecycle

The full per-feature notes (front matter, phases, file references) are in the sub-agent reports summarised here; the key document paths are linked from the integrated plan.

4. Open PRs in scope (live, 3 October 2026, about 04:52 BST; rechecked 05:48 BST)

Mergeability as GitHub reported it after recomputing against 2949ca3a7; the 05:48 recheck found no change except #3955 merging. All authored by chrissena except #2224 (nurikarakaya).

PR State Head Notes
#3617 research (this package's worktree) Merged on 3 October 2026 (f5318074d); conflicting at the first reading 0f4c764b2 at the first reading 5 committed files from 24 September at the first reading. The owner ledger, research inputs and this package were committed on the PR #3617 branch and merged to main on 3 October 2026 as a docs-only PR (D1-05, merge commit f5318074d)
#3964 ownership-transfer security fix Merged 20:27 BST (19:27 UTC), merge commit 85e6facf7, after an approving Claude review on head 16788f9 and green checks; worktree and branches removed 16788f9cb Kept by D1-01 (Chris, 3 October); ported #3969's active-member check and tests
#3969 duplicate ownership fix Closed 19:27 UTC, with a comment pointing to #3964 9e4eaf36f Closed after the port (D1-01, decided by Chris on 3 October, carried out)
#3965 private reconciliation conversations Open and ready for review; ten commits pushed (20:35 BST); local e2e journey passed (19:30 BST reading); the tenth commit makes the reconciler-reviewed-study refusal stage-independent 986b1cdc2 Chris's Q-10 changes; stacked on #3947 (base codex/checked-pdf-proposals-and-explicit-administrator-a-r6bdl2) and waits for the stack; restack onto #3944 approved under D1-09 (3 October) if the stack owner agrees
#3546 AF2 tabs/Focus/action bar Open, conflicting b38dffbd3 Staging corrections 4–6
#3543 branch tabs/delete/numbering Open, mergeable (blocked) 09684ba93
#3394 Study fullscreen Open, conflicting, stale (8 Sep) aad2feca6 Superseded by the Focus contract
#3292 panel resizing Open, conflicting, stale (6 Sep) c71501d50 Chris chose Dockview instead
#3017 AF2 virtual scrolling Open, conflicting, stale 72ffc09cb
#3288 AF2 acceptance evidence Draft, conflicting d4fec9cc2
#3939 progressive batches Open, conflicting 62e8101eb 63 files
#3936 batches plan Open, mergeable (blocked) a799b538e
#3934 template import UI Open, conflicting 9d6c596cf Flag annotationQuestionImport
#2781 importer foundation Open, conflicting 2d8b071b0 Network writes disabled
#3932 → #3938 → #3941 → #3942 → #3943 → #3944 → #3945 → #3947 Open, stacked, none merged; #3932 conflicting with main, the rest mergeable into their bases #3932 2ddd96fb0 · #3938 180f0d1bb · #3941 eb72c886d · #3942 75f89b33d · #3943 d75fd81b9 · #3944 59ab32e7b · #3945 25b364da3 · #3947 ae3c6749d Notification inbox, email, digests, reconciliation questions, study issues, PDF proposals; see notifications integration
#3955 QuestionAnswers stale scopes on transactional saves (fixes #3933) Merged 04:47 UTC (c59d9d0f1) 7cad12dc5 FEAT-024; touches the C7/C8 seams
#3956 reviewer screening drift guards (fixes #3937) Merged 05:53 UTC b0c18e033 FEAT-024; follow-up #3960 open
#3962 async point-fold slice 7 (docs, rules, status) Merged 06:13 UTC 5cca5e490 FEAT-024 STATUS still says "in review" and "fold flag off everywhere"
#3961 architecture review findings Draft, mergeable 3db9e5f6d Issues #3972–#3990; D1-02
#2612 staged search import plan Open, mergeable (docs only) 03c4c57aa X-IMPORT
#3746 eligibility S6a Open, conflicting 66ec5a8e0
#3742 eligibility S4-B Draft, 0 files 87c9de59f Migration tooling not started
#3741 eligibility S5 audit Draft 22a5786cf Only source of the G1–G6 gap list
#3327 allocation preview acceptance Open, conflicting, stale 2c1055968
#2224 custom project groups Open, conflicting (22 Sep) fff8385ac Author nurikarakaya; the authorization plan reuses its shape (D10), not the PR
#2412 reviewer no-work page redesign Open, conflicting 3feb4912c Not stage completion
#2387 QM child visualisation and assign tree Open, conflicting c81426c44
#2461 QM v2 R1 umbrella Draft, conflicting 1ca9f5def 738 files
#2572 → #2573 → #2574 → #2575 QM v2 stack Open, dormant since April af5136696 … 098330759 Harvest per Q-08
#2987, #2986, #2629 (mergeable); #2812 (conflicting) Open, dormant since 1 Sep — Schema/profile/response/validation inputs; #2986 harvest into R2a
#2621 profile versioning prototypes Draft, conflicting, dormant 105bdc09e Seven prototypes; its ADR numbers collide with main
#2469 stage overview chart refactor Open, conflicting 2488a1f92 Stage-target chart conflicts with SF2

Opened since the first read, outside this plan's areas: #3958 (integrated PDF viewer fixes) and

3959 (statistics test isolation).

Recently merged and relevant: statistics slices 0–6 (6a #3948 at 02:57 UTC and 6b #3949 at 03:39 UTC on 3 October) and #3955 (04:47 UTC); eligibility S1b, S2-C, S3, S4-A and the claim-revoked event; authorization M5b (#3929, #3921) and the catalogue coverage test (#3882); bulk update v2 and study locks (#3914,

3909); route-owned statistics SignalStores (#3776–#3795); Dockview fixes (#3828, #3734); design

parity (#3544, #3545, #3533, #3542).

5. Feature flags in scope

All default false unless stated. "Staging" and "Prod" are cluster-gitops values.yaml values (runtime overrides not read). Production pilots need a per-flag decision with each owner (Q-25).

Flag Default Hosts Staging Prod E2E stack Gates
newQuestionManagement false web off unset — New editor nav link only
annotationFormV2 false web on unset — AF2 form (whole environment)
stageReviewRedesign false web unset unset — Redesigned review shell
stageReviewDockview false web unset unset — Dockview workspace
integratedPdfViewer false web on unset — Integrated PDF viewer
reviewEligibilityPolicy false API only (PM only through #3939's PR-only block) unset unset — Eligibility code paths
proportionalStudyAllocation false API only unset unset — Allocation (on only in preview pr-3327)
activeReviewerTrackingEnabled false API, PM unset unset true Tracking (with signalRActive, default true); claims and capacity guards exist only when on
maxInProgressSessions true (API appsettings), false (PM), false (preview) API, PM — — — In-progress cap
stagePermissionsConfig false — — — — Mock stage-permissions UI
disableMembership, editProjectMembers false — — — — Membership controls
syrfOwnedApplicationRoles(Enforced), delegatedWorkAdmissionEnforced false — — — — Authority transition
deletionLifecycle false — — — — Message choice only today; gates creation of reversible deletion operations once built
bulkStudyUpdateAtomicApply, batchRiskOfBiasAtomicApply false — — — — Writers to inventory
materializedProjectStatistics* (25) false API, PM 8 on for one pilot project, plus materializedProjectStatisticsFold pinned on (API and PM; "staging pilot only (Chris, 2026-10-01)") and partial fold coverage allowed on the API none — FEAT-024
materializedProjectStatisticsQuestionCounts false — — — — Live question counts and locks
screeningKeywordHighlighting, graph2Data, quantitativeDataExportEnabled false — — quantitative export on in prod web — —
notificationInbox, notificationEmail, studyAttention PR-only API, web — — — Notification stack, environment-wide; accepted email continues after notificationEmail goes off
reconciliationConversations PR-only (#3965) API, web — — — Private conversations; depends on notificationInbox
annotationQuestionImport PR-only — — — — #3934
progressiveReviewBatches PR-only API, PM, web — — — #3939; requires reviewEligibilityPolicy

6. Existing documents that conflict with later owner decisions

These need explicit supersession or amendment in the PR that implements the affected area. They are listed so nobody builds from them by mistake.

Document / code Conflicting statement Superseded by Handling in the plan
Review-eligibility policy D3a (In-Review, 25 Sep) No stage closure or reopening state machine RX2/LC1 (3 Oct), by the precedence rule R3c introduces lifecycle for the new model; eligibility slices still don't. Record the supersession in the R3c ADR.
Eligibility D3b and the AnnotationHasNoScreeningPrerequisite test Annotation never needs a screening decision DP6/DP7 for configured dependencies Keep it as the behaviour of independent steps and of migrated legacy combined stages; add dependency semantics only where a step edge exists (C6, Q-24)
FEAT-008 stage filtering (and its user-guide draft) Pass Included, Conflict forward; annotation pool = collective Included DP7 default (collective Include), DP6 within-stage own Include Amend in R3a
FEAT-010 stage settings "Stages are unordered" (D30) DP7 dependent stages Amend in R3a
FEAT-026 batches README (PR) "No arbitrary sequential stage-step model" DP6 steps Join at F3 with the batch owner
FEAT-006 reconciliation (README, design decisions, data-model migration, AF2 README) Per-stage pools; "Annotator A vs B"; global anonymised-candidate invariant; answer every required question; single-annotator auto-promotion; rollback by $unset (D18) RE4, SF4/RE3, BL1, RE2, GS1; Q-29; canonical-aware rollback Amend in R4a
FEAT-009 screening annotations Separate screening and extraction reconciliation workflows; per-field choice RE4, RE2, RX1 Amend in R3b/R4p
QM v2 / annotation versioning Per-stage question-set versions; checks against the previous version only; activation on stage enable; dataType versioned (D008) vs fixed (D38); one mutable pendingAnswer draft; gold as "latest version on the reconciliation annotation"; migration step 6 auto-promotion FV1–FV3, SF1, SL1, GS1, Q-29 Contract C4/C5 decide; harvest per Q-08
FEAT-011 PRISMA (Approved) Platform-wide MIG-11/MIG-12 backfill; ScreeningOutcome with one stageId and no legacy authority; $unset rollbacks; "Delete Study removes its Citations" Per-project adoption; per-profile outcome; canonical-aware rollback; reversible deletion Amendments G–J (Q-06a) through the FEAT-011 change policy
QM v2 PR-A OutcomeDataStateSnapshot GreaterIsWorse per row ODIR1 C14
#2621 ADR-013 Rationale library shared across profiles DP4 Reference only
#2987 ADR-016 "AnnotationProfile" bound to a stage SF1; profile naming clash C4 naming; disposition at G0
GroupedReviewConfiguration (#3732) Per-stage SessionCountTargetOverride SF2 Legacy-only; canonical stages take the form target, with an adapter for old readers (C7)
Category guidance per-stage override Stage-owned guidance SF1 (if it counts as form content) Proposal A-15: keep as stage presentation text, never evidence
Live question locks (#3572–#3594) Answered questions locked; additions only warned FV1 Canonical forms version instead of locking; legacy keeps locks
User guide members-groups.md Administrators can assign a new owner PM1/PM2 Fix with the ownership enforcement follow-up
Root CLAUDE.md domain model Describes versioning, profiles and screeningOutcomes[] as current — (accuracy) Docs follow-up
FEAT-026 batches README (PR) "Do not add a stage closure concept"; ConfigureProgressiveBatches requires a disabled stage LC1/RX2 (3 Oct) R3c's Completed/Reopen lifecycle replaces "disable the stage before changing batches" for canonical stages
FEAT-008 Filter Set model (JSON rules, same-profile $elemMatch simplifier) Undispositioned DP6/DP7 routes Decide at F3 whether the Filter Set schema is the route representation; keep the simplifier as a correctness rule for screeningOutcomes[] filters
docs/features/signalr-active-reviewer-tracking.md narrative (:102-160) Describes ActiveReviewSession The delivered SlotReservation and presence contract Presence owner's docs PR before F1a (T1)
ADR-014 (uncommitted) Physical deletion of Project, Search and Study after a 24-hour grace period Amendment J, QD1 D3-12; X-DEL

7. Observed defects and risks outside this plan's scope

Reported, not fixed (scope discipline). Each should become a follow-up issue Chris can triage.

Finding Evidence Severity (proposed)
Project administrators can transfer ownership through PATCH /api/projects/{id}; the owner-only ChangeOwner rule is never checked. The permission-update endpoints also accept owner-reserved activities. ProjectController.cs:365-390, 1303-1320; Project.cs:855-883; ResourceSecurity.json ChangeOwner; no use of ProjectChangeOwnerPolicy (re-verified; the permission-update part per review C) High (authorization); Chris approved the fix on 3 October: PR #3964, merged on 3 October (85e6facf7)
Question deletion destroys every answer non-atomically ProjectManagementService.cs:201-222; #3088 High (data loss), known. Under the new versioning a published question can never be permanently deleted (QD1, Chris, 3 October); legacy projects keep today's deletion until adopted
Reconciliation responses include every session on the study across stages; reviewer identities likely included ReviewController.cs:1586-1628; StudyDto.cs:53-58; agent: StatsWithIncompleteDto.cs:14-31 Medium (privacy); current UI shows no names
Export page lets any ExportData holder unmask identities regardless of stage blinding Review C: blinding-option-group.component.html:6-24; ResourceSecurity.json ExportData Medium (privacy)
Membership route guard checks project.editMembership (typo) project-admin.routes.ts:36; authorization WP1d Low to medium (UI guard only; likely a no-op; server checks EditMemberships)
Required answers are not enforced on the server AnnotationQuestion.cs:55, 227 Medium (relies on client)
Debug text "Focused question" ships in the new Design tab design.component.html:14 Low
The export option "completed sessions only" is forwarded but never applied by the writers, so exports can include incomplete work WriterConfig.cs:46-60; screening research §1.5 Medium (export correctness)
COMPARISON.md line 107 says Review Prototype v4 is absent; it exists in handover/2026-09-21-stage-review-design/design_handoff_stage_review_page/ Prototype asset search Low (documentation)
Stale status documents: AF2 STATUS, FEAT-024 STATUS, allocation STATUS, the catalogue, root CLAUDE.md domain model Theme A/B reports Low
Duplicate identifiers: FEAT-025 (allocation and keyword highlighting), ADR-008 (two documents); every ADR number in open QM/annotation PRs collides with main (next free: ADR-021) Theme A/B reports Low (process)
Broken references: .planning/REQUIREMENTS.md, docs/features/annotation-management-reconciliation/… Theme A/B reports Low
The owner decision ledger, later research and this package are committed only on the PR #3617 branch (latest planning commit aac4debcd), not yet on main git ls-files on the PR #3617 branch; aac4debcd is not an ancestor of origin/main Medium (authority at risk until merged to main; resolved: PR #3617 merged to main on 3 October 2026, f5318074d)
Production has no claims or capacity guards because tracking is off everywhere; the over-allocation report #2446 remains open FeatureFlags.cs:35-36; cluster-gitops values; #2446 Medium (capacity correctness)
Reconciliation has no editor exclusion: two reconcilers can edit one study StageReviewService.cs:67-70, 153 Medium (data correctness)
Presence snapshots name claim holders to every member who can view studies, whatever the blinding StudyReviewPresenceSnapshot.cs:86-96 (per review RT); #3892 Medium (privacy; dark today)
reviewEligibilityPolicy and proportionalStudyAllocation reach the API host only, while Core code reading them runs in both hosts env-mapping.yaml services: [api] block Medium (split brain on enablement)
The allocation flag is read twice per request (runtime value in the controller, process value in admission) ReviewController.cs:500, 626, 753, 790, 1173, 1443, 1609; StudyRepository.ActivityReservations.cs:19-21 (per review AP) Low (latent; real once overrides work)
The question-delete cascade and the inclusion recalculation change pmStudy without bumping Audit.Version StudyRepository.cs:1306-1319, 1620-1650 Medium (CAS cannot see them; #3985)
Stale status documents: allocation STATUS (#3603), FEAT-024 STATUS (slice 7, staging fold flag) proportional-study-allocation/STATUS.md:71; materialized-project-statistics/STATUS.md:372-386 Low

8. Prototype and design assets

See the UI coverage comparison, which records every asset found and not found.

9. Notification infrastructure

See notifications integration.

10. Earlier-year documents and their disposition (PROPOSAL)

Review A listed earlier documents the first draft didn't reference. Status and dates from their front matter.

Document Status, date Disposition
docs/planning/screening-step-dependency-options.md (PR3617 worktree) Draft, 24 Sep Input to Q-15: its Modes B and C are now presented alongside the hybrid
docs/planning/active-reviewer-tracking-overhaul.md Approved, 10 Apr Background for C7 claims (E18); implemented behind activeReviewerTrackingEnabled
docs/planning/review-access-state-overhaul.md Draft, 17 Apr Background for C6 admission; superseded in scope by the eligibility programme; read before F3
docs/planning/session-capacity-suspended-sessions-handover.md Draft, 15 Apr Background for capacity and suspended-session behaviour in C7 (E6, E18); read before F1a
docs/planning/session-copy-review.md Draft, 17 Apr Input to the terminology and copy contract (C17)
docs/planning/data-export-analysis.md Draft, 11 Mar Input to C11 export modes and the OnlyCompleted fix
docs/planning/stage-review-layouts/contract.md Approved (layout contract) Binding for C17's layout amendment