Skip to content

Harvest map: existing question-management work and dormant PRs

Status on 5 October 2026. This is a temporary planning document. Feature implementation is on hold (Chris, 5 October 2026) and G0 is not approved. Nothing has been ported, rebased, merged or closed. This map is planning input for the release briefs: no harvest and no PR closure is authorised by it, and every open PR it covers stays open and untouched.

1. Summary in plain English

What exists. Thirteen open PRs hold earlier work on question management and its neighbours:

  • the dormant Question Management v2 (QM v2) stack: #2572 (domain), #2573 (services), #2574 (migration and API) and #2575 (web), with the #2461 umbrella they were split from;
  • 2224, custom project groups, by nurikarakaya, who has left;

  • 3934 and #2781, question template import (#3934 is Chris's recent work, frozen by the hold);

  • 2387, child-question checks and an assign tree for the current new editor;

  • 2986, #2987, #2629 and #2812, answer validation and the schema, profile and response-mode

    designs.

Overall verdict. The plan does not start from scratch, but almost nothing ports as is. The QM v2 stack was built for a model the owner session has replaced. Its ideas, test cases and several algorithms are worth keeping. Its storage shapes, drafts, stage-keyed publishing and migration are not. #3934 is the exception: most of it carries into R1a nearly unchanged.

What M0 and the later releases reuse.

  • M0 writes the harvest-and-avoid record into its report (AC-M0-04), so each adapted piece lands in the brief of the release that will build it (T-RD-10).
  • F1a takes the typed answer payload, the legacy question-shape mapping, the system-question definitions as a global seed, the provenance value objects, #2986's shared fixtures and error codes, and #2812's response-mode contract.
  • R1a takes #3934's import reader, plan, controller and transactional receipt, #2781's golden fixture and #2387's child-validity rule.
  • R1b and R1c take #2224's API shape, domain rules and tests, rebuilt on membership schema 1.
  • R2a, F2 and R2c take the composition validators re-keyed to option IDs, the form-version pin guards, the save-conflict contract, the publication planner's shape, the impact counts and digest, and the reviewer's post-publication alert.
  • Conversion takes PR-C's plan builder, review-state extraction, parity checker and legacy-shaped projection, all retargeted to the new records.

What is avoided, and why.

  • PR-C's migration erases the embedded legacy data from pmStudy, and its rollback is a lossy hand-back to the legacy model (H-MIG-05, H-MIG-08). This directly contradicts BC-R27, BC-R29, C16 and AC-M0-04. Neither piece is carried.
  • Per-stage question sets, stage transitions and the review and export locks: under the stage study filter a stage owns no evidence, target or session.
  • Single mutable drafts: the owner asked for collaborative drafts with an audit trail.
  • Publish transitions that clear answers or copy status, and mapping by value: RD-R21 and RD-R23 forbid both.
  • Version arrays embedded in documents, per-project copies of system questions, #2224's schema-0 groups and its default that lets administrators assign permissions, and #2781's production uploader.
  • Work that main has since done another way: the AF2 scaffold, active-reviewer presence, the ADR-009 extraction and the #2467 copies inside PR-C.

Counts. The five audits hold 131 entries: 6 Reuse, 41 Adapt, 35 Reference only and 49 Avoid. Five of them (three Reuse, two Reference only) sit outside this programme. The ported effort is roughly 50 to 123 working days, about 95 days at a central estimate (§9).

When. Harvesting is planned work. It waits for G0 and the hold lift, and each port happens in its release's slice under that release's approved brief. The PRs stay open until their harvest is done. Closing any of them is a later decision for Chris (G0-D4 to G0-D7, §8.2).

2. Authority and boundaries

  • Q-08 (Chris, 3 October 2026). Harvest the dormant QM v2 stack (#2572 to #2575, with the #2461 umbrella) rather than revive it: audit it against the new contracts, port what fits into small new PRs and close the stack once harvested. AC-M0-04 makes the harvest-and-avoid table part of M0.
  • Q-09 (Chris, 3 October 2026). Harvest #2224's API shape and tests into R1c, then close it with a note crediting its author. AC-R1c-12 records both.
  • The hold. Feature implementation is on hold (Chris, 5 October 2026). The PR dispositions in the G0 dossier are not authorised: G0-D4 (QM v2), G0-D5 (#2224), G0-D6 (#2986) and G0-D7 (#2987, #2629, #2812). No G0 item yet covers closing #3934, #2781 or #2387 (§10). The rollout plan §11 lists PR closure among the actions that never happen without separate approval.
  • This map is planning input. Each port is a slice of the release that owns it. It is built only under that release's approved brief, after its freeze gate, with G0 approved and the hold lifted (D1-04). Every port is a fresh PR from main; no stack branch is rebased, merged or cherry-picked. A verdict here is a recommendation that a brief may overturn with a recorded reason.
  • Relation to the versioning model. Versioning model §12.6 was the only harvest table before this map. It covers versioning alone and predates the owner session. Where the two differ, this map applies; §7.2 notes each row.

3. Sources

Five read-only audits compared these heads with the nine specifications on 5 October 2026, against main at 7673ed0d3. Nothing was checked out, fetched, built, committed or commented. They are kept verbatim in reviews/harvest-2026-10-05/: audit A (#2572, #2461), audit B (#2573, #2986,

2987, #2629, #2812), audit C

(#2574), audit D (#2575,

2387) and audit E

(#2224, #3934, #2781). The table's states and sizes were read with gh pr view on the same day. Titles are as on GitHub, with dashes normalised to colons.

PR Title Head Base State Size Last updated
#2461 feat(qm): Question Management v2: R1 domain + API + web scaffolds (WIP) 1ca9f5def main Open, draft, conflicting; do-not-merge umbrella 738 files (+70,509/−9,289) against today's main; 437 changed files against its own merge base 22 Sep 2026 on GitHub; commits 20 Mar to 24 Apr
#2572 feat(qm): Question Management v2: Domain foundation (PR-A of 5) af5136696 main Open, conflicting 67 files (+10,283/−184), none generated 1 Sep on GitHub; last commit 26 Apr
#2573 feat(qm): Admin decision framework domain services (PR-B of 5) 271290115 feat/qm-v2-a-domain Open, clean against its stacked base 8 files (+1,694/−13) 17 Apr
#2574 feat(qm): Migration, ADR-009 cutover, and API (PR-C of 5) 1b93cbbc4 feat/qm-v2-b-admin-services Open, mergeable (unstable) against its stacked base 604 files (+34,231/−3,992); own QM work 138 files plus edits in 24 mixed files (+16,966) 24 Apr
#2575 feat(qm): Web scaffolds + docs (PR-D of 5) 098330759 feat/qm-v2-c-migration-cutover Open, mergeable (unstable) against its stacked base 544 files (+44,007/−7,385); own work 158 non-generated files (about +30.5k) 24 Apr
#2224 implement custom project groups feature (author nurikarakaya) fff8385ac main Open, conflicting 47 files (+4,850/−543); about 1,900 lines of real logic 22 Sep on GitHub; last main merge 5 May
#3934 feat(annotation): implement question template import through the UI 9d6c596cf main Open, conflicting in generated files only 42 files (+6,192/−20); about 1,800 lines of real logic 2 Oct
#2781 feat(importer): add guarded annotation question import foundation 2d8b071b0 main Open, conflicting 19 files (+10,044/−5), Python tooling 1 Sep
#2387 feat: QM child question visualization and assign tree improvements c81426c44 main Open, conflicting; CI red on the head 46 files (+3,819/−1,127) 1 Sep on GitHub; feature commit 10 Mar
#2986 fix(annotation): validate current-schema answers before persistence 1c6799b00 main Open, mergeable, blocked by review rules 8 files (+1,306) 1 Sep
#2987 docs(annotation): define schema and profile architecture boundaries efd4b96ba main Open, mergeable, blocked 1 file (+258) 1 Sep
#2629 docs(annotation): scope FEAT-027 annotation validation architecture d761ca442 main Open, mergeable, blocked 1 file (+320) 1 Sep
#2812 feat(annotation): define response-mode gate contract 1c3869224 main Open, conflicting 39 files (+1,112/−162), 12 of them generated 1 Sep on GitHub; last commits 27 Aug

Path abbreviations in the evidence column. PMC/ = src/libs/project-management/SyRF.ProjectManagement.Core/ (audit A's Core/); QV/ = PMC/Model/QuestionVersioning/; PMA/, PMD/ and PMT/ = the Application, Mongo.Data and Core.Tests projects beside it; API/ = src/services/api/SyRF.API.Endpoint/; QMV2/ = src/services/web/src/app/project/project-admin/question-management-v2/; QMS/ = src/services/web/src/app/core/state/question-management-v2/; AF2/ = src/services/web/src/app/shared/annotation/annotation-form-v2/; QM/ = src/services/web/src/app/project/project-admin/question-management/. Short SHAs follow the audits; @7673ed0 is main.

4. Per-PR verdicts

4.1 #2461, the QM v2 umbrella

  • Holds. The original combined QM v2 R1: domain, API and web scaffolds, 309 commits from 20 March to 24 April 2026. Against its merge base de8e312ad it changes 437 files plus 2 deletions (+77,083/−5,462).
  • State and drift. A draft marked do-not-merge, conflicting with main. A blob-by-blob comparison found 419 of the 437 paths byte-identical to a stack tip or main. The other 18 are infrastructure drift, five planning-archive files and three older copies. Its domain code is at PR-A's squash level, without any of PR-A's later fixes. Its planning decisions (D001 to D012) and knowledge (K001 to K019) are on main in docs/planning/qm-v2-context/.
  • Disposition. Reference then close, with the stack. Nothing is harvested (H-DOM-25, H-DOM-26).
  • Closure-note draft (not to be posted while the hold lasts; posting it needs G0-D4):

This umbrella was split into #2572 to #2575. Every changed file is byte-identical to a file in that stack or on main, or is an older copy (harvest map H-DOM-25 and H-DOM-26). Its planning context is preserved on main in docs/planning/qm-v2-context/. Nothing further is harvested, and it closes with the stack.

4.2 #2572, QM v2 PR-A (domain foundation)

  • Holds. 67 files and no generated code, API, web or migration. The question-versioning types, extracted Annotation, AnnotationSession and OutcomeData aggregates, services and validators, 169 tests, and ADR-010 to ADR-012 drafts. Nothing is wired to an endpoint.
  • State and drift. Conflicting with main: 14 conflict hunks in 6 files and 3 modify-or-delete conflicts, from a merge base of 25 April. After its squash 36190433d, PR-A's tip has 37 of its own non-merge commits plus 7 merges of main; B, C and D never absorbed them (§8.3). ADR numbers 010 to 012 are all taken on main. Git flags none of three semantic conflicts with main: #2635's duplicate-annotation-ID guard, #2648's nested Study parents and #2651's anchor split.
  • Disposition. Harvest then close. 9 Adapt, 8 Reference only, 7 Avoid; nothing ports as is. (Audit A's other two Avoid entries, H-DOM-25 and H-DOM-26, are #2461's.)
  • Closure-note draft (not to be posted while the hold lasts; posting it needs G0-D4):

Harvested under Q-08 into the October 2026 integrated review plan (harvest map H-DOM-01 to H-DOM-24). Ported in adapted form: the typed answer payload and its shape check, the legacy question-shape mapping, the system-question definitions as a global seed, the form-version pin guards, the composition rules and rule codes, the legacy-write guard pattern, and the provenance and version-reference value objects (tracker rows T-RD-01, T-RD-02, T-RD-04, T-BC-01 and T-BC-06). Not carried: the extracted aggregates with embedded version arrays, per-stage question sets, single mutable drafts, publish transitions that clear answers or copy status, and rollback to the embedded model. ADR-010 to ADR-012 stay reference only; their numbers are taken on main.

4.3 #2573, QM v2 PR-B (admin decision services)

  • Holds. One commit on PR-A's squash, 8 files: an impact service with a fingerprint, a session transition planner, a leased stage-transition job, typed exceptions and 13 tests. No tests cover the job.
  • State and drift. Clean against its stacked base. Unlike C and D, it never merged main. None of its classes exist on main, and it inherits PR-A's conflict.
  • Disposition. Harvest then close. 4 Adapt, 4 Reference only, 5 Avoid. Its core idea, one attributable session version per affected session per publication, returned with the owner's D2-01 reversal; its stage-keyed job and locks did not.
  • Closure-note draft (not to be posted while the hold lasts; posting it needs G0-D4):

Harvested into the integrated review plan (harvest map H-SVC-01 to H-SVC-13). The core idea, that a publication writes one attributable session version per affected session combining every question's treatment, returned with the owner session's D2-01 reversal. It is specified in RD §3.15 and in C4 and C5 as PublicationGenerated, and the impact counts and fingerprint inform the R2c preview and its digest (T-RD-04, T-RD-05). The stage-keyed job, the review and export locks, value-based mapping, answer clearing and replacement across questions are not carried: stages own no evidence, and publication uses the shared operation family.

4.4 #2574, QM v2 PR-C (migration, cutover and API)

  • Holds. 604 files on GitHub, but C's own question-management work is 138 files plus edits in 24 mixed files (+16,966 lines: 8,813 source, 8,153 tests). It covers migration, cutover readers and statistics, migrated review writes, a 17-endpoint API and export modes. It also embeds 73 files derived from #2467 (not 75) and 22 of #2543's files.
  • State and drift. Mergeable only against its stacked base. Against main a trial merge gives 545 conflict blocks in 61 files plus 29 files added on both sides, and 103 of its 225 own files have changed on main. #2467 merged on 30 August and #2543 on 27 April, by other routes.
  • Headline. Its migration clears the embedded annotations, sessions and outcome data from each Study and saves the Study by full replace, so the legacy originals in pmStudy are erased (C-D05). Its rollback rebuilds legacy records from the extracted ones, losing fields and flattening any work saved after migration into the legacy model (C-D07). Both contradict BC-R27, BC-R29, C16 and AC-M0-04.
  • Disposition. Harvest then close. 8 Adapt, 3 Reference only, 11 Avoid.
  • Closure-note draft (not to be posted while the hold lasts; posting it needs G0-D4):

Harvested into the October 2026 plan (harvest map H-MIG-01 to H-MIG-09 and H-API-01 to H-API-13). The conversion planner, review-state extraction, parity checker, canonical-to-legacy projection and export mode reservation carry forward as adapted designs and test cases, into the baseline-conversion rows T-BC-01, T-BC-03, T-BC-05 and T-BC-06, the R2a, F2 and R2c rows T-RD-02, T-RD-04 and T-RD-05, and the export rows T-RI-08 and T-RI-12. The erasure of embedded state, the reconstructive rollback, per-project system-question copies, the stage-publish transaction and stage transitions are deliberately not carried. The embedded #2467 and #2543 files are superseded by those PRs' own merges into main.

4.5 #2575, QM v2 PR-D (web scaffolds and docs)

  • Holds. 544 files on GitHub; D's own commit has 158 non-generated files (about +30.5k lines), of which about 6.7k are designer code and tests. The rest is an early AF2 scaffold, presence web code, docs and a prototype. Nothing was wired to production.
  • State and drift. Mergeable only against its stacked base. Against main it conflicts in substance:
  • main has its own AF2 at the same path, lifted from this PR;
  • presence is already on main;
  • its ADR numbers collide;
  • it reuses the newQuestionManagement flag and path for a different editor;
  • it targets Angular 21, where main runs 22.1.

Correction: main is not zoneless by default. Change detection is chosen at bootstrap, the zonelessChangeDetection flag defaults to false and no environment sets it. Guard specs still enforce zoneless-safe code, so any ported component must pass them. - Disposition. Harvest then close. 2 Adapt, 9 Reference only, 9 Avoid. - Closure-note draft (not to be posted while the hold lasts; posting it needs G0-D4):

Harvested into the October 2026 plan, not merged: the reviewer's post-publication alert, as input to the R2c in-form alerts (T-RD-05); the publish base-version and impact-fingerprint check, as the R2c preview-digest recheck; and the UI specification, publishing UX and prototype, as design references for designer history with a diff (AC-R2c-27) and the keyboard model (AC-R1a-12). The AF2 scaffold already lives on main (74dffd658), and the active-reviewer web code merged by another route. The per-stage Assign and publish model, the root store and the properties panel are superseded by the owner-session specifications, and so are the April release docs. The defects found are recorded in the harvest map so they are not reintroduced: the wizard's injector error, the no-op undo, the autosave that wipes options and the discarded admin decisions.

4.6 #2986, current-schema answer validation (G0-D6)

  • Holds. 8 files: a conformance validator (419 lines), a ProblemDetails model, a malformed lookup-ID rule, 15 tests and one 11-case fixture run by .NET, AF1 and AF2.
  • State and drift. Mergeable, blocked by review rules; none of its files changed on main. It validates no write today: nothing outside its tests calls the validator (V-D1), and its own checklist leaves the integration unticked. The blocker it waited for, #2467, merged on 30 August.
  • Disposition. Depends on G0-D6. The dossier's premise, "it fixes today's legacy writes", is false until it is wired. Recommended: confirm the deviation with a corrected rationale (§10, item 1), keep it open outside this programme, and harvest its fixtures and rule codes into E23 and the conversion inventory either way (H-VAL-02 to H-VAL-04).
  • Closure-note drafts (not to be posted while the hold lasts):

If G0-D6 is confirmed: stays open outside the programme as the legacy-write integrity fix, to be finished by wiring both submission paths. Its fixture corpus and rule codes are harvested into E23 and the T-BC-01 inventory (harvest map H-VAL-02 to H-VAL-04).

If G0-D6 is declined: closed after harvesting the same items into T-RD-01, T-RD-02 and T-BC-01. Legacy writes stay unvalidated until R7.

4.7 #2987, #2629 and #2812, the schema, profile and response-mode designs (G0-D7)

  • Holds. #2987 is one ADR (258 lines) separating schema from profile, with the five semantic categories of a response. #2629 is one draft feature doc (320 lines) scoping FEAT-027. #2812 has 27 authored files: ADR-017, an extensibility-doc rewrite and inert flag plumbing, plus 12 generated files.
  • State and drift. #2987 and #2629 are mergeable but blocked; #2812 is conflicting, with 28 of its 39 paths changed on main. ADR-016 and ADR-017 are taken on main, and #2629's planned "ADR-011 Project Template" collides with main's ADR-011. #2987 retires #2629's runtime design.
  • Disposition. Harvest into the F1a C4 draft (and the F-O C14 ADR for #2812's units and metadata types), then close each.
  • Closure-note drafts (not to be posted while the hold lasts; posting them needs G0-D7):

#2987. Harvested into the F1a C4 draft: server authority, the five semantic categories, the ban on LatestVersion and the lifecycle (harvest map H-VAL-07, H-VAL-08). The schema and profile split and the per-stage binding are superseded by question and form versions. ADR-016 is taken on main; the content lands in a programme ADR numbered from 030 to 069.

#2629. Superseded by #2987 and #2986 and by E23's shared-fixture applicability specification. Its problem statements are kept as H-VAL-10.

#2812. The response-mode wire contract is harvested into C4 and E37, with metadata types and units into C14 (H-VAL-12, H-VAL-13). The schema-v0 activation path, the per-stage lock and the three-service flag are not carried: response modes are canonical-only, and R7 retires legacy writers. The fail-closed flag parsing is proposed as a separate small fix (H-VAL-15). ADR-017 is taken on main.

4.8 #2224, custom project groups (G0-D5)

  • Holds. Work by nurikarakaya from December 2025 to January 2026: about 300 backend and 1,600 frontend lines of real logic. It has group create and delete endpoints, domain rules with a cascading delete, schema-0 persistence, a default that lets Administrators assign permissions, a group dialog, members-page components and about 1,400 lines of .NET tests.
  • State and drift. Conflicting; 25 of its 47 files changed on both sides since 4 May. Bots reviewed it; no person did. Nothing on main creates a custom group yet.
  • Disposition. Harvest into R1c (T-AC-10), with two inputs to the R1b page (T-AC-11), then close (T-AC-12). The schema-0 persistence and the permission default are avoided.
  • Closure-note draft (not to be posted while the hold lasts; posting it needs G0-D5):

Thank you, @nurikarakaya, for the custom project groups work (December 2025 to January 2026). Its API shape (POST and DELETE api/projects/{projectId}/groups under EditMemberships), its create-and-cascade-delete rules and its domain, controller and permission-isolation tests are carried into R1c of the integrated review plan, delivered with the authorization programme's WP11 once memberships are on schema 1 (harvest map H-GRP-01, H-GRP-02 and H-GRP-09 to H-GRP-11). The schema-0 persistence path and the AssignPermissions default are not carried, because memberships migrate to schema 1 first and AssignPermissions stays owner-reserved. The members-page components inform the new Members & groups design.

4.9 #3934 and #2781, question template import

  • Holds. #3934 has a bounded CSV and XLSX reader, a canonical plan with a legacy adapter, a transactional apply with a receipt and attempt history, a flagged controller, an Angular dialog and 45 API tests. #2781 is Python tooling with a reference parser, a synthetic golden fixture and a production uploader that fails closed.
  • State and drift. #3934 is recent work that Chris started on 2 October; the hold froze it, so it is not dormant. Its conflicts are generated files only, and its one red .NET test is in a project it does not touch. #2781 is 686 commits behind main. The uploader that ran in August lives outside the repository.
  • Disposition. #3934: harvest by re-cutting it on main and splitting it into R1a-3 and R1a-4 (T-RD-11), then close it as superseded by those PRs. #2781: harvest its fixture and test cases, then close. Both closures are T-RD-16, and no G0 item covers them yet (§10).
  • Closure-note drafts (not to be posted while the hold lasts):

#3934. Harvested into R1a. The bounded reader, the canonical plan and legacy adapter, the controller and the transactional receipt with its tests are split into R1a-3 (preview behind the import-target port) and R1a-4 (legacy apply), with the dialog adapted to the new editor's design (harvest map H-IMP-01 to H-IMP-07). The canonical adapter, which writes versioned question drafts with import or copiedFrom provenance, follows in R2a.

#2781. The reference parser, shared fixture and Python tests shaped #3934's legacy adapter. The fixture becomes a .NET golden test in R1a-3, and the test cases are used to find coverage gaps (H-IMP-08, H-IMP-09). The live uploader, its production impersonation path and its CI lane are not carried, because the production path is the server-side atomic import.

4.10 #2387, QM child visualisation and assign tree

  • Holds. 46 files: 2024 work by Mala K and Chris, a feature commit of 10 March 2026 and a merge of main. Much of the diff is formatting churn, and two stray files sit at the repository root.
  • State and drift. Conflicting; 27 of its 46 paths changed on main since March. The head does not compile (D-D13), and CI is red.
  • Disposition. Harvest then close. 2 Adapt, 1 Reference only, 5 Avoid. Closure is T-RD-16.
  • Closure-note draft (not to be posted while the hold lasts):

Harvested: the child-question validity rule (a child condition naming a parent option that no longer exists), as the R1a editor warning and the R2a composition refusal (AC-R2a-24, FX-VM-10), re-keyed on option IDs; and the computedPrevious tests, for main's signal utilities. The sticky flat Assign tree, the template-driven validation framework, the MatOption subclass and the navigation changes are superseded by main or retired, because forms replace per-stage question selection. Thanks to Mala K and Chris for the 2024 child-visualisation work.

5. Harvest entries

All 131 entries, merged from the five audits with their IDs kept. They are grouped by the release that first uses them. The Target column names a second release or row where an entry splits. Effort is the audits' grading for the port or adaptation including tests: S one day or less, M one to three days, L more than three days, — nothing to port. Defect IDs such as C-D05 are explained in §6.2.

5.1 M0: the harvest record (T-RD-10)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-WEB-17 #2575 D-RS-01 to D-RS-05 in release-strategy.md Reference only AC-M0-04 record; RD §4.8; BC §10; C16; T-RD-10 Record each as superseded: D-RS-01 is the F1a and G0 model; D-RS-02 becomes Study.CanonicalSummary and the C16 readers; D-RS-03 becomes versions with "removed question" treatments (AC-R2c-18); D-RS-04 becomes universal conversion with routing rollback; D-RS-05's batching survives as phase 2 per Study, without freezing review. D-RS-03's dialog wording is copy input for AC-R2c-18 — docs/features/question-management/release-strategy.md:357-408 @0983307
H-WEB-19 #2575 Planning and history docs (implementation plan, state of play, reviews, migration strategy, the M011 plan, five April plans, three feature briefs) Reference only Decision register §5; T-RD-10 Not ported into docs/; cited by SHA here. Their briefs now belong to other lanes: annotation import to XA1, question import to R1a, autosave to AF2 and RD §4.2, training rounds to TI — docs/features/question-management/*.md @71b179c

5.2 F1a: contract drafts (T-RD-01)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-DOM-02 #2572 AnnotationAnswer records, EnsureCompatible, FromLegacy Adapt RD §3.9; C1 revision payload, C2; VM §3.4, §6.3; T-RD-01; R2a T-RD-02; adoption T-BC-01 Option answers carry option IDs; add response mode, metadata and unmappedLegacyValue; FromLegacy and ResolveValueType fail closed on unknown types (BC-R08, BC-R26; A-N6); structural equality for list payloads (A-N5) M PMC/Model/AnnotationAggregate/AnnotationAnswer.cs:19-44,89-103 @af51366
H-DOM-05 #2572 AnnotationQuestionV2, AQVersion, QuestionOptionV2, AnswerOptionFilter, DraftContent Reference only RD §3.4; C4; VM §3.1 to §3.3; T-RD-01, T-RD-02 Keep the identity and content split, init-only identity, never-delete (QD1) and "seed a design draft from an older version". Versions become separate records; requiredness is form-owned (VB-17); entity types replace categories (DD-12); the catalogue's copiedFrom replaces Scope (D2-15). Rename A's QuestionRef, which means a version pin in A and an identity in the package. The model has no condition field (A-N1) — QV/AnnotationQuestionV2.cs:15-135,197-221,335-351 @af51366
H-DOM-06 #2572 ChildQuestionScope, AnnotationCollectionMode, ResolveCollectionMode, ResolveValueType Adapt VM §3.1 (repeatable), §11; C2 instance element; D2-03; T-RD-01; mapping in T-BC-01, T-BC-03 Fix repeatable at creation, not at the first Multiple publish; unknown DataType fails closed; one mapping table shared by conversion and the designer S PMC/Model/AnnotationAggregate/Annotation.cs:489-549 @af51366; QV/ChildQuestionScope.cs:28-35
H-DOM-07 #2572 SystemQuestionFactory (18 definitions with per-version parent and option resolvers) Adapt VM §3.7; RD-R32; D2-06; C4 system row; T-RD-01 (seed contract), T-RD-02; parity input to T-BC-01 Global records keyed (systemGuid, systemQuestionVersion, seq) with a structural digest, never per-project documents with the GUID as _id (H-MIG-02); restore main's exact text at seq 1 (A-N7); mint stable option IDs; a parity test against main's AnnotationQuestion.SystemQuestions, including #2651's anchor split M PMC/Services/SystemQuestionFactory.cs:18-50,119-127,171-187 @af51366; PMC/Model/ProjectAggregate/AnnotationQuestion.cs:417-421,724,739 @7673ed0
H-DOM-10 #2572 ADR-011 (A): two-level draft and formal versioning Reference only F1a storage ADR rationale; RD §3.10; VM §7.7; T-RD-01 Cite in the storage ADR; never merge. Its ageing snapshots and per-annotation drafts conflict with RD §3.10, and its number is taken on main — docs/decisions/ADR-011-qm-v2-two-level-draft-and-formal-versioning.md:44-110 @af51366
H-DOM-11 #2572 ADR-010 renames, ubiquitous-language.md, scripts/apply-qm-renames.sh Reference only Domain model §8; F1a naming ADR; T-RD-01 An old-to-new name key for reading dormant code; superseded by domain model §8 — docs/decisions/ADR-010-qm-v2-ubiquitous-language-renames.md:39-79 @af51366
H-DOM-16 #2572 Extracted AnnotationSession, AnnotationSessionVersion and its trigger enum Reference only RD §3.9; C5; VM §7.1 to §7.3; T-RD-02, T-RD-04 Keep the full pin-map shape and status derived from the latest explicit version. Sessions are Study × form with deterministic IDs, have drafts (SL1), and the reconciler is not a form session — PMC/Model/AnnotationSessionAggregate/AnnotationSession.cs:20-63,326-359 @af51366
H-DOM-23 #2572 VersionAudit, typed VersionReference records, VersionChangeReasons Adapt C1, C3 provenance; VM §12.3, §12.4; T-RD-01 Add real actor, effective author, operation, command ID, clock stamp and digest; typed references back the integrity checker; rename QuestionRef S QV/VersioningValueObjects.cs:11-95 @af51366; QV/VersionChangeReasons.cs:9-21
H-VAL-03 #2986 Shared fixture annotation-answer-conformance-v1.json with .NET, AF1 and AF2 runners Adapt E23; AC-R2a-03 (FX-APPLIC); T-RD-01, T-RD-02 Re-key to option IDs and pinned question versions; add applicability, response-mode and metadata cases; keep the three-runner pattern, with AF1 for legacy parity only S src/services/web/src/app/shared/annotation/testing/annotation-answer-conformance-v1.json @1c6799b
H-VAL-04 #2986 Rule codes and AnnotationAnswerConformanceProblemDetails Adapt RD §4.4 ValidationFailed; C18 and E23 error catalogue; T-RD-01, T-RD-02 Return every error, not only the first (V-D2); add the C2 context key and the question version; keep the codes stable S PMC/Services/Validation/AnnotationAnswerConformanceValidator.cs:10-37; API/Models/AnnotationAnswerConformanceProblemDetails.cs:8-42 @1c6799b
H-VAL-07 #2987 ADR-016 §1 and §3: server authority, five semantic categories, value XOR mode, suppression derived Adapt F1a C4 ADR (a number from ADR-030 to 069, DOM §11.8); VM §3.4; E37; DD-12; T-RD-01 Map onto question-version content. Settle in E37 that a response is a value or a responseModeId, plus metadata: #2987 also allows metadata alone (V-D3). A reference response belongs to C1 or C13 entity references, not options S docs/decisions/ADR-016-annotation-schema-profile-boundary.md:57-114 @efd4b96
H-VAL-08 #2987 ADR-016 §4 and §5: exact session-to-version chain, LatestVersion prohibited, lifecycle Reference only C4 (QD1), C5; RD §3.9; T-RD-01 Cite as provenance; the contracts already cover it S Same file, :116-150 @efd4b96
H-VAL-10 #2629 FEAT-027 problem statements Reference only E23, E24; DD-12; ACD §3.4; T-RD-01, T-AC-04 Problem framing only S docs/features/annotation-questions/configurable-validation-strategy.md:119-266 @d761ca4
H-VAL-12 #2812 ADR-017 response contract (value XOR mode, scoped metadata, stable IDs, no global N/A enum, suppressDescendants by ancestor instance, requiresReason, presence-sensitive updates) Adapt F1a C4 ADR and E37 (T-RD-01); units and metadata types into the F-O C14 ADR (T-RI-11) definitionVersion becomes the revision's questionVersionRef; expectedDefinitionVersion becomes the session's declared form version plus StaleBase; drop schema-v0 activation; align units with C14 M docs/decisions/ADR-017-annotation-response-modes-and-metadata-contract.md:28-192,252-273 @1c38692
H-VAL-13 #2812 Freeze-on-first-use (Chris, 18 August 2026) Reference only C4; VM §3.4 (PH-06) Provenance for frozen versions. main's extensibility doc still calls the choice "not decided" (§5.14) S Same file, :209-250,341-345,374-417 @1c38692

5.3 R0: the compatibility floor (no R0 row; held by T-BC-06)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-DOM-19 #2572 ThrowIfMigratedForLegacyMutation and ThrowIfMigratedForLegacyProjection on Project and Stage Adapt C16 E49; integrated plan §5 R0 item 3; BC §4.5; T-BC-06 Key on the per-scope CanonicalScopes marker (Project and Study) through main's IAggregateWriteGuard, not on MigrationStatus S PMC/Model/ProjectAggregate/Project.cs:643-660 @af51366; Stage.cs:318-326
H-API-06 #2574 GuardLegacyReviewPath, Study.UsesExtractedReviewState, ExtractionInfo.ThrowIfUsingExtractedReviewState Reference only R0 floor item 3; C16; BC §4.5; writer list for T-BC-01; T-BC-06 Not ported; its guarded methods start R0's writer inventory. It falls short: the flag moves with migration and rollback; screening, consumers, UpdateMany, bulk update and question-delete cascades are unguarded; no CAS; an untyped refusal that loses the draft; no refusal test — PMC/Services/ReviewSubmissionService.cs:14-18,46-51,57-63,72-79 @874a421; PMC/Model/StudyAggregate/ExtractionInfo.cs:398-418

5.4 R1a: question templates and import (T-RD-11, T-RD-12, T-AC-04)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-IMP-01 #3934 QuestionImportFileReader and vendored Unicode case folding Reuse AC-R1a-01 to 04; ADR-009; R1a-3; T-RD-11 Move to the Application layer beside the plan; no logic change S QuestionImportFileReader.cs:24-27,131-159,239-246 @9d6c596cf
H-IMP-02 #3934 QuestionImportPlanBuilder (standard v1, legacy adapter, deterministic IDs, parent and condition resolution, plan hash) Adapt DS-20 import-target port; AC-R1a-01, 02; C4 identity; DD-12; R1a-3; T-RD-11 Split into a target-neutral rows-to-plan step and target resolution behind IQuestionImportTarget; @question, @system and category placement move into the legacy adapter; errors name the unresolved reference; add the lookup remap or refuse lookups and amend AC-R1a-01 (brief item, §10); filtered-options columns arrive in format v2 for R1a-5 M QuestionImportPlan.cs:32-38,194,224-241,272-290 @9d6c596cf
H-IMP-03 #3934 QuestionImportService, QuestionImportAuditStore Adapt AC-R1a-01, 03, 04, 08; V2-16; R1a-3, R1a-4; T-RD-11; writer inventory in T-BC-01 Expose as LegacyProjectImportTarget; list it in R0's writer inventory and refuse canonical projects; move the bulk-lock check inside the transaction (E-D11); create indexes at start-up (E-D8); rename to pmQuestionImportReceipt and pmQuestionImportAttempt (E-D9); store receipts as BSON (E-D10); add source {kind: file, catalogue or project} for AC-R1a-08; stop calling preview read-only, since it writes an attempt record M QuestionImportService.cs:41-57,96-187 @9d6c596cf
H-IMP-04 #3934 QuestionImportController, upload processor, annotationQuestionImport flag Reuse C10-T07; flag rules; R1a-3, R1a-4; T-RD-11 Regenerate OpenAPI, the client, checksums and flag artefacts when it is re-cut on main; add the routes to EndpointAuthorizationCatalogTests S QuestionImportController.cs:11-110 @9d6c596cf
H-IMP-05 #3934 Angular question-import component, service, dialog and spec Adapt Plan R1a; U19; C17 and F1c placement; UX §3.12; AC-R1a-07; T-RD-11 Validate against U19 and Material 3 and place it as C17 says. Under the canonical adapter, Confirm creates a draft, not live questions. R1a-6 removes the "Focused question" text under the new toolbar M question-import.component.ts:35-75,90-240; design.component.html:14-15 @9d6c596cf
H-IMP-06 #3934 Refusal of unsupported fields (CAPABILITY_NOT_AVAILABLE) Reuse Legacy adapter (T-RD-11); lifted per capability by the R2a canonical adapter (T-RD-02) Keep for the legacy target; lift each refusal once C4 version content and AF2 support the field S QuestionImportPlan.cs:154-161 @9d6c596cf
H-IMP-07 #3934 ui-import-implementation.md, how-to/import-question-templates.md Adapt The R1a-3 and R1a-4 PRs; T-RD-11 Re-cut to the R1a slices and the import-target port; mark the canonical adapter as an R2a follow-on S docs/features/question-management/ui-import-implementation.md @9d6c596cf
H-IMP-08 #2781 contract-fixtures/annotation-questions-v1.csv and .expected.json Adapt R1a-3 .NET golden test; AC-R1a-01; T-RD-11 Map the expected payloads to the .NET plan. #2781 puts option labels into description, which #3934 refuses (E-D18): keep the refusal until display-label persistence lands and record that row as an expected refusal S contract-fixtures/annotation-questions-v1.expected.json:42-52 @2d8b071b0
H-IMP-09 #2781 question_template_parser.py and its three test suites Reference only R1a-1 evidence; T-RD-11 Compare its cases (cycles, answer_mode, Unicode, sibling order, booleans) with #3934's tests and port gaps as .NET tests; no Python is carried S question_template_parser.py, test_question_template_parser.py @2d8b071b0
H-IMP-12 #2781 docs/how-to/bulk-import-annotation-questions.md Reference only Input to H-IMP-07 Superseded by #3934's how-to — docs/how-to/bulk-import-annotation-questions.md @2d8b071b0
H-TREE-01 #2387 Child-validity check (checkChildQuestionValidity, isChildInvalid, editor warning) Adapt R1a client warning (T-RD-12); R2a server refusal (T-RD-02); C4; AC-R2a-24; FX-VM-10 Compare option IDs, not values (C4; ADR-011's multi-option conditions); a pure function over main's current design.store; the server validator is authoritative; sentence-case copy naming the parent, child and option M QM/design/design.store.ts:153,189-213,444; QM/edit/edit.component.html:43-55 @c81426c
H-TREE-02 #2387 "New options untouched on children" (OptionStatus.addedUntouched, NewOptionComponent) Reference only AC-R1a-06 (T-RD-12); VM §3.5 added options; C4 Re-express as an explicit "Show for new option?" choice keyed on option IDs, with public components; the code overrides private MatOption internals (D-D17) S QM/edit/new-option/new-option.component.ts:39-62 @c81426c
H-TREE-07 #2387 core/utils/signal.utils.spec.ts Adapt main's core/utils/signal.utils.ts; T-RD-12 Keep the computedPrevious cases; rewrite the computedFromPrevious cases to recompute through a source signal (D-D15) S signal.utils.spec.ts:1-50 @c81426c; signal.utils.ts:43-53 @7673ed0
H-DOM-24 #2572 ReplacementDraftLineagePlanner, DraftPQS.ReplacePublishedSubtree Reference only ACD §3.4 catalogue copy (copies are new identities with copiedFrom); VM §4.5; T-AC-04 The subtree-copy algorithm and its deterministic tests as input; not a versioning mechanism (RD-R30) — PMC/Services/ReplacementDraftLineagePlanner.cs:10-70 @af51366

5.5 R1b: the Members & groups page (T-AC-11)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-GRP-13 #2224 custom-groups-table, project-group-badge, membership-table badges, edit-entity toggles, create-project-group, the project-members rework, with specs Reference only R1b page (T-AC-11); R1c (T-AC-10); U8; UX §3.12 main rewrote membership-table (#2771, #3459), project-members (#2271) and the invite dialog, so rebuild against U8 and carry the specs' behaviours, not the files — custom-groups-table.component.ts:31-36; project-group-badge.component.ts @fff8385ac
H-GRP-14 #2224 Web state fixes: the selector drops unknown groups, the stage-permission entity keys on stageId, the effects normalise group objects Adapt AC-R1b-04 (the page shows exactly what is enforced); T-AC-11 Reproduce each on main with a failing spec first; main still has all three. The effects change may be unnecessary; confirm whether consumers use id or stageId S project-detail.effects.ts:795-806, membership.selectors.ts:50, stage-permission-set.entity.ts:12 @fff8385ac

5.6 R1c: configurable groups and the permissions dialog (T-AC-10)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-GRP-01 #2224 Group endpoints in ProjectController, CreateCustomGroupDto Adapt AC-R1c-01, 12; C10; #3335 WP11; T-AC-10 Add rename; ProblemDetails bodies; 404 for an unknown group and 400 for a null body (E-D7); CreatedAtRoute; register in the endpoint catalogue (C10-T07); behind an R1c flag after X-AUTH-SCHEMA; write authorizationAudit entries (AC-R1c-06) M Controllers/ProjectController.cs:772-835,935 @fff8385ac
H-GRP-02 #2224 CreateCustomGroup, DeleteCustomGroup, TryGetGroup, ProjectMembership.LeaveGroupInternal Adapt C10 anti-escalation and revocation; AC-R1c-08, 10; ACD §3.10; TI-R17; T-AC-10; consumers T-TI-04, T-RS-07 Schema 1 only; skip or clear owner-reserved legacy grants without tripping main's storage guard (E-D3); raise GroupCreated, GroupRenamed, GroupDeleted; route revoked Review grants through claim revocation; an active-work impact preview first (T-AC-09); refuse or convert deletion while a training policy or adjudicator assignment references the group; a domain exception, not DuplicateNameException M Security/ProjectSecuritySettings.cs:151-268, ProjectMembership.cs:223-235 @fff8385ac; ProjectPermissionsWithDefaults.cs:29-36 @7673ed0
H-GRP-07 #2224 Save changed to await SaveAsync in membership and permission endpoints Reference only Whichever R1c slice touches those endpoints (T-AC-10) Hygiene only: its "silent data loss" reason is refuted, because the synchronous save completes before the response S ProjectController.cs:1223,1297,1318,1342; MongoUnitOfWorkBase.cs:248-273 @7673ed0
H-GRP-09 #2224 ProjectSecuritySettingsTests (20 facts) Adapt AC-R1c-12; Q-09; T-AC-10 Schema-1 projects with an Audit; main's security collection scope instead of the global singleton; add cases for an owner-reserved grant during the cascade, rename, events, and deletion refused while a policy references the group S ProjectSecuritySettingsTests.cs:15-500 @fff8385ac
H-GRP-10 #2224 ProjectControllerTests group section (11 tests plus 2) Adapt AC-R1c-01, 12; C10-T07; T-AC-10 main's constructor takes 7 arguments; add endpoint authorisation tests (403 without EditMemberships) on main's harness; ProblemDetails, 404 and 400 expectations; drop the save-count assertions M ProjectControllerTests.cs:30-345 @fff8385ac; ProjectController.cs:69-90 @7673ed0
H-GRP-11 #2224 ProjectLevelPermissionTests, ProjectStagePermissionTests, TestPermissionHelper Adapt AC-R1c-02, 05, 09; C10-T02; FX-PERM; X-AUTH-ENFORCE parity; T-AC-10 Run every case through the legacy check and ProjectAuthorityEvaluator; enumerate activities from the catalogue (22 project, 4 stage); add the FX-PERM anti-escalation matrix; delete TestPermissionHelper, which sets a process-wide singleton M ProjectLevelPermissionTests.cs:16-167, ProjectStagePermissionTests.cs:17-184 @fff8385ac; ProjectAuthorityEvaluator.cs:213 @7673ed0
H-GRP-12 #2224 manage-group-dialog (group × activity matrix, stage accordion, delete) Reference only AC-R1c-07; U8 dialog design; C17; T-AC-10 Design and test-case input only: it lists 13 of 22 activities (E-D6) and saves one request per change by client-side read-modify-write (E-D4). R1c needs one atomic group-grants command with a base version and a catalogue-driven dialog — manage-group-dialog.component.ts:145-193,310-345,420-470 @fff8385ac

5.7 R2a: versioned forms and sessions (T-RD-02)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-DOM-08 #2572 ProjectQuestionSet.Publish, PQSVersion Adapt RD §3.5 form-version pins; VM §4.1; C4; T-RD-02 Per form, not a project singleton; add requiredness, minimum instances, ancestor closure, the applicability graph, renderability, standardTarget and ReconciliationPolicy; store in pmAnnotationFormVersion, not in Project S QV/ProjectQuestionSet.cs:167-198 @af51366
H-DOM-13 #2572 Candidate validators, QuestionPublishCandidateBuilder, CrossQuestionValidationService, rule codes AQ001 to AQ017 Adapt VM §4.2, §4.3; C4 composition (F1a part in T-RD-01); T-RD-02 Build the candidate from a design draft and pinned versions; re-key filters to option IDs; replace A's placement copy with main's placement rules and validator (#2648, #2651); the stage-subset rule becomes ancestor closure; namespace the codes against main's; keep "not renderable" separate. Never run on legacy data during conversion (C-D09) M PMC/Services/Validation/CandidateProjectQuestionSetValidator.cs:21-60,136-182,231-256 @af51366; PMC/Services/QuestionValidationRuleCodes.cs:11-59
H-API-01 #2574 QuestionManagementV2Controller (17 endpoints) and its DTOs Reference only RD §3.4 to §3.8, §4.7, §4.8; C4; T-RD-02 (drafts, history, reads); T-RD-05 (impact, publish) Rebuild from RD and C4, using the endpoint list as a coverage checklist and its 409 shapes as cases. It publishes by stage, keeps drafts on the question and in Project with no base check (D-D12), puts Optional and Multiple on the question, has untyped option filters, no option IDs and a boolean BreakingChange, and gates by migration status — API/Controllers/QuestionManagementV2Controller.cs:28-30,58-91,114-174,381-449,694-706,763-806 @874a421
H-API-05 #2574 MigratedReviewSubmissionService, MigratedReviewMutationPlanner, typed concurrency conflict, ReviewController's migrated branch Adapt RD §4.2 to §4.4; C1, C5, C18; T-RD-02 Keep evidence and Study in one transaction, the base-version check with a typed conflict (StaleBase) and the duplicate-key-as-CAS idiom. Drop the statistics write in every save (CR-2), hard deletes, LatestVersion at save time (FX-VM-05) and routing by migration status (C-D10); add the command ledger (E50) M PMC/Services/MigratedReviewSubmissionService.cs:44-203,205-263,273-289 @874a421; API/Controllers/ReviewController.cs:77-90,187-215
H-WEB-03 #2575 Design view shell (design-v2.component, design-v2.store) Reference only Design-prototype handoff §4.2, DH-C16, DH-C31; T-RD-02 Layout reference only; build inside main's current editor; entity types, not six fixed tabs; index children by parent once, because buildTree is quadratic and the 2,023-question form is an acceptance case S QMV2/design/design-v2.store.ts:44-51,205-218 @0983307
H-WEB-04 #2575 Question tree and node Reference only AC-R2c-27; AC-R1a-12; UI-1, UI-5, UI-7; handoff §7.4; T-RD-02 Add a version chip and a lifecycle state shown by icon shape and text in Material 3 roles; a virtualised CDK tree; the keyboard model from H-WEB-18. The PR has emoji icons, incomplete tree semantics and no arrow keys, and hides the version number S QMV2/design/question-tree/question-node.component.ts:97-106; question-node.component.html:10-16 @0983307

5.8 F2: the publication contract (T-RD-04)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-DOM-01 #2572 VersionHistory<T> Adapt RD §3.8; VM §8.3 policy generations in FormVersionIssue; C4; T-RD-04 Bounded embedded sequences only. It gives no append-only guarantee, because it wraps a mutable list that a full replace rewrites, so immutability is enforced in the repository and an architecture test; write facade tests S QV/VersionHistory.cs:18-58 @af51366
H-DOM-04 #2572 PublishDecision, DraftPublishDecision, ChangeImpactClassification, AQVersion.BreakingChange, StagePublishDecisionSummary Reference only RD §3.4, §4.8; VM §3.5, §8.2; C4; T-RD-04 Vocabulary only: the classification maps to the publisher's immutable declaration (RD-R20) and the strategy to a treatment; add added, removed and requiredness classes and categories — QV/VersioningValueObjects.cs:101-171 @af51366; QV/AQVersion.cs:65-68
H-DOM-17 #2572 TryApplyPublishTransition (Annotation, AnnotationSession, OutcomeData), CreatePublishTransitionReplacement Reference only RD §3.15, §4.8 phase 2; C4, C5; T-RD-04 Keep "no version when nothing changes" as the no-generation rows. The code copies status, clears answers and writes without operation, generation or CAS (A-N2, A-N3) — PMC/Model/AnnotationAggregate/Annotation.cs:270-341 @af51366; AnnotationSession.cs:253-324
H-SVC-02 #2573 StageImpactFingerprint.Compute Adapt RD §4.8 step 3 (PreviewDigestChanged); AC-R2c-06; T-RD-04 Digest identities and heads (session ID, head sequence, pinned form version), the draft-only count, the treatments' draft revision and the usage-evidence identity; a canonical or length-prefixed encoding (B-D11); no answer values S PMC/Services/AnnotationImpactService.cs:206-245 @2712901
H-SVC-04 #2573 SessionTransitionService.PlanStageTransition Adapt (rewrite, using the logic as reference) RD §3.15, §4.8 phase 2; C4 publication; C5 PublicationGenerated; consistency §7.4; T-RD-04, then T-RD-05 Keep one combined version per session per generation, publisher attribution, and removed questions leaving the new version. Change: sessions keyed by form across stages; the generation table per category; affected sessions only (B-D5); every prior version (B-D6); head CAS and deterministic IDs per (sessionId, operationId, generation) (B-D7); no invalid Complete; the reviewer stays effective author (B-D9); a pure planner (B-D1). Rewrite the Mouse-to-Rat mapping fixture, a meaning change Q-34 forbids L PMC/Services/SessionTransitionService.cs:36-186 @2712901
H-SVC-05 #2573 Decision vocabulary as B consumes it, and the job's decision snapshot Adapt IssuePolicyRecord per question in FormVersionIssue; VM §8.2, §8.3; RD-R20, RD-R21; T-RD-04 Keep becomes autoUpdate or doNothing; Map becomes a mapping by option ID; ReAnswer becomes requireReanswer, which keeps pins and shows Needs updating; add added, removed, per-category scope, the counting choice and a rationale M QV/VersioningValueObjects.cs:101-160 @3619043; PMC/Model/StageTransitionJobAggregate/StageTransitionJob.cs:259-268 @2712901
H-SVC-09 #2573 SessionTransitionService.PromoteDecision Reference only RD §4.7, §4.8 steps 2 and 3; T-RD-04 Already implied by attributed design-draft changes; not worth porting S PMC/Services/SessionTransitionService.cs:22-34 @2712901
H-SVC-12 #2573 StageTransitionInProgressException Reference only Typed PublicationInProgress (D2-11, C18); AC-R2c-14; T-RD-04 Key by form; carry the running operation and its progress S PMC/Services/StageTransitionExceptions.cs:6-22 @2712901
H-API-02 #2574 Publish preconditions (expected published version, expected impact fingerprint, conflict DTO) Adapt C4 publication; RD §4.8; D2-11; RD-AE16; T-RD-04, T-RD-05 Key on the form head (formId, currentPublishedSeq, publicationSeq); digest over the preview for prior versions, categories and treatments; typed StaleBase and PublicationInProgress; drop the stage job S API/Controllers/QuestionManagementV2Controller.cs:114-174,790-806,920-930 @874a421; PMC/Services/OptimisticConcurrencyExceptions.cs:5-24

5.9 R2c: publication with impact (T-RD-05, T-UX-06)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-SVC-01 #2573 AnnotationImpactService.ComputeStageImpact, IStageImpactReader Adapt RD §4.8 step 1; Q-20; RD-R22; C4; C8; T-RD-05 (with T-RD-04) Key by form; count completed, saved incomplete and draft-only sessions by prior form version and route; read a pinned snapshot through the C8 boundary; a set for membership; drop the embedded overload M PMC/Services/AnnotationImpactService.cs:23-88; PMC/Interfaces/IStageImpactReader.cs:8-11 @2712901
H-SVC-03 #2573 Top-20 answer distribution per question Reference only RD §4.8 step 2 mapping choice; Q-34; T-RD-05, T-UX-06 Count per option ID, show retired options only, to publishers only; not a code port S PMC/Services/AnnotationImpactService.cs:153-162 @2712901
H-SVC-10 #2573 StageTransitionSummary and the job counters Reference only VM §8.6 impact manifest; RD §4.8 step 5; T-RD-05 Use the manifest vocabulary (carriedForward, needsUpdatingVersion, mappedByPolicy); two counters are never set (B-D10) S PMC/Services/SessionTransitionService.cs:366-381 @2712901
H-API-04 #2574 StageImpactReader aggregation pipelines Reference only C4 per-category counts; C8; FX-VM-35; T-RD-05 New readers for the per-form-version usage family; this one is stage-keyed, has no draft-only category and no protected usage boundary — PMD/Readers/StageImpactReader.cs:27-120 @874a421
H-WEB-06 #2575 Impact and mapping panel, DraftPublishDecision Reference only RD §3.4, §4.8; Q-34; handoff §5.9, DH-C32; T-RD-05 Copy and the distribution display only; keep becomes doNothing, re-answer becomes requireReanswer, map becomes a per-option mapping where meaning is unchanged. The PR maps by value, uses a binary "may affect" and its effect re-triggers itself (D-D07) S impact-mapping-panel.models.ts:7-28; impact-mapping-panel.component.ts:161-176 @0983307
H-WEB-07 #2575 Publish wizard (five-step stepper) Reference only RD §4.8; UX §3.9; handoff §5.9; AC-R2c-01 to 35; T-RD-05, T-UX-06 Rebuild on the shared impact-preview pattern and main's "Apply anyway" prompts; step titles as sentence-case copy only. It is stage-scoped, throws on open (D-D03), drops decisions (D-D04) and is not zoneless-safe (D-D08) S publish-wizard.component.ts:269-299,336-338,375-387 @0983307
H-WEB-08 #2575 Publish concurrency inputs, extractApiErrorMessage Adapt RD §4.8 step 3; UX §3.9, UX-R35; AC-R2c-35; C4, C8; T-RD-05, T-UX-06 Rename to the form-head CAS plus the preview digest; route the typed refusal to the recheck screen ("The impact changed since you reviewed it"); typed problem codes instead of parsing message text S QMS/qm-v2-root.store.ts:160-175,232-265 @0983307
H-WEB-10 #2575 Preview v2 (published versus pending, change markers, banner) Reference only AC-R2c-16; T-RD-05 Re-implement the markers in main's AF2-based preview against form-version pins, not stage sets S QMV2/preview/preview-v2.store.ts:21,89-133 @0983307
H-WEB-11 #2575 Version-transition alert (AF2/version-transition-alert/*) Adapt UX §3.10; RD §4.8 step 5; AC-R2c-07, 16, 20r, 22; T-RD-05 Use the copy deck (Needs updating, Outdated answers, Fix); show the generated version's attribution; offer "Use previous answer" only when that value is valid under the session's pinned version; Material 3 roles; host it in main's AF2, which left it out of the lift M AF2/version-transition-alert/version-transition-alert.component.html:1-60; .ts:93-112 @0983307
H-WEB-12 #2575 Web AnnotationImpactService and StageImpactSummary DTO Reference only C8; RD §4.8 step 1; T-RD-05 The field list as input to the impact-preview DTO; it hard-codes a relative API URL (D-D11) — annotation-impact.service.ts:7-28,52-55 @0983307
H-WEB-18 #2575 ui-specification.md, publishing-versioning-ux.md, prototype.html, figma-design-reference.md Reference only AC-R2c-27 (T-RD-05); AC-R1a-12 keyboard model (T-RD-12); UX §3.8; handoff §5.9 §8's history timeline with a per-field diff is the only design for AC-R2c-27: show the version number on cards, "Restore" creates a new draft, add "Why it changed" and "What reviewers need to do differently". §9's keyboard and tree model serves AC-R1a-12. Already assets A and A2 in the UI coverage comparison S docs/features/question-management/ui-specification.md:748-880 @0983307

5.10 Conversion track: dry run, staging trials, parity and R6 (T-BC rows)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-MIG-01 #2574 ProjectQuestionMigrationDomainService and its plan Adapt BC §3.3 baseline structures, §3.4, §4.2 dry-run preview; BC-R15; C4; T-BC-01 (preview), T-BC-03 Emit a manifest draft and a legacy activity mapping, not aggregates; target RD's definitions and forms with standardTarget from the effective legacy target and NoAcceptance for target-one forms; pin global system-question versions (H-DOM-07); stable option IDs; deterministic IDs from (project, manifest lineage, legacy ID) with LegacyIdAlias; repairs and validation errors become findings (C-D09). New fixtures: two projects in one database; a project valid since #2648 M PMC/Services/ProjectQuestionMigrationDomainService.cs:71-117,138-144,218-225,246-252 @874a421
H-MIG-04 #2574 ReviewStateMigrationDomainService.BuildExtractionBatch Adapt BC §3.2 to §3.4; C1; C14; T-BC-03, T-BC-05 Target RD's session, session-version, head and revision records and O1 observations; deterministic IDs; carry the original time, author and wording with legacy-gap states (UnknownLegacyTime, UnknownLegacyAuthor, LegacyCompletionUnvalidated, ValueOrDefaultUnknown); duplicates to a Conflicted head; throws become manifest dispositions; include main's six session fields (C-D06) L PMC/Services/ReviewStateMigrationDomainService.cs:30-66,93-97,142-149,176-201 @874a421
H-MIG-06 #2574 MigrationValidationService Adapt BC §3.3 parity report, §4.4; BC-AE13; C16; T-BC-06 Compare legacy records with shadow canonical records; persist a parity report per attempt and run; quarantine instead of throwing; legacy-gap differences are expected; add decisions, pools, offered work, permission-filtered output, exports, statistics (#3845) and timings M PMC/Services/MigrationValidationService.cs:32-113,197-318 @874a421
H-MIG-07 #2574 MigratedStudyReadModelAssembler, ExtractedAnnotationLegacyMapper Adapt BC §4.4, BC-AE13 (exports); domain model §2; T-BC-06 Retarget to RD records; carry stored wording, legacy time and author with gap labels, and every current embedded field; missing references become parity findings; for parity and legacy-shaped exports only, retired at R7; never for rollback M PMC/Services/MigratedStudyReadModelAssembler.cs:31-142; PMC/Services/ExtractedAnnotationLegacyMapper.cs:29-64,137-164 @874a421
H-DOM-14 #2572 AnnotationRelationshipValidator over validation-state projections Adapt BC §4.2 dry-run findings; C16; T-BC-01 Rebase on main's validator, keeping #2635's duplicate-ID guard; populate child IDs for extracted answers (A-N9) S PMC/Services/Validation/AnnotationRelationshipValidator.cs:43-60; AnnotationValidationState.cs:32-42 @af51366
H-DOM-22 #2572 Extracted OutcomeData, OutcomeDataMutationMapper Reference only C14; BC §3.4 outcome rows; BC-R19; T-BC-05 Field inventory only; A copies values verbatim, where BC labels untouched defaults ValueOrDefaultUnknown — PMC/Model/OutcomeDataAggregate/OutcomeData.cs:15-45,382-417 @af51366
H-VAL-02 #2986 The conformance rules as an inventory detector Adapt BC §3.3 inventory, §8 unmappable values; E37's R6 manifest of unmatched values; T-BC-01 A read-only scan of all historical answers, with no grandfathering, reporting counts per rule code into the inventory and manifest S–M PMC/Services/Validation/AnnotationAnswerConformanceValidator.cs:142-266 @1c6799b

5.11 R5a: as-of exports (T-RI-12)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-API-11 #2574 ExportSpec modes and selectors, legacy-request mapping, the controller gate Adapt C11; AC-R2a-05 previous versions (T-RD-02); AC-R5a-01, 02r, 03 as-of (T-RI-12) Modes become Current, PreviousVersions and AsOf (a clock watermark under the C11 as-of rule); selectors become (formId, seq) and session-version IDs, never stage scopes or a raw date; keep the server refusing unsupported modes behind flags S PMC/Model/DataExportJobAggregate/ExportSpec.cs:6-19,72-100; API/Controllers/DataExportController.cs:69-78 @874a421

5.12 Later: X1 analysis-ready export (T-RI-08)

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-API-12 #2574 ExportSchemaSidecar, ExportQuestionCatalog, ExportSchemaObservationReader Adapt RI §3.9 codebook (T-RI-08); C11 manifests; the previous-versions manifest in AC-R2a-05 (T-RD-02) Key by question and form version; add class, option IDs, requiredness, the version each answer was given under, legacy-gap coverage labels and dataset labels; rebuild the observation reader over canonical revisions M PMC/Services/DataExportServices/ExportSchemaSidecar.cs:8-48; PMD/Readers/ExportSchemaObservationReader.cs:30-121 @874a421

5.13 Outside the programme

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-VAL-01 #2986 The PR as a legacy-write integrity guard Reuse (outside the programme, if G0-D6 is confirmed) Normal triage; T-RD-14 records the disposition Wire it into both legacy submission paths, return HTTP 400 with every error, add endpoint and service tests (V-D1, V-D2) M PMC/Services/Validation/AnnotationAnswerConformanceValidator.cs:104-397 @1c6799b
H-VAL-06 #2986 LookupTargetInvalidId rule Reuse (outside the programme, with H-VAL-01) Normal triage None S PMC/Services/Validation/AnnotationRelationshipValidator.cs:248-259 @1c6799b
H-VAL-15 #2812 Fail-closed boolean flag parsing Reuse (outside the programme; platform hygiene) A small separate fix (§5.14) Port the type check to main's generator, which still returns JSON.parse(value); add a .NET test S src/services/web/scripts/generate-feature-flags.ts @1c38692; same file :389-398 @7673ed0
H-GRP-05 #2224 FixAdminGroupIds inverted guard and its notes Reference only Preflight input to #3335's WP-M2; not R1c Do not change legacy behaviour before migration; record the observation as a preflight query S ProjectMembership.cs:266-275, Project.cs:880-887 @fff8385ac
H-GRP-06 #2224 Schema-0 CustomProjectPermissions getter fix Reference only A follow-up for the authorization programme (§5.14) Write a failing schema-0 test on main first; the fix follows only if it fails S ProjectSecuritySettings.cs:80 @fff8385ac; ProjectSecuritySettings.cs:60,82, PermissionCollectionWithDefaults.cs:45-47,88-102 @7673ed0

5.14 Findings outside this programme

Each is a candidate for a follow-up issue. None gets a tracker row.

  1. Flag parsing (H-VAL-15). main's generated parseBoolean returns JSON.parse(value), so a non-boolean value such as "1" counts as true (src/services/web/scripts/generate-feature-flags.ts:389-398 @7673ed0). #2812 has the fail-closed check.
  2. Schema-0 permission update (H-GRP-06). On main, UpdateProjectPermission on a schema-0 project with no stored overrides probably throws NotSupportedException, because the schema-0 getter hands out an immutable empty set. It could affect today's chart-visibility dialog. Unverified: main's tests use schema 1, so the first step is a failing schema-0 test.
  3. Members route guard key (WP1d). project-admin.routes.ts:36 @7673ed0 checks editMembership, while the permission report key is editMemberships. The G0 dossier's slice R1b-2 and #3335's WP1d already name this fix; the audit confirms it is still on main.
  4. Extensibility doc drift (H-VAL-13). main's Approved annotation-question-extensibility-architecture.md:87-93 still lists frozen versus snapshot versions as "not decided". #2812 records Chris's freeze decision of 18 August, and versioning model §3.4 adopts frozen versions.

5.15 Not carried (Avoid)

§6.1 groups these by reason.

ID PR Component Verdict Target (spec §, contract, release, tracker row) Adaptation Effort Evidence
H-DOM-03 #2572 AnnotationAnswer.ApplyTransition, AnswerHandlingStrategy, OptionMapping(OldValue, NewValue) Avoid None; RD §3.15 and §4.8 replace it Not ported. Re-answer keeps pins; mapping writes a new revision by option ID with provenance; it maps null to "" (A-N4). Mapping cases only as fixture inputs — AnnotationAnswer.cs:46-87 @af51366
H-DOM-09 #2572 DraftPQS, DraftSQS, DraftQuestion, DraftQuestionTree, DraftContent, DraftSnapshot, class-map lines Avoid None; RD §3.7 replaces it Not ported; the operation list (add, remove subtree, reorder, promote, withdraw, fork) becomes design-draft change kinds — QV/DraftSnapshot.cs:9-84 @af51366; PMC/Model/ProjectAggregate/Project.cs:109-218
H-DOM-12 #2572 ADR-012 DRAFT: a question-management entity inside Project with RevertToEmbeddedQuestionModel Avoid None Not ported; its verb list is input to domain model §6.3 command names — docs/decisions/ADR-012-DRAFT-question-management-entity-extraction.md:34-60 @af51366
H-DOM-15 #2572 Extracted Annotation, AnnotationVersion, state types, AnnotationMutationMapper Avoid None; C1, C2 and VM §6 replace it Not ported; factory-fixed identity, the collection-mode invariant and LegacyIdAlias survive as ideas, and 25 tests as C1 test ideas — PMC/Model/AnnotationAggregate/Annotation.cs:15-66,343-368,440-457 @af51366
H-DOM-18 #2572 StageQuestionSet, SQSVersion, stage-version references, the Stage.AnnotationQuestions projection Avoid None; SP §3.3 and RD-R31 replace it Not ported; legacy stage sets are conversion input only (BC-R15) — QV/StageQuestionSet.cs:38-150 @af51366; PMC/Model/ProjectAggregate/StageEntity/Stage.cs:128-147
H-DOM-20 #2572 MigrationStatus, migrated and rolled-back marks Avoid None; BC §4.9 replaces it Not ported — PMC/Model/ProjectAggregate/Project.cs:221-285 @af51366
H-DOM-21 #2572 AnnotationQuestion.CreateExportProjections Avoid None; C11 replaces it Not ported — PMC/Model/ProjectAggregate/AnnotationQuestion.cs:193-283 @af51366
H-DOM-25 #2461 The umbrella's domain, service, API and web code Avoid None Nothing to port: 419 of 437 changed paths are byte-identical to a stack tip or main — QV/AnnotationQuestionV2.cs blob 0253500 equals 36190433d @1ca9f5d
H-DOM-26 #2461 Planning archive and stale copies Avoid None Nothing to port; main keeps the planning context — planning-archive/decisions.md @1ca9f5d; docs/planning/qm-v2-context/README.md @7673ed0
H-SVC-06 #2573 Option mapping as executed (ApplyTransition, MapValue) Avoid None; RD-R21 replaces it Do not carry the mapping test — PMC/Model/AnnotationAggregate/AnnotationAnswer.cs:46-85 @3619043
H-SVC-07 #2573 Clearing answer and notes on re-answer Avoid None; RD §3.15 Replaced by a generated incomplete version that keeps pins — PMC/Services/SessionTransitionService.cs:199-204 @2712901
H-SVC-08 #2573 Replacement across question identities and outcome repointing Avoid None; RD-R30 None; context-keyed heads make repointing unnecessary — PMC/Services/SessionTransitionService.cs:223-294,296-335 @2712901
H-SVC-11 #2573 StageTransitionJob and its repository Avoid None; the publication phase-2 operation in T-RD-04 succeeds it Use main's operation family instead — PMC/Model/StageTransitionJobAggregate/StageTransitionJob.cs:10-241 @2712901
H-SVC-13 #2573 Review and export locks during a transition Avoid None; RD-R35 None — PMC/Services/StageTransitionExceptions.cs:24-60 @2712901
H-VAL-05 #2986 Validation against the current definition with grandfathering, for canonical paths Avoid None; VM §3.6 Kept only inside H-VAL-01 for legacy writes — PMC/Services/Validation/AnnotationAnswerConformanceValidator.cs:379-397 @1c6799b
H-VAL-09 #2987 Schema and profile split, per-stage binding, delivery map Avoid None None — docs/decisions/ADR-016-annotation-schema-profile-boundary.md:77-98,195-217 @efd4b96
H-VAL-11 #2629 FEAT-027 runtime design (boot-time rule endpoint, client rule cache, "ADR-011 Project Template") Avoid None None — docs/features/annotation-questions/configurable-validation-strategy.md:286-298 @d761ca4
H-VAL-14 #2812 Schema-v0 activation, per-stage AF2 lock, three-service flag and plumbing Avoid None None — docs/decisions/ADR-017-annotation-response-modes-and-metadata-contract.md:275-308,349-355 @1c38692
H-MIG-02 #2574 System-question documents persisted per project Avoid None; VM §3.7 global store Seed the global store once; conversion pins versions — PMC/Services/SystemQuestionFactory.cs:18-46; PMD/Repositories/AnnotationQuestionV2Repository.cs:12-31 @874a421
H-MIG-03 #2574 ProjectQuestionMigrationApplicationService, MigrationReport, the project marker Avoid None; BC §4.1 to §4.6 Only the batch shape (extract, verify, persist, verify) is noted, which BC §4.4 already requires; two flow tests as cases — PMA/Services/ProjectQuestionMigrationApplicationService.cs:46-161 @874a421
H-MIG-05 #2574 Extracted-state activation (Study.EnableExtractedReviewState, ExtractionInfo.ClearReviewReadModel, the class map) Avoid None; R0's CanonicalScopes marker and reader floor replace it Not ported. It erases the legacy originals from pmStudy (C-D05) — PMC/Model/StudyAggregate/Study.cs:137,226-253; PMD/Repositories/StudyRepository.cs:2684-2697; PMT/QuestionVersioning/ProjectMigrationMongoIntegrationTests.cs:52-55 @874a421
H-MIG-08 #2574 ReconstructiveRollbackService, RollbackProjectMigrationAsync, Study.DisableExtractedReviewState Avoid None; BC §4.9 and §4.10, BC-AE19, BC-AE20 Not ported. A destructive, lossy hand-back to legacy (C-D07) — PMC/Services/ReconstructiveRollbackService.cs:13-16,55-80,105-118 @874a421
H-MIG-09 #2574 StudyRepository.BackfillAnnotationVersionIdsAsync, embedded QuestionVersionId Avoid Writer inventory in T-BC-01, as a pattern to refuse Not ported — PMD/Repositories/StudyRepository.cs:2734-2763 @874a421
H-API-03 #2574 StagePublishApplicationService, StagePublishDomainService Avoid None; C4 and RD §4.8 Not ported — PMA/Services/StagePublishApplicationService.cs:62-216 @874a421
H-API-07 #2574 ADR-009 pieces copied from #2543, and C's moves into the Application layer Avoid None Not ported — PMA/Services/StageReviewService.cs:9-11 @874a421; docs/decisions/ADR-009-domain-vs-application-service-classification.md:67 @7673ed0
H-API-08 #2574 StageTransitionWorker, its workload service, readers, repository and background service Avoid None; RD §3.8 and main's ADR-020 pattern Not ported — PMC/Services/StageTransitionWorker.cs:47-140; API/Services/StageTransitionBackgroundService.cs:19-38 @874a421
H-API-09 #2574 ProjectStatsAggregate, ProjectStatsService, ProjectStatsRepository Avoid None; FEAT-024 and C8 Not ported — PMC/Services/ProjectStatsService.cs:21-90 @874a421
H-API-10 #2574 Repositories and class maps for PR-A's extracted aggregates Avoid None; RD §3.9 and the storage ADR Not ported — PMD/Repositories/AnnotationRepository.cs, AnnotationSessionRepository.cs @874a421
H-API-13 #2574 DraftSnapshotService (ageing snapshots in Project) Avoid None; RD §3.7 Not ported — PMC/Services/DraftSnapshotService.cs:8-30 @874a421
H-WEB-01 #2575 QmV2RootStore with undo and redo and the draft autosave Avoid None; RD §3.7, §4.7 Build on main's route-owned editor stores with per-item design-draft changes — QMS/qm-v2-root.store.ts:63-67,126-154,160-175 @0983307
H-WEB-02 #2575 Web models and normaliser Avoid None; C4 Its normaliser spec only as a pattern for DTO tests — QMS/qm-v2.models.ts:29-33,62-83; qm-v2.normalise.ts:114 @0983307
H-WEB-05 #2575 Properties panel Avoid None None — properties-panel.component.ts:117-139,168-176 @0983307
H-WEB-09 #2575 Assign view and assign tree Avoid None; compose forms with main's Assign None — assign-v2.store.ts:25-34,359-377 @0983307; QM/assign/assign.store.ts:474-488 @7673ed0
H-WEB-13 #2575 The AF2 scaffold Avoid None Delete; main has its own AF2 — docs/superpowers/plans/2026-08-06-af2-phase2-foundation.md:82,95,125 @7673ed0
H-WEB-14 #2575 Active-reviewer tracking web (32 files) Avoid None; for design-page presence, add a group to main's existing hub (UX §3.8) None — stage/stage-admin/review-settings/review-settings.component.html @71b179c; src/services/web/src/app/study-presence/ @7673ed0
H-WEB-15 #2575 Routing, navigation and the newQuestionManagement flag reuse Avoid None; C17 and handoff §4.1 None — project-admin.routes.ts:67-89; project-nav.component.ts:470-520 @0983307
H-WEB-16 #2575 release-strategy.md R1 checklist and R1 to R3 boundaries Avoid None; integrated plan §8 None — docs/features/question-management/release-strategy.md:32-123,237-336 @0983307
H-WEB-20 #2575 ADRs (two ADR-008s, ADR-009), the QM v2 section of CLAUDE.md, architecture docs, appConfig.local.json Avoid None None — docs/architecture/dependency-map.md:29-65 @0983307
H-TREE-03 #2387 Flat assign tree with a sticky header and scroll-synced positions Avoid None None — QM/assign/stage-assign/stage-assign.component.ts:48-49,153-240 @c81426c
H-TREE-04 #2387 Template-driven validation framework Avoid None None — QM/edit/edit.form-validations2.ts:21; QM/edit/edit.component.html:6-27 @c81426c
H-TREE-05 #2387 Node and editor changes gated by annotation count Avoid None None — QM/design/question-node/question-node.component.html:61,114 @c81426c
H-TREE-06 #2387 Navigation and shell changes Avoid None None — core/nav/nav.component.html @7673ed0 (+587/−302 since 262d6be)
H-TREE-08 #2387 Shared utilities (mapFn, KeyMap, MergeUnion, flattenedNodes) Avoid None None — core/actions/util.ts:467-526 @c81426c
H-GRP-03 #2224 Schema-0 group persistence Avoid None; #3335 WP-M2 Not ported — ProjectMembership.cs:85-114, ProjectRepository.cs:427-442,741-744 @fff8385ac; ProjectRepository.cs:1385-1391 @7673ed0
H-GRP-04 #2224 ResourceSecurity.json default granting AssignPermissions to Administrators Avoid None; C10 Not ported; until R1d only the owner assigns grants — ResourceSecurity.json:50-53 @fff8385ac; OwnerReservedActivityDefaultsTests.cs:23 @7673ed0
H-GRP-08 #2224 PermissionReportResolver null guard Avoid None Not ported — PermissionReportResolver.cs:19-28 @fff8385ac; :30-47 @7673ed0
H-GRP-15 #2224 angular.json and vitest.config.ts exclusion edits, AGENTS.md, .gitignore Avoid None Not ported — angular.json:181-184, vitest.config.ts:32-35 @7673ed0
H-IMP-10 #2781 Live uploader (bulk_importer.py, generic_uploader.py) Avoid None Not ported; the hard-coded production base and impersonation identity must not enter the repository — bulk_importer.py:33,38,55,284-370 @2d8b071b0
H-IMP-11 #2781 pr-tests.yml Python lane and the CLAUDE.md section Avoid None Drop both; any surviving Python runs on juniper-ci — pr-tests.yml:322-326 @2d8b071b0

6. Avoid list

6.1 Everything avoided, and why

The headline. PR-C's migration erases the embedded legacy annotations, sessions and outcome data from pmStudy (H-MIG-05, C-D05). Its rollback rebuilds legacy records from the extracted ones, keeps only five session fields and migration-time timestamps, deletes the extracted documents and flattens work saved after migration into the legacy model (H-MIG-08, C-D07). Together they break the rule that conversion never modifies or deletes legacy originals (BC-R29), the rule that rollback only restores routing before the first canonical write (BC-R27), the compatibility floor (C16) and AC-M0-04's ban on destructive rollback and hand-back to legacy.

Reason Entries Rules it breaks
Destructive or lossy migration and rollback H-MIG-05, H-MIG-08, H-MIG-03, H-MIG-09, H-DOM-20, H-DOM-12 BC-R25 to BC-R29; BC §4.9, §4.10; C16; AC-M0-04. H-MIG-03 is also non-transactional, non-idempotent and has no caller; H-MIG-09 adds a field inside ExtractionInfo with an unguarded UpdateMany
Per-project system-question copies H-MIG-02 D2-06, RD-R32, C4: one global store pinned by (guid, systemQuestionVersion, seq). As written only one project can ever migrate (C-D01)
Embedded version arrays and the wrong storage shapes H-DOM-15, H-API-10 C1, C2, VM §6.3; AC-M0-04 (no unbounded embedded arrays); no context key, entity path or owner scope
Single mutable drafts and drafts inside Project H-DOM-09, H-API-13, H-WEB-01 OS-A01, D2-11, RD §3.7, RD-R26: many drafts, append-only changes with base revisions, nothing pruned
Stage-keyed question sets, publication, transitions and locks H-DOM-18, H-API-03, H-API-08, H-SVC-11, H-SVC-13, H-WEB-09, H-TREE-03 SP-R01, RD-R04, RD-R31, RD-R35; consistency §7.2 (one operation family, ADR-020 on main); C4 phase 1 is constant work
Answer rewriting that RD forbids H-DOM-03, H-SVC-06, H-SVC-07, H-SVC-08 RD-R21 and Q-34 (mapping by option ID, meaning unchanged, originals kept); RD §3.15 (re-answer keeps pins); RD-R30 (same identity)
Validation against the live definition H-VAL-05 VM §3.6, RD-R07: validity is under the declared, pinned version
Exports from the latest version H-DOM-21 C11, VM §10.2: exports resolve pinned versions and carry option IDs; it also drops conditions
Superseded schema, profile and activation designs H-VAL-09, H-VAL-11, H-VAL-14 "Profile" collides with ScreeningProfile (RD §3.6); stages own no form settings (SP §3.2); response modes are canonical content (C4); AF2 only for canonical routes (VB-08)
A statistics document written inside saves H-API-09 FEAT-024 and ADR-019 supersede it; CR-2 (no per-project document in interactive transactions)
Defective or wrong-model designer pieces H-WEB-02, H-WEB-05, H-WEB-16, H-TREE-04, H-TREE-08 C4 (option IDs; requiredness on the form); UI-1 to UI-11; AC-R1a-07; AC-R2c-21r
#2224 pieces that contradict C10 and #3335 H-GRP-03, H-GRP-04 #3335 gate G-D and WP-M2 (schema 1 first); PM2, SEC1 (owner-reserved AssignPermissions); C16 (older binaries drop the groups)
#2781's production uploader and CI lane H-IMP-10, H-IMP-11 AC-R1a-03 (no partial questions); C3 real-actor provenance; C10; the CI runner rules
Superseded by main H-API-07, H-WEB-13, H-WEB-14, H-WEB-15, H-WEB-20, H-TREE-05, H-TREE-06, H-GRP-08, H-GRP-15, H-DOM-25, H-DOM-26 §6.3

6.2 Confirmed defects not to carry over

IDs are the audits' own, prefixed with the audit letter where they would otherwise collide (A-, C-, D-, E-). Audit B's IDs (B-D…, V-D…) are unchanged.

PR-A (audit A).

ID Defect Evidence @af51366
A-N1 Conditional-parent applicability is lost: the v2 model has no condition field, the embedded-model factory sets filters to null, and C's converter never reads conditions and invents missing parents QV/AQVersion.cs:10-68; QV/AnnotationQuestionV2.cs:255-286; PMC/Services/ProjectQuestionMigrationDomainService.cs:132-165 @1b93cbb
A-N2 A publish-triggered session version copies the latest status, so it can stay Completed after answers were cleared (against RD-R23) AnnotationSession.cs:264-277
A-N3 Re-answer clears the answer instead of keeping the pin and flagging it AnnotationAnswer.cs:54
A-N4 Mapping turns a null string answer into "" AnnotationAnswer.cs:78-83
A-N5 No-op detection compares list payloads by reference, so array answers always append a spurious version Annotation.cs:288-295; AnnotationAnswer.cs:138-174
A-N6 Unknown legacy types become strings instead of failing closed AnnotationAnswer.cs:101; Annotation.cs:547
A-N7 System seed descriptions were edited, so seq 1 would not equal production definitions SystemQuestionFactory.cs:119-127 against main's AnnotationQuestion.cs:724,739
A-N8 Rollback discards all question-set history and allows re-migration from rolled back Project.cs:221-283
A-N9 Extracted answers carry no child IDs, so the child-resolution check is skipped AnnotationValidationState.cs:32-42
A-N10 Stage.AnnotationQuestions silently switches to the latest stage set for migrated projects Stage.cs:128-142
A-N11 Unbounded embedded version arrays in six documents AnnotationQuestionV2.cs:119; ProjectQuestionSet.cs:149; StageQuestionSet.cs:77; Annotation.cs:44; AnnotationSession.cs:38; OutcomeData.cs:38

The three semantic conflicts are confirmed: A overwrites in-payload duplicate annotation IDs that

2635 rejects, refuses Study questions under custom Study parents that #2648 allows, and treats any

system parent as first-level against #2651's anchor split.

PR-B and the validation PRs (audit B).

ID Defect Evidence
B-D1 The planner never converts answers to the target type or shape, throws mid-loop after mutating earlier sessions in memory, and so is neither pure nor atomic PMC/Services/SessionTransitionService.cs:72-147,199-221 @2712901
B-D2 The job has no failure or stalled state and re-queues forever StageTransitionJob.cs:10-15,197-204 @2712901
B-D3 Zombie writer: progress and completion take no lease owner or generation StageTransitionJob.cs:178-215 @2712901
B-D4 A random-GUID cursor (forbidden by consistency §7.2) and an ordinal status enum StageTransitionJob.cs:46,185 @2712901
B-D5 Every incomplete session gets a new version on any change, even with no affected answer SessionTransitionService.cs:135-149 @2712901
B-D6 Blind to prior versions: a session still on v1 receives the v2-to-v3 decisions SessionTransitionService.cs:72-147 @2712901
B-D7 No head check and random replacement IDs, so a replay duplicates versions and can overwrite a newer reviewer version SessionTransitionService.cs:85-90,135-143 @2712901
B-D8 Unchecked decisions: classification never read, empty mapping silently copies, many-to-one accepted, a meaning-changing fixture AnnotationAnswer.cs:59-85 @3619043; SessionTransitionServiceTests.cs:39,91 @2712901
B-D9 The publishing admin becomes the author of the reviewer's answer revisions SessionTransitionService.cs:206-218 @2712901
B-D10 Two summary counters are never set SessionTransitionService.cs:366-381 @2712901
B-D11 The fingerprint encoding is ambiguous and digests counts, not identities AnnotationImpactService.cs:30,67,206-245 @2712901
V-D1 #2986 is unwired: no production caller of its validator exists git grep @1c6799b; the PR's checklist
V-D2 Its ProblemDetails reports only the first error AnnotationAnswerConformanceProblemDetails.cs:40-42 @1c6799b
V-D3 #2987 allows a metadata-only response, against C4 and VM §3.4; settle it in E37 ADR-016…md:110-112 @efd4b96
V-D4 ADR numbers collide with main (ADR-016, ADR-017 and a planned ADR-011); harvested content takes numbers from ADR-030 to 069 git ls-tree origin/main docs/decisions/ @7673ed0

PR-C (audit C).

ID Defect Evidence @874a421 unless stated
C-D01 Hard-coded system-question GUIDs: a second project or a retry hits a duplicate key and aborts the migration SystemQuestionFactory.cs:18-46; AnnotationQuestionV2.cs:259; MongoUnitOfWorkBase.cs:355-372
C-D02 Not transactional: four separate write phases and no session ProjectQuestionMigrationApplicationService.cs:76-158
C-D03 Not idempotent: retries fail or short-circuit, and IDs change on every run ProjectQuestionMigrationApplicationService.cs:54-66; ReviewStateMigrationDomainService.cs:149
C-D04 No caller: no endpoint, consumer, job or registration git grep over src @1b93cbb
C-D05 The migration deletes the legacy originals from pmStudy; an older image then reads a migrated Study as having no review data Study.cs:226-253; StudyRepository.cs:2684-2697; ProjectMigrationMongoIntegrationTests.cs:52-55
C-D06 Legacy timestamps, question wording and session fields are lost (4 session fields against main's 10) Annotation.cs:64-90; ExtractedAnnotationLegacyMapper.cs:144-146,163; AnnotationSession.cs:26-52 @1b93cbb
C-D07 Rollback is destructive and hands the scope back to legacy, flattening later work ReconstructiveRollbackService.cs:55-80; ProjectQuestionMigrationApplicationService.cs:206-233
C-D08 The dry run reads no Study, runs read-write and produces no counts ProjectQuestionMigrationApplicationService.cs:68-74
C-D09 Conversion invents parents and refuses projects valid since #2648 and #2651, with no quarantine ProjectQuestionMigrationDomainService.cs:138-144,246-252; CrossQuestionValidationService.cs:316-328
C-D10 The migrated save path writes statistics inside each save, hard-deletes, resolves the latest version and refuses saves when statistics are missing MigratedReviewSubmissionService.cs:187-190,239-255,283-288; ProjectStatsService.cs:59-63
C-D11 An unbounded publish transaction, and an always-on background service with no flag decision StagePublishApplicationService.cs:168-193; Program.cs:142 @1b93cbb
C-D12 The PR body attributes five assignment-state files to #2467; they are QM's own, so #2467's merge does not supersede them git log 0d943a34d^2 -- …/ReviewerAssignmentState.cs returns nothing

PR-D and #2387 (audit D).

ID Defect Evidence
D-D01 Undo does nothing (it tracks keys the store lacks), and its Ctrl+Z handler blocks native text undo QMS/qm-v2-root.store.ts:63-67; design-v2.component.ts:89-99 @0983307
D-D02 Autosave wipes options[]: the first text edit to a published question saves a draft with no options design-v2.component.ts:131-143; QuestionManagementV2Controller.cs:73-86 @0983307
D-D03 The publish wizard throws NullInjectorError: the store is route-scoped and the dialog opens from the root injector; its spec hides this publish-wizard.component.ts:271; assign-v2.component.ts:152,259; spec :77 @0983307
D-D04 Admin decisions are discarded at four points, from the unbound panel to the wizard payload design-v2.component.html:32-35; publish-wizard.component.ts:375-387; qm-v2.normalise.ts:114 @0983307
D-D05 One shared debounce stream drops edits made across questions QMS/qm-v2-root.store.ts:126-131 @0983307
D-D06 The properties panel shows published values and reverts typing (static reading) properties-panel.component.ts:130-139 @0983307
D-D07 The impact panel's effect re-triggers itself (static reading) impact-mapping-panel.component.ts:161-176 @0983307
D-D08 The wizard writes plain fields from an effect in an OnPush component, so it would not refresh with the zoneless flag on and fails main's zoneless discipline; its conflict step always passes publish-wizard.component.ts:286-299,336-338 @0983307
D-D09 Committed conflict markers docs/architecture/dependency-map.md:29-65 @0983307
D-D10 A stale revert of main's MongoDB reference doc docs/architecture/mongodb-reference.md @0983307
D-D11 A hard-coded relative API URL and a subscription with no error branch annotation-impact.service.ts:52-55; assign-v2.component.ts:257 @0983307
D-D12 PR-C's draft save has no base revision, so the last write wins (against RD-R26) QuestionManagementV2Controller.cs:58-86 @0983307
D-D13 #2387's head does not compile: two files sit at the repository root stage-assign.component.ts:48-49; src/services/web/tsconfig.json:7-18 @c81426c
D-D14 Debug output and TEST: copy in the user-facing editor edit.component.html:6-27; edit.form-validations2.ts:21 @c81426c
D-D15 Wrong computedFromPrevious tests signal.utils.spec.ts:24-50 @c81426c
D-D16 An operator-precedence bug (annotationCount ?? 0 > 0) question-node.component.html:114 @c81426c
D-D17 Private Material internals overridden in a MatOption subclass new-option.component.ts:39-62 @c81426c
D-D18 A breaking mapFn signature change and scratch code core/actions/util.ts:467-526 @c81426c

#2224, #3934 and #2781 (audit E).

ID Defect Evidence
E-D1 Schema-0 group persistence bypasses WP-M2, activates stray groups on two production documents, and older binaries drop the definitions on save, orphaning membership IDs ProjectMembership.cs:85-114 @fff8385ac; ProjectRepository.cs:1385-1391 @7673ed0
E-D2 AssignPermissions granted to Administrators by default fails main's owner-reserved tests ResourceSecurity.json:50-53 @fff8385ac; OwnerReservedActivityDefaultsTests.cs:23 @7673ed0
E-D3 The delete cascade throws on owner-reserved legacy grants under main's storage guard ProjectPermissionsWithDefaults.cs:29-36 @7673ed0
E-D4 The dialog saves grants by non-atomic client-side read-modify-write manage-group-dialog.component.ts:310-345 @fff8385ac
E-D5 No anti-escalation, audit, notification capture or claim release on group changes Audit E §3
E-D6 The activity list covers 13 of 22 grantable project activities manage-group-dialog.component.ts:145-193 @fff8385ac
E-D7 Wrong status codes and bodies: 400 for an unknown group, an exception for a null body, string bodies ProjectController.cs:772-835 @fff8385ac
E-D8 #3934 creates indexes on every attempt and swallows failures QuestionImportService.cs:57 @9d6c596cf
E-D9 Its collection names break the pm{Entity} rule docs/architecture/mongodb-reference.md:73-92 @7673ed0
E-D10 The receipt is stored as a JSON string inside BSON QuestionImportService.cs @9d6c596cf
E-D11 The bulk-lock check sits outside the transaction QuestionImportService.cs:96-187 @9d6c596cf
E-D12 Domain logic lives in the API project (ADR-009) SyRF.API.Endpoint/Services/QuestionImport @9d6c596cf
E-D13 No lookup remap, which AC-R1a-01 promises QuestionImportPlan.cs @9d6c596cf
E-D14 #2781's uploader fails closed pending answer-label survival and atomic rollback bulk_importer.py:55 @2d8b071b0
E-D15 Its live path is non-atomic sequential PUTs with DELETE rollback bulk_importer.py:284-370 @2d8b071b0
E-D16 It hard-codes a production base URL and an impersonated investigator (not reproduced here) bulk_importer.py:33,38 @2d8b071b0
E-D17 Its CI lane runs on a hosted runner with no valid reason pr-tests.yml:322-326 @2d8b071b0
E-D18 Its fixture puts option labels where #3934 refuses distinct labels annotation-questions-v1.expected.json:42-52 @2d8b071b0

Known facts corrected or refuted.

  • PR-A's tip has 52 commits after the squash 36190433d, not "about 51": 37 non-merge commits of its own, 7 merges of main, and 8 non-merge commits of main brought in by those merges. Audit B's "45 non-merge" counts the 8 from main; audits A and C's 37 excludes them. Verified on 5 October with git rev-list --count --no-merges 36190433d..af5136696 ^origin/main.
  • "Each branch merged main independently" holds for C and D, not B, which is one commit on PR-A's squash (B-R1).
  • PR-C embeds 73 files derived from #2467, not 75.
  • RevertToEmbeddedQuestionModel is not in #2574; it appears only in PR-A's ADR-012 draft.
  • 2224's "Save() causes silent data loss" is refuted (H-GRP-07).

  • 3934's red .NET test is in a project the PR does not touch.

6.3 Superseded by main

  • #2467, active-reviewer tracking, merged on 30 August 2026 (0d943a34d) with slot reservations and reviewer presence. It supersedes all 73 #2467-derived files in PR-C and PR-D's presence web code (study-presence/ since 19d266c70).
  • #2543, the ADR-009 extraction, merged on 27 April 2026 (6506f7e28). Claims later moved to StudyAssignmentClaim.
  • AF2. PR-D's scaffold was lifted into main as 74dffd658 (6 August 2026) and has grown to 157 files.
  • Validators. #2635 (duplicate IDs), #2648 (nested Study parents) and #2651 (anchor split) own the rules PR-A copied.
  • Stage capacity fields. EnforceAnnotationTarget and IdleSessionTimeoutMinutes are on main, and D2-07 moves them to the form.
  • Statistics. FEAT-024's ProjectStatisticsAggregate (ADR-019) supersedes pmProjectStats.
  • Operations. ADR-020's generation-fenced operations supersede the stage-transition job and worker. The round-2 VB review's harvest of "the StageTransitionWorker pattern" pointed at PR-C, not PR-B, and should not be revived.
  • Write guards. #3909's IAggregateWriteGuard is the seam R0's ownership guard composes with.
  • Exports. #3243's export authorisation and formula neutralisation changed the same writers.
  • The current new editor. Live assignment locks (#3582, #3594), fresh counts (#3572, #3778), Material 3 colours (#4023), answer-label authoring (#2772, #2739) and the AF2 preview host (#2737). The editor still uses native drag events, which AC-R1a-12 replaces.
  • Navigation and shell. #3502, #3454, #3468, #3867, #2712 and #2716; drawer.scss deleted.
  • #2224's neighbours. The permission report (#3642, #3723, #3879), owner-only transfer and owner-reserved refusal (#3964), membership disable (#2271), the members UI rework (#2771, #3459, #3273), new activities (#2788, #3060), the endpoint catalogue tests, and M5b's queued-work authority check.
  • #2781's purpose is superseded by #3934 (the extensibility map's step 2g).
  • Docs and ADR numbers. #2398 deleted the docs PR-A edits and added docs/planning/qm-v2-context/. ADR-008 to ADR-012, ADR-016, ADR-017 and ADR-021 are taken on main.

7. What changed with the owner session

7.1 How the owner-session model changes the harvest

  • The target in the form version (OS-A12, RD-R12). The earlier work kept the target and the timeout on the stage. Now FormVersion.standardTarget and ReconciliationPolicy sit in every canonical form version, and the form owns the timeout and in-progress limit (D2-07).
  • PR-A's pin guards (H-DOM-08) hang off the form version, not the project.
  • PR-C's conversion plan (H-MIG-01) takes the effective legacy target into the v1 form version, with NoAcceptance for target-one forms.
  • PR-D's stage review settings (H-WEB-14) are avoided.
  • Because a target-only change is a publication, the impact counts and digest (H-SVC-01, H-SVC-02) must cover target-only publications and Study overrides.
  • Collaborative drafts (OS-A01, D2-11). Every QM v2 draft is one mutable record: PR-A's draft types, PR-C's base-less draft save and PR-D's last-write-wins autosave. Now many drafts exist, each change is appended with its base revision, and presence is never stored. All draft code is avoided (H-DOM-09, H-API-13, H-WEB-01); only PR-A's operation list survives as change kinds. Single-editor drafts with base checks come in R2a, presence in R2c (rollout plan R-AMB-04).
  • Generated session versions (D2-01 amended, RD-R23). The round-2 rule said publication writes no evidence, which made PR-B's planner and PR-A's publish transitions wrong in principle. The owner reversed it. PR-B's shape, one combined, attributed version per session per generation, returns (H-SVC-04), and PR-A's transitions become reference (H-DOM-17). The code is still rewritten: it copies status, clears answers, has no CAS or deterministic IDs and makes the admin the author.
  • The stage study filter (SP-R01, RD-R04, RD-R31). QM v2 modelled per-stage question sets, stage-keyed publication and stage transitions. Now a stage binds a form identity, its filter alone defines its pool, and sessions are Study × form across stages. The stage sets, transitions, locks, stage-keyed export selectors and per-stage Assign are avoided, and PR-B's counts re-key from stage to form and route.
  • Universal faithful conversion (OS-A14, OS-A15). QM v2 assumed an opt-in per-project migration with a reversible mode and reconstructive rollback (PR-A's MigrationStatus, PR-C's rollback, PR-D's D-RS-04). Now every project converts to a faithful baseline: originals are never modified (BC-R29), routing rollback applies only before the first canonical write (BC-R27, BC-R28), forward recovery applies after it, and a project that cannot convert faithfully is quarantined (BC-R26). PR-C is the most affected. Its erasure and rollback are avoided, and its planner, extraction, parity checker and projection are adapted with legacy-gap states, deterministic IDs and manifests. The "R6 adapters" of the versioning model move to the parity tooling before pilots (T-BC-06), because R6 now means universal waves.
  • The consolidated merge (OS-A29). QM v2 predates duplicate merge. Now a merge produces one current Study with StudyVersion, tombstones and merge and unmerge session-version kinds.
  • Any harvested reader or guard (H-DOM-19, H-API-06, H-MIG-07) must respect the tombstone predicate that R0 adds before P2.
  • The session-version kinds that replace PR-A's trigger enum (H-DOM-16) include the merge kinds, so the publication planner (H-SVC-04) computes against the latest head, whatever wrote it.
  • Replacement across identities (H-SVC-08, H-DOM-24) is not a model for merge lineage, which the duplicate-merge specification defines separately.
  • The catalogue (D2-15 amended). Copies carry copiedFrom provenance and never overwrite the source. #3934's receipt gains a source.kind (H-IMP-03), and PR-A's subtree-copy algorithm becomes a catalogue-copy input (H-DOM-24).

7.2 Versioning model §12.6, row by row

Versioning model §12.6 now points to this section; its table is otherwise unchanged.

Harvest column.

§12.6 item Still holds? What changes Entries
VersionHistory<T> Yes, narrowed No append-only guarantee; bounded embedded sequences only (policy generations), never revisions, session versions or draft changes H-DOM-01
Typed AnnotationAnswer payload with EnsureCompatible as the §3.6 validity check Yes, adapted Option IDs, response mode, metadata, fail-closed legacy mapping, structural equality; ApplyTransition moves to Avoid H-DOM-02, H-DOM-03
ChildQuestionScope as the repeatable identity property Yes, corrected Fixed at creation, not lazily at the first Multiple publish; it covers only half of the shape (AnswerArray decides multi-select) H-DOM-06
CandidateProjectQuestionSetValidator, CrossQuestionValidationService and AnnotationValidationState as E23 inputs Corrected The first two are composition and content validation (VM §4.2, C4), re-keyed to option IDs, with main's placement rules winning; AnnotationValidationState feeds conversion findings and keeps #2635's guard. E23's fixtures come from #2986. None of them runs on legacy data during conversion H-DOM-13, H-DOM-14, H-VAL-03, C-D09
SystemQuestionFactory as the §3.7 seed builder Yes, adapted Global records keyed (systemGuid, systemQuestionVersion, seq); main's exact text at seq 1; stable option IDs; a parity test. Per-project copies are avoided H-DOM-07, H-MIG-02
AnnotationMutationMapper as an R6 adapter No It maps to PR-A's wrong aggregates and drops time and wording; only FromLegacy and the shape resolution carry H-DOM-02, H-DOM-06, H-DOM-15
ExtractedAnnotationLegacyMapper and MigratedStudyReadModelAssembler as R6 adapters Only with fixes Lossy as written (wording, time, six session fields); for parity and legacy-shaped exports only; the release moves to T-BC-06, before pilots H-MIG-07
MigrationValidationService as a parity check Yes, adapted Legacy against shadow, a persisted report, quarantine instead of throwing, more dimensions; T-BC-06, before pilots H-MIG-06
ExportSpec mode reservation renamed to form-version selectors Yes Modes Current, PreviousVersions and AsOf; previous versions in R2a, as-of in R5a H-API-11

Avoid column.

§12.6 item Still holds? What changes Entries
ReconstructiveRollbackService Yes Joined by the extracted-state activation that erases the originals H-MIG-08, H-MIG-05
RevertToEmbeddedQuestionModel Yes, corrected It is in PR-A's ADR-012 draft, not #2574; PR-C's equivalent is RollbackProjectMigrationAsync H-DOM-12, H-MIG-08
Drafts and question-set versions inside the Project document Yes Joined by single mutable drafts and ageing snapshots anywhere H-DOM-09, H-API-13, H-WEB-01
AQVersion.PublishDecisions, Optional and Multiple placement Yes The decision vocabulary survives as reference for policy records H-DOM-04, H-SVC-05, H-WEB-02
Untyped AnswerOptionFilters Yes The model also has no condition field, so conditions are lost (A-N1) H-DOM-05, H-API-01
Unbounded version arrays in annotation and session documents Yes Six documents, not two (A-N11) H-DOM-15, H-API-10
Annotation identity without entity path, owner scope or population Yes — H-DOM-15
Stage-keyed export selectors; raw AsOfDate Yes Joined by export projections from the latest version H-API-11, H-DOM-21
ReplacementDraftLineagePlanner unless D2-03 keeps D38 Changed RD-R30 (PROPOSAL) makes a type or multiplicity change an incompatible version of the same identity; the planner survives only as a catalogue-copy algorithm, and replacement across identities is avoided H-DOM-24, H-SVC-08

Additions.

  • Harvest: impact counts and the preview digest (H-SVC-01, H-SVC-02); the planner's shape (H-SVC-04) and treatment vocabulary (H-SVC-05); publish preconditions (H-API-02); the save conflict contract (H-API-05); the form-version pin guards (H-DOM-08); provenance value objects (H-DOM-23); the legacy-write guard pattern (H-DOM-19); the conversion plan builder and review extraction (H-MIG-01, H-MIG-04); the export sidecar (H-API-12); #2986's fixtures, codes and detector (H-VAL-02 to H-VAL-04); #2812's response contract (H-VAL-12); the reviewer alert and digest recheck (H-WEB-11, H-WEB-08).
  • Avoid: answer rewriting (H-DOM-03, H-SVC-06 to H-SVC-08); publish transitions that copy status (A-N2); per-stage question sets and stage pins (H-DOM-18); stage transitions, the job and worker, and the review and export locks (H-SVC-11, H-SVC-13, H-API-03, H-API-08); per-project system questions (H-MIG-02); the unguarded backfill (H-MIG-09); statistics writes inside saves and hard deletes in the save path (H-API-09, C-D10); MigrationStatus (H-DOM-20); PR-A's QuestionRef name, which means a version pin there and an identity in the package (H-DOM-23).

8. Sequencing and closure plan

8.1 When each harvest happens

When Slice Entries Tracker row Needs before it starts
M0 (M0-5, docs-only) The QM v2 harvest-and-avoid record, with each adapted and reference entry written into its target row's brief, and the closure notes Every H-DOM, H-SVC, H-MIG, H-API and H-WEB entry; H-WEB-17, H-WEB-19 T-RD-10 G0, the hold lift, the M0 brief
M0 to R0 Writer and reader inventory and read-only dry-run tooling H-DOM-06, H-DOM-07 (parity), H-DOM-14, H-MIG-01 (preview), H-VAL-02; refusal patterns from H-MIG-05, H-MIG-09, H-API-06, H-IMP-03 T-BC-01 M0; the F1a part of T-BC-00; no production inventory without its own approval
F1a ADR drafts C4 definitions part, C5, E23, E37, C18, storage and naming ADRs §5.2 T-RD-01 Final only after M0 go
F-O The C14 ADR H-VAL-12 (units and metadata types) T-RI-11 The F-O part of T-RI-00; T-SI-01 for event counts
R0 Legacy-writer guard pattern H-DOM-19, H-API-06 T-BC-06 (R0 has no row of its own) F1a
R1a Import pipeline: R1a-3 preview and R1a-4 legacy apply H-IMP-01 to H-IMP-09, H-IMP-12 T-RD-11 R1a-1; U19; G0-X9 fixed for R1a-4
R1a Editor hardening: R1a-5, R1a-6 and the tree-reordering part of AC-R1a-12 H-TREE-01 (client warning), H-TREE-02, H-TREE-07, H-WEB-18 (keyboard model) T-RD-12 R1a-1; S0-7; G0-X9 fixed
R1a Catalogue copy H-DOM-24 T-AC-04 ACD §12.5 B5
R1b Read-only Members & groups page H-GRP-13, H-GRP-14 T-AC-11 U8 visibility validation
R1c Group CRUD, grants and dialog H-GRP-01, H-GRP-02, H-GRP-07, H-GRP-09, H-GRP-10, H-GRP-11, H-GRP-12 T-AC-10 X-AUTH-SCHEMA; X-AUTH-ENFORCE or the parity suite; X-AUTH-WP9; Q-03a; X-NOTIF
R2a Versioned forms, sessions, single-editor drafts; the canonical import adapter §5.7; H-TREE-01 (server refusal); H-IMP-02, H-IMP-03, H-IMP-06 (canonical adapter); H-API-11 (previous versions) T-RD-02 F1a, F1b, F1c; R0's staging rehearsal
F2 Publication contract §5.8 T-RD-04 The F2 part of T-RD-00
R2c Publication with impact and the shared impact preview §5.9 T-RD-05, T-UX-06 F2
Staging trials and parity tooling Conversion adapters H-MIG-01, H-MIG-04, H-MIG-06, H-MIG-07, H-DOM-22 T-BC-03, T-BC-05, T-BC-06 R2a and R2b (annotation scope); O1, O2 and AL1 (extraction)
R5a As-of exports H-API-11 T-RI-12 F6a; R4a
X1 Codebook H-API-12 T-RI-08 O1, R4c and R5a
Outside the programme #2986 wiring; flag parsing; the schema-0 test; the WP-M2 preflight query H-VAL-01, H-VAL-06, H-VAL-15, H-GRP-06, H-GRP-05 None (normal triage; #3335 for H-GRP-05); T-RD-14 records G0-D6 G0-D6 for #2986

8.2 When each PR can close

A PR can close only when all four hold: its harvest slice has merged, G0 has passed, the hold is lifted, and Chris has answered its disposition item. Until then it stays open and untouched. GitHub keeps a closed PR's head (refs/pull/<number>/head; checked on 5 October against closed

3969), so the evidence citations in §5 stay readable after closure.

PR group Disposition item Harvest done when Closure row Earliest point
#2461, #2572, #2573, #2574, #2575 G0-D4 T-RD-10 merges T-RD-13 M0-5, before the M0 go or no-go, as G0-D4 recommends
#2224 G0-D5 T-AC-10 merges T-AC-12 R1c. The dossier's first recommendation closes it in W0 (§10, item 3)
#2986 G0-D6 If the deviation is confirmed, this programme does not close it, and only its fixtures and codes are harvested with T-RD-01. If declined, when T-RD-01's E23 corpus merges T-RD-14 F1a, if declined
#2987, #2629, #2812 G0-D7 The F1a C4 ADR draft that cites them merges, with #2812's C14 input recorded for T-RI-11 T-RD-15 F1a ADR drafts
#3934, #2781, #2387 None yet (§10, item 2) T-RD-11 and T-RD-12 merge T-RD-16 R1a

8.3 Order of operations for the out-of-sync QM v2 stack

  1. Never rebase, merge or cherry-pick a stack branch. Every port is a fresh PR from main, written against the target records.
  2. Read PR-A's tip, not its copies. B, C, D and #2461 carry PR-A's squash 36190433d. PR-A's tip af5136696 adds 37 commits of its own (renames, VersionHistory<T>, init-only fields, the validator split), plus 7 merges of main. For any domain type, read the tip.
  3. Isolate each layer's own work against its parent. B is 36190433d..271290115 (one commit). C is 271290115..874a421fb. D is 874a421..71b179c. GitHub's file lists for C and D are dominated by separate main merges; ignore them.
  4. Strip the embedded third-party work. PR-C's 73 #2467-derived files and its #2543 copies are superseded by those PRs' merges; PR-D's AF2 scaffold and presence code are on main. The five assignment-state files PR-C attributes to #2467 are QM's own (C-D12).
  5. Check semantic drift before porting anything that validates or writes: #2635, #2648 and #2651; main's six extra session fields; IAggregateWriteGuard (#3909); FEAT-024 statistics; ADR-020 operations; #3243 export authorisation.
  6. Port in dependency order: F1a contract parts (T-RD-01) and the inventory (T-BC-01); then the R0 guard pattern; R2a (T-RD-02); F2 (T-RD-04); R2c (T-RD-05, T-UX-06); and the conversion adapters for staging trials and parity (T-BC-03, T-BC-05, T-BC-06).
  7. Take new ADR numbers from the programme block ADR-030 to 069 (DOM §11.8). The PRs' numbers (ADR-008 to ADR-012, ADR-016, ADR-017) are all taken on main.
  8. Close the stack together once T-RD-10 has merged and Chris has answered G0-D4: #2461 with #2572 to #2575 (T-RD-13).

8.4 Tracker notes

  • R0 has no tracker row. Audits A and C both found this. The guard pattern (H-DOM-19, H-API-06) is held by T-BC-06 meanwhile. Adding an R0 row is outside this map.
  • The R1b page had no tracker row. The authorization programme tracks only WP1d (the route guard) and WP9 (explanations), so the page itself, the G0 dossier's slice R1b-1, now has T-AC-11.
  • AC-R1a-12 sits in T-RD-12 because the drag and keyboard work is in the editor tree; the G0 dossier lists it under slice R1a-2. The R1a brief fixes one owner.
  • The canonical import adapter is part of T-RD-02 (DS-20), not a row of its own.

9. Effort summary

Assumptions.

  • Each entry carries the audits' grading for the port or adaptation, tests included: S is one day or less, M is one to three days, L is more than three days.
  • The central estimate counts S as 1 day, S–M as 1.5, M as 2 and L as 5. The range counts S as 0.5 to 1, S–M as 0.5 to 3, M as 1 to 3 and L as 4 to 8.
  • Avoid entries and reference entries graded "—" cost nothing to port. Reading them inside their slices is not counted.
  • The estimates exclude the slices that host the ports (T-RD-02 itself, for example), review and CI time, and stack rebases (no PR is rebased; #3934's re-cut on main is counted in its entries). They also exclude the M0 record (T-RD-10, about one to two days) and the closure notes.

By release.

Release Entries S S–M M L — Central (days) Range (days)
M0 2 0 0 0 0 2 0 0
F1a 15 8 0 3 0 4 14 7 to 17
R0 2 1 0 0 0 1 1 0.5 to 1
R1a 14 8 0 4 0 2 16 8 to 20
R1b 2 1 0 0 0 1 1 0.5 to 1
R1c 7 2 0 4 0 1 10 5 to 14
R2a 6 3 0 2 0 1 7 3.5 to 9
F2 9 5 0 1 1 2 12 7.5 to 16
R2c 11 7 0 2 0 2 11 5.5 to 13
Conversion track 7 1 1 3 1 1 13.5 8 to 21
R5a 1 1 0 0 0 0 1 0.5 to 1
X1 1 0 0 1 0 0 2 1 to 3
Outside the programme 5 4 0 1 0 0 6 3 to 7
Not carried (Avoid) 49 — — — — 49 0 0
Total 131 41 1 21 2 66 94.5 50 to 123

By verdict.

Verdict Entries S S–M M L — Central (days) Range (days)
Reuse 6 5 0 1 0 0 7 3.5 to 8
Adapt 41 18 1 20 2 0 69.5 37.5 to 97
Reference only 35 18 0 0 0 17 18 9 to 18
Avoid 49 0 0 0 0 49 0 0
Total 131 41 1 21 2 66 94.5 50 to 123

Inside the programme the central estimate is 88.5 days. The two largest single items are PR-B's planner rewrite (H-SVC-04) and PR-C's review-state extraction (H-MIG-04), both L.

10. Open questions

Only owner-level questions are listed. None blocks a brief.

# Question Recommendation Can it wait?
1 G0-D6, with a corrected premise. The dossier keeps #2986 open because "it fixes today's legacy writes". It fixes none yet: nothing calls its validator, and the #2467 blocker has merged. Legacy writes still last until R7, which has no date, and every invalid legacy answer becomes a conversion finding at R6 Confirm the deviation with this corrected rationale: keep #2986 open outside the programme and treat its wiring (H-VAL-01, H-VAL-06) as a legacy-integrity fix rather than feature work. Chris could then approve that fix separately from the feature hold; this map approves nothing. Harvest its fixtures and codes either way (H-VAL-02 to H-VAL-04). The coordinator updates the dossier Yes, until the G0 sitting. If Chris wants the integrity fix sooner, it is his separate decision
2 Who closes #3934, #2781 and #2387, and when? No G0 item covers them; the dossier only says R1a-1 audits them Add a disposition item: Stream A's lead closes each with its harvest note after its R1a slice merges. #3934 closes as superseded when its split R1a-3 and R1a-4 PRs merge (T-RD-16) Yes, until R1a-1 is done
3 G0-D5 timing for #2224. The dossier's first recommendation closes it in W0 with a harvest note; its alternative keeps it open until R1c The alternative: keep it open until T-AC-10 merges, as this map's rule says. Closing earlier gains nothing, and GitHub keeps the head either way Yes, until the G0 sitting

Brief items, not owner questions. These go to the named rows' briefs:

  • AC-R1a-01 promises a lookup remap that neither import PR has: implement it or refuse lookups and amend the criterion (T-RD-11).
  • A file import should count as a copy for AC-R1a-08, with source.kind = file (T-RD-11, ACD §12.5 B5).
  • AC-R1a-04 should say "never changes existing question content", because the legacy writer appends a new child's ID to its parent (T-RD-11).
  • E37 settles whether a metadata-only response is allowed (V-D3, T-RD-01).
  • D2-03 decides whether a type or multiplicity change ever needs a new identity, which is the only case that would revive H-DOM-24 as a versioning mechanism (T-RD-01).
  • G0-X9 places R1a-4 to R1a-6 under a gate (T-G0).