Skip to content

Read-only audit of #2572 at af5136696 and #2461 at 1ca9f5def. Saved verbatim as evidence for the harvest map. Feature implementation is on hold; nothing was ported, rebased or closed.

Harvest audit: QM v2 PR-A domain foundation (#2572) and umbrella (#2461)

Read-only audit, 5 October 2026, against main at 7673ed0d3 and the planning package on pr4061 (bc0c94734). Nothing was checked out, fetched, committed or commented. Path abbreviations: Core/ = src/libs/project-management/SyRF.ProjectManagement.Core/, QV/ = Core/Model/QuestionVersioning/, Tests/ = src/libs/project-management/SyRF.ProjectManagement.Core.Tests/. SHAs: A = af5136696, #2461 = 1ca9f5def, main = 7673ed0d3.

1. Scope and state

1.1 #2572 (PR-A), head af5136696, base main

Area Files Added lines Content
Domain and services (C#) 37 5,314 QV/ (AnnotationQuestionV2, AQVersion, DraftQuestion and tree, DraftSnapshot, ProjectQuestionSet, StageQuestionSet, VersionHistory, value objects, ChildQuestionScope, MigrationStatus); extracted Annotation, AnnotationSession, OutcomeData aggregates; AnnotationAnswer; services (SystemQuestionFactory, QuestionPublishCandidateBuilder, CrossQuestionValidationService, candidate validators, rule codes, ReplacementDraftLineagePlanner, mutation mappers, SessionTransitionService stub); edits to Project.cs, Stage.cs, AnnotationQuestion.cs, AnnotationRelationshipValidator.cs; 7 class-map lines in ProjectRepository.cs
Tests 19 3,887 169 new test methods under Tests/QuestionVersioning/ and Tests/Validation/, 2 BSON round trips, an API validator test edit
Docs and scripts 11 1,082 ADR-010 (renames), ADR-011 (two-level drafts), ADR-012 DRAFT (QuestionManagement entity), ubiquitous-language.md, glossary, scripts/apply-qm-renames.sh
  • No generated files, no API, no web, no migration, no repositories beyond the Project class map. The real size is the 67 files above (+10,283/−184). Nothing is wired to an endpoint.
  • Relation to its base. Merge base with main is b47f5c59c (25 April 2026). The branch holds the squash 36190433d (17 April) plus 44 later commits (37 non-merge, 7 main merges), last commit 26 April. GitHub's updatedAt of 1 September is metadata only.
  • Stack sync (verified). #2573, #2574 and #2575 contain 36190433d but not 4b5c6a8d32, the first later A commit. VersionHistory.cs exists only at A's tip. B, C, D and #2461 carry the same blobs as 36190433d for AnnotationQuestionV2.cs (0253500), Annotation.cs (69494e4) and SystemQuestionFactory.cs (b76cc0d); A's tip has 6558874, 7c744d9 and da0b1e3.
  • Drift with main. 6,855 main commits since the merge base; Project.cs 57 commits (+506), Stage.cs 23 (+397), AnnotationQuestion.cs 8 (+99). A legacy git merge-tree finds 14 conflict hunks in 6 files (CLAUDE.md, docs/decisions/index.md, mkdocs.yml, Project.cs, Stage.cs, AnnotationRelationshipValidator.cs) and 3 modify/delete conflicts: main deleted docs/features/advanced-screening-filtering/terminology.md, screening and filtering/screening-annotations-feature-spec.md and user-guide/glossary.md in #2398 (14f2dd375, 4 May). All three ADR numbers are taken on main (ADR-010 S3 notifier, ADR-011 schema-v0 conditional parents, ADR-012 bulk PDF).
  • Semantic conflicts git does not flag (all three confirmed, §3). #2635, #2648, #2651.

1.2 #2461 (umbrella, draft, DO-NOT-MERGE), head 1ca9f5def

Against its merge base de8e312ad (24 April): 437 changed files plus 2 deletions, +77,083/−5,462, 309 commits from 20 March to 24 April (GitHub shows 738 files against today's main). A blob-by-blob comparison of every changed path against the A, B, C and D tips and main:

Result Files Detail
Byte-identical to a stack tip or main 419 204 in C and D only, 145 in D only, 29 in B to D, 15 in A to D, 1 in A, C and D, 25 also or only on main
Different everywhere 18 11 infra and config drift (syrf.sln, angular.json, Quartz files, checksums, mkdocs.yml, dependency map, app-config template); 5 docs/features/question-management/planning-archive/* files; older copies of m011-signalstore-integration-plan.md (2-line diff to D), annotation-impact.service.spec.ts (D adds session counts and fingerprint) and e2e/tests/session-lifecycle.spec.ts (main renamed to SlotReservations)

The planning archive's decisions D001–D012 and knowledge K001–K019 are all present on main in docs/planning/qm-v2-context/qm-v2-architecture-and-knowledge.md, with the 101-requirement tracker beside it. #2461's domain code is the pre-A-tip squash level. Nothing in #2461 is of value that is not already in #2572–#2575 or on main. It lacks every later A fix (§3 lists what those fixed).

1.3 Mapping to the RD specification and contracts

RD / contract concept Nearest A component Gap that decides the verdict
Question definition and version (RD §3.4, VM §3.1–3.3, C4) AnnotationQuestionV2 + embedded AQVersion list Versions embedded in the question; options keyed by value, no optionId; no condition field; DataType/AnswerArray frozen as identity (D2-03 makes them version content); Optional/Multiple on the version; no definitionOwner, entityTypeId or systemQuestionVersion identity
Compatibility classes (VM §3.5, D2-02 amended, RD-R20) ChangeImpactClassification, advisory BreakingChange, PublishDecision on AQVersion No classSeq, no compatibility {suggestedBySyrf, declared, declaredBy, declaredAt, rationale}; the draft decision is mutable until publish and stored per publish, not immutable on the version
Option mapping (Q-34, RD-R21) OptionMapping(OldValue, NewValue), ApplyTransition(Map) Value strings, no option IDs, no source-revision provenance
Form and form version with standardTarget and ReconciliationPolicy (RD §3.5, OS-A12) ProjectQuestionSet + PQSVersion (one per project) and StageQuestionSet + SQSVersion (one per stage) No form entity; no target, requiredness, ancestor closure, applicability graph or renderability in any version; the target stays Stage.SessionCountTarget
Design drafts (RD §3.7, OS-A01, D2-11) DraftContent on each question, DraftPQS, DraftSQS, DraftQuestion list on Project, GFS DraftSnapshot One mutable draft per item, overwritten by autosave; no base revision, change log, conflicts or presence
Session and session versions (RD §3.9, C5) extracted AnnotationSession Keyed by stage with a random ID; embedded versions; no draft; kinds are triggers (ReviewerSubmit, AdminPublish, Reconciliation, Migration)
Answer heads and revisions (C1, C2, VM §6) extracted Annotation One document per legacy annotation ID with embedded versions; no AnswerContextKey; locked to one session lineage
Publication-generated versions (D2-01 amended, RD §3.15) TryApplyPublishTransition on Annotation, AnnotationSession, OutcomeData Writes versions without operation, generation or CAS attribution; copies status; clears answers on re-answer
System questions as versioned data (D2-06, RD-R32, VM §3.7) SystemQuestionFactory Per-project documents with the system GUID as _id; seed text edited
Legacy-writer refusal on canonical scopes (C16, E49) ThrowIfMigratedForLegacy* on Project and Stage Keyed by a per-project MigrationStatus, with a destructive rollback

1.4 What the owner-session decisions change for A

  • Target inside the form version (OS-A12, RD-R12). A has no form-level target. Harvested pieces must hang off AnnotationFormVersion, which gains standardTarget and ReconciliationPolicy from the first canonical form (T-RD-01). A's stage-level SessionCountTarget, EnforceAnnotationTarget, IdleSessionTimeoutMinutes and MaxInProgress path is doubly superseded: main already has these fields, and D2-07 moves timeout and in-progress limit to the form.
  • Collaborative drafts (OS-A01). Every A draft type is a single mutable record. Only the operations catalogue survives as reference for DesignDraftChange item kinds. A's own ADR-011 anticipated an append-only autosave trail, but its GFS ageing contradicts "changes are never edited" (RD §3.7) and the reconstructable session draft log (RD §3.10).
  • Publication generates attributable session versions (D2-01 amended). This rehabilitates A's idea that publication writes session versions (AdminPublish), which the round-2 rule had rejected. A's implementation still breaks RD-R23 (status copied, answers cleared, no attribution or CAS), so it stays reference only.
  • Stage study filter replaces per-stage question sets (SP-R01, RD-R04, RD-R31). StageQuestionSet, SQSVersion, StagePublishDecisionSummary and the StageQuestionSetVersionReference pinned on every annotation and session version have no target. A stage binds a form identity, and route provenance sits on session versions only.
  • Universal faithful conversion (OS-A14, OS-A15, BC-R01, BC-R27, BC-R29). MigrationStatus with RolledBack and re-migration assumes an opt-in, reversible per-project mode. BC has one engine, routing rollback only before the first canonical write, and forward recovery after it. The legacy-mutation guards survive as a pattern for the CanonicalScopes checks. The mapping helpers must fail closed (BC-R08, BC-R26) instead of defaulting unknown types to strings.

1.5 Corrections to versioning-model §12.6

  1. VersionHistory<T> gives no append-only guarantee. It wraps a mutable embedded List, and BSON round trips or the generic ReplaceOne still rewrite it (§12.2). It fits only bounded embedded sequences such as IssuePolicyRecord generations, never revisions, session versions or draft changes.
  2. CandidateProjectQuestionSetValidator and CrossQuestionValidationService are composition and content validation (VM §4.2, C4 "Composition and renderability"), not E23 applicability inputs. They validate against live or latest option values, so they need re-keying to pinned option IDs.
  3. AnnotationMutationMapper maps to A's aggregates, which have the wrong target shape. Only AnnotationAnswer.FromLegacy and AnnotationQuestionState's shape resolution are worth carrying into R6 adapters.
  4. ChildQuestionScope is lazily committed at the first Multiple publish. As the repeatable identity property it must be fixed at creation, and it covers only half of the shape (AnswerArray decides multi-select).
  5. Add to Avoid: AnnotationAnswer.ApplyTransition; publish transitions that copy session status; single-session lineage on answers; per-stage question sets and stage-version pins on evidence; single mutable drafts and GFS snapshots; system seeds stored per project with the system GUID as _id; seed-text edits at seq 1; export projections built from LatestVersion; A's QuestionRef name, which means a version pin, whereas the package's QuestionRef is an identity.

2. Harvest entries

ID PR Component (type or file at SHA) What it does Verdict Why (rule IDs, decisions) Target (spec §, contract, release, tracker row) Adaptation needed Tests to carry Effort Evidence (path:line @ short SHA)
H-DOM-01 #2572 VersionHistory<T> Append facade over an embedded list: Latest, NextVersionNumber, Append Adapt §12.6 harvest, narrowed by §12.1–12.2 (revisions, session versions and draft changes live in append-only collections; IAppendOnlyRepository) VM §8.3 policy generations inside FormVersionIssue; C4; F2; T-RD-04 Use only for bounded embedded sequences; enforce immutability in the repository and architecture test, not the facade None exist; write facade tests S QV/VersionHistory.cs:18-58 @af51366
H-DOM-02 #2572 AnnotationAnswer records, EnsureCompatible, FromLegacy Typed answer payload per value type and array shape; shape check; legacy-to-typed mapping Adapt VM §3.4 (value XOR responseModeId + metadata), §3.3 rule 2 (option IDs), §3.6 step 2; C1 revision payload; BC-R08, BC-R26 C1, C2; VM §6.3; F1a payload value object 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; structural equality for list payloads AnnotationAnswerTests: 3 EnsureCompatible_*, FromLegacy_*, 8 *_CopyAndClear / display M Core/Model/AnnotationAggregate/AnnotationAnswer.cs:19-44,89-103 @af51366
H-DOM-03 #2572 AnnotationAnswer.ApplyTransition, AnswerHandlingStrategy, OptionMapping(OldValue, NewValue) Keep copies, Map remaps strings, ReAnswer clears Avoid RD §3.15 (re-answer keeps pins and shows Needs updating), RD-R21 and Q-34 (new revision on the same head with {sourceRevisionId, mappingRef, operationId, generation}); null mapped to "" RD §3.15, §4.8; C4 publication command; T-RD-04, T-RD-05 Not ported; mapping is rebuilt on option IDs as a revision writer ApplyTransition_Map_* only as mapping fixture inputs — AnnotationAnswer.cs:46-87 @af51366
H-DOM-04 #2572 PublishDecision, DraftPublishDecision, ChangeImpactClassification, AQVersion.BreakingChange, StagePublishDecisionSummary Per-question impact decision drafted by autosave, promoted at publish, stored on the question version and per stage Reference only D2-02 amended and RD-R20 (immutable publisher declaration on the version); §12.6 avoids AQVersion.PublishDecisions; VM §8.2–8.3 (per-question treatment and per-category counting in IssuePolicyRecord) RD §3.4, §4.8; VM §3.5, §8.2; C4; F2 T-RD-04 Vocabulary only: classification maps to the declaration and strategy to treatment; add added, removed and requiredness classes plus categories PromoteDraftPublishDecisions_* (3) as cases — QV/VersioningValueObjects.cs:101-171 @af51366; QV/AQVersion.cs:65-68
H-DOM-05 #2572 AnnotationQuestionV2, AQVersion, QuestionOptionV2, AnswerOptionFilter, DraftContent Published question aggregate with init-only structure, embedded version list and one pending draft Reference only VM §3.1–3.3, §12.1 (pmQuestionDefinitionVersion); D2-03 PROPOSAL; VB-17 (requiredness is form-owned); DD-12 (EntityTypeId); D2-15 amended (catalogue copiedFrom replaces Scope/OwnerProjectId); no condition field (§3, N1) RD §3.4; C4; R2a; T-RD-01, T-RD-02 Keep the identity/content split, init-only identity, never-delete (QD1), StartDraftFromVersion as "seed a design draft from an older version"; rename A's QuestionRef QuestionVersioningTests publish, no-draft, independence cases as FX-VM ideas — QV/AnnotationQuestionV2.cs:15-135,197-221,335-351 @af51366
H-DOM-06 #2572 ChildQuestionScope, AnnotationCollectionMode, AnnotationQuestionState.ResolveCollectionMode/ResolveValueType Maps legacy AnswerArray/Multiple/DataType to single, multi-select array or repeated instances Adapt VM §3.1 (repeatable = Multiple && !AnswerArray, identity), D2-03 (multiplicity is version content, always incompatible); C2 instance element in entityPath VM §3.1, §11; C2; T-BC-01 and T-BC-03 mapping; T-RD-01 identity Fix repeatable at creation (no lazy commit); unknown DataType fails closed; one mapping table shared by BC and the designer ChildQuestionScopeTests (4); add a mapping-table test S Core/Model/AnnotationAggregate/Annotation.cs:489-549 @af51366; QV/ChildQuestionScope.cs:28-35; QV/AnnotationQuestionV2.cs:80-99
H-DOM-07 #2572 SystemQuestionFactory (18 definitions with per-SystemQuestionVersion parent and option resolvers) Builds system questions from code for a project Adapt D2-06, RD-R32, VM §3.7 rules 1–2 and §11 system row (seed for seq 1 is today's definition) pmSystemQuestionVersion seed; C4 system row; T-RD-01 (D2-06 contract), T-RD-02; parity input to T-BC-01 Write global records keyed (systemGuid, systemQuestionVersion, seq) with a structural digest, never per-project documents with the GUID as _id; restore main's exact text at seq 1 (A's double-space fix becomes a later version); mint stable option IDs (main keeps candidate GUIDs commented out); add a parity test against main's AnnotationQuestion.SystemQuestions (#2651 anchor split) SystemQuestionFactoryTests: GUIDs, v0/v1 error-type variants, cohort parents; drop the no-double-space test for seq 1 M Core/Services/SystemQuestionFactory.cs:18-50,119-127,171-187 @af51366; main Core/Model/ProjectAggregate/AnnotationQuestion.cs:417-421,724,739 @7673ed0
H-DOM-08 #2572 ProjectQuestionSet.Publish, PQSVersion Appends an ordered snapshot of (questionId, versionId) pins; refuses empty IDs and duplicates; copies the input Adapt VM §4.1 (ordered pins, one version per question, A-26), FV1; OS-A12 AnnotationFormVersion pins; RD §3.5; C4; R2a T-RD-02 Per form, not a project singleton; add requiredness, minimum instances, ancestor closure, applicability graph, renderability, standardTarget, ReconciliationPolicy; store in pmAnnotationFormVersion, not in Project Publish_ShouldAppendVersionWithRefs, Publish_ShouldSnapshotOrderedRefs_CallerMutationDoesNotAffectPublishedVersion, duplicate refusal S QV/ProjectQuestionSet.cs:167-198 @af51366
H-DOM-09 #2572 DraftPQS, DraftSQS, DraftQuestion, DraftQuestionTree, DraftContent, DraftSnapshot (GFS), Project and Stage class-map lines Single mutable designer drafts embedded in Project and each question, with ageing snapshots Avoid OS-A01 and D2-11 (many drafts, append-only DesignDraftChange with base revision, recoverable conflicts); RD §3.7 (changes never edited); §12.6 (no drafts in Project) RD §3.7, §4.7; VM §3.9; C4; T-RD-02 (single editor), T-RD-05 (collaborative) Not ported; reuse the operation list (add, remove subtree, reorder, promote, withdraw, fork) as change item kinds DraftQuestionTreeTests, ProjectDraftQuestionsTests as cases — QV/DraftSnapshot.cs:9-84 @af51366; QV/AQVersion.cs:79-92; Core/Model/ProjectAggregate/Project.cs:109-218
H-DOM-10 #2572 ADR-011 (A) two-level draft and formal versioning Autosave trail vs explicit Save or Publish; session not mirrored Reference only Anticipates RD §3.10 and VM §7.7; GFS retention and per-annotation drafts conflict with them; number taken on main F1a storage ADR rationale; T-RD-01 Cite in the storage ADR; never merge — — 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 Rename table (39 rows; high-risk renames deferred) and glossary Reference only Superseded by domain-model §8 and the F1a naming ADR; ADR-010 number collides domain-model §8; naming ADR; T-RD-01 Use as an old-to-new name key when reading dormant code — — docs/decisions/ADR-010-qm-v2-ubiquitous-language-renames.md:39-79 @af51366
H-DOM-12 #2572 ADR-012 DRAFT QuestionManagement entity inside Project Keeps definitions in the Project aggregate with mode history and RevertToEmbeddedQuestionModel Avoid domain-model §5 (questions leave Project); §12.6 and AC-M0-04 (no destructive rollback); BC-R27 — Verb taxonomy only, as input to domain-model §6.3 command names — — docs/decisions/ADR-012-DRAFT-question-management-entity-extraction.md:34-60 @af51366
H-DOM-13 #2572 CandidateProjectQuestionSetValidator, CandidateStageQuestionSetValidator, QuestionPublishCandidateBuilder, CrossQuestionValidationService, QuestionValidationRuleCodes (AQ001–AQ017) Publish-time content, option-filter, cycle, placement and stage-subset checks with typed codes Adapt VM §4.2 (resolve against the pinned parent version by option ID), §4.3; C4 composition; #2648 and #2651 (main's placement rules win) VM §4.2–4.3; C4; F1a C4 part T-RD-01; R2a T-RD-02 Build the candidate from a design draft plus pinned versions; re-key filters to option IDs; replace A's placement copy with main's AnnotationQuestionPlacementRules/Validator; turn the stage-subset rule into ancestor closure; namespace the codes against main's FL/NQ codes; keep FormVersionNotRenderable separate CrossQuestionValidationServiceTests (9), QuestionPublishCandidateBuilderTests (3), QuestionValidationRuleCodesTests (2) M Core/Services/Validation/CandidateProjectQuestionSetValidator.cs:21-60,136-182,231-256 @af51366; Core/Services/QuestionValidationRuleCodes.cs:11-59
H-DOM-14 #2572 AnnotationRelationshipValidator over AnnotationValidationState/OutcomeDataValidationState Decouples tree, conditional and lookup checks from embedded annotation classes Adapt Useful for BC dry-run findings (BC §4.2) and the R0 legacy floor; canonical E23 is option-ID and entity-path based (VM §3.6) BC §4.2; C16; T-BC-01 Rebase on main's validator, keeping #2635's DuplicateAnnotationId guard; populate ChildIds in FromExtracted AnnotationRelationshipValidatorProjectionTests (2); main's validator tests stay authoritative S Core/Services/Validation/AnnotationRelationshipValidator.cs:43-60 @af51366; Core/Services/Validation/AnnotationValidationState.cs:32-42; main same validator :56 @7673ed0
H-DOM-15 #2572 Extracted Annotation aggregate, AnnotationVersion, AnnotationStructure/SubmissionState/VersionState, AnnotationMutationMapper One document per answer with embedded versions, each pinning session, question and stage versions Avoid C1 and VM §6.3 (heads and revisions in separate collections); C2 (AnswerContextKey with author scope, definition owner, classSeq, entityPath, population); RD-R04 and RD-R31 (no stage pins on evidence); §12.6 and AC-M0-04 (no unbounded embedded arrays); no command ID, HLC or digest C1, C2; VM §6; R2a T-RD-02 Not ported; keep the ideas of factory-fixed identity, a collection-mode invariant across versions (I1) and legacy ID preservation (LegacyIdAlias) AnnotationAggregateTests (12), ExtractedReviewVersioningTests (13) as C1-T ideas — Core/Model/AnnotationAggregate/Annotation.cs:15-66,343-368,440-457 @af51366
H-DOM-16 #2572 Extracted AnnotationSession, AnnotationSessionVersion, AnnotationSessionVersionTrigger Per-stage session; each version lists all annotation and outcome version references; status projected from the latest version Reference only Matches the full pin map (VM §7.2, C5 E28) and status as a fact of the latest explicit version (C5); conflicts with RD-R04 and C5 E27 (Study × form, deterministic ID), VM §7.1 (reconciler is not a FormSession), SL1 (no draft), RD-R23 C5; RD §3.9; VM §7.1–7.3; T-RD-02, T-RD-04 Pin-map shape and derived-status rule only AnnotationSessionAggregateTests (10) as cases — Core/Model/AnnotationSessionAggregate/AnnotationSession.cs:20-63,326-359 @af51366
H-DOM-17 #2572 TryApplyPublishTransition (Annotation, AnnotationSession, OutcomeData), CreatePublishTransitionReplacement Appends a publish-triggered version unless the state is unchanged; can spawn a replacement annotation Reference only D2-01 amended and RD §3.15 (the generation table decides; CAS on the session head; deterministic ID per (sessionId, operationId, generation); publisher attribution; never an invalid Complete); replacement IDs are D38 lineage (RD-R30) RD §3.15, §4.8 phase 2; consistency §4.2; C4, C5; F2 T-RD-04 Keep "no version when nothing changes" as the no-generation rows — — Annotation.cs:270-341 @af51366; AnnotationSession.cs:253-324
H-DOM-18 #2572 StageQuestionSet, SQSVersion, StageQuestionSetVersionReference, Stage.AnnotationQuestions projection Per-stage question subsets and stage-version pins on evidence Avoid SP-R01 (stage filter defines the pool), RD-R04, RD-R31 (stage binds form identity); the projection silently returns the latest SQS for migrated projects SP §3.3; BC-R15 (legacy stage sets are conversion input only); T-SP-03, T-BC-03 Not ported — — QV/StageQuestionSet.cs:38-150 @af51366; Core/Model/ProjectAggregate/StageEntity/Stage.cs:128-147
H-DOM-19 #2572 ThrowIfMigratedForLegacyMutation/Projection on Project and Stage Refuses legacy question writes and projections once a project is in the new mode Adapt C16 E49: legacy aggregate methods check CanonicalScopes C16 (R0 floor); integrated-plan §5 R0 item 3; T-BC-06 (no R0 row exists) Key on the CanonicalScopes marker per scope (Project and Study) with IAggregateWriteGuard, not on MigrationStatus LegacyQuestionManagementBoundaryTests (6) as the pattern S Core/Model/ProjectAggregate/Project.cs:643-660 @af51366; Stage.cs:318-326
H-DOM-20 #2572 MigrationStatus, Mark/ApplyMigratedQuestionManagement, Mark/ApplyRolledBackQuestionManagement Opt-in per-project mode with rollback that discards the PQS and SQS history and allows re-migration Avoid AC-M0-04 (no destructive rollback or hand-back); BC-R01, BC-R27, BC-R28, BC-R29 BC §4.9 Not ported — — Project.cs:221-285 @af51366
H-DOM-21 #2572 AnnotationQuestion.CreateExportProjections, CreateOrdered*ExportProjections Projects v2 questions back into legacy AnnotationQuestion from LatestVersion for exports Avoid C11 and VM §10.2 (exports resolve pinned versions and carry option IDs); §12.6 (no stage-keyed export selectors); drops conditions (TargetDto(parent, null)) C11; T-RI rows Not ported — — Core/Model/ProjectAggregate/AnnotationQuestion.cs:193-283 @af51366
H-DOM-22 #2572 Extracted OutcomeData, OutcomeDataMutationMapper Versioned outcome rows referencing experiment, cohort and outcome annotations Reference only C14 (observations on instance IDs); BC-R19 (untouched defaults become ValueOrDefaultUnknown; A copies values verbatim) C14; BC §3.4; T-BC-05 Field inventory only OutcomeDataMutationMapperTests (4) as cases — Core/Model/OutcomeDataAggregate/OutcomeData.cs:15-45,382-417 @af51366
H-DOM-23 #2572 VersionAudit, typed VersionReference records, VersionChangeReasons Provenance record and typed cross-aggregate version references Adapt C1 and C3 provenance (real actor, effective author, operation, command ID, HLC, digest); VM §12.3–12.4 (I1, I2) F1a value objects; C1, C3; T-RD-01 Extend the audit; typed references back the integrity checker; rename QuestionRef (a pin in A, an identity in the package) — S QV/VersioningValueObjects.cs:11-95 @af51366; QV/VersionChangeReasons.cs:9-21
H-DOM-24 #2572 ReplacementDraftLineagePlanner, DraftPQS.ReplacePublishedSubtree Clones a published subtree into new drafts with rewired parents and an old-to-new ID map (injected ID factory) Reference only Not the versioning mechanism (RD-R30, D2-03; §12.6); the algorithm fits catalogue copy (VM §4.5, ACD §3.4: copies are new identities with copiedFrom) ACD §3.4; T-AC-04 Algorithm and deterministic tests as input to catalogue copy ReplacementDraftLineagePlannerTests (6) as cases — Core/Services/ReplacementDraftLineagePlanner.cs:10-70 @af51366; QV/ProjectQuestionSet.cs:68-105
H-DOM-25 #2461 Domain, service, API and web code of the umbrella The same as B, C or D, or older than A's tip Avoid Superseded by #2572's tip and #2573–#2575; blob comparison in §1.2 — Nothing to port — — Blob comparison: 419 of 437 changed paths byte-identical to a stack tip or main; e.g. QV/AnnotationQuestionV2.cs blob 0253500 equals 36190433d, B and C @1ca9f5d
H-DOM-26 #2461 docs/features/question-management/planning-archive/*, older annotation-impact.service.spec.ts, older session-lifecycle.spec.ts Planning archive and stale copies Avoid Superseded by main's docs/planning/qm-v2-context/ (D001–D012, K001–K019), D's newer spec and main's renamed e2e spec — Nothing to port — — planning-archive/decisions.md @1ca9f5d; main docs/planning/qm-v2-context/README.md @7673ed0

Counts (26 entries): Reuse 0; Adapt 9 (H-DOM-01, 02, 06, 07, 08, 13, 14, 19, 23); Reference only 8 (04, 05, 10, 11, 16, 17, 22, 24); Avoid 9 (03, 09, 12, 15, 18, 20, 21, 25, 26). Nothing ports as is: every adapted piece needs option IDs, pinned versions, form scope or fail-closed mapping first.

3. Defects not to carry over

Known facts, checked.

Fact Result Evidence
B, C and D sit on A's squash; A has "about 51" later commits Confirmed, corrected to 44 (37 non-merge, 7 merges) git rev-list 36190433d..af5136696; merge-base --is-ancestor 4b5c6a8d32 fails for B, C and D
#2635 duplicate-annotation-ID guard Confirmed: A's loop overwrites in-payload duplicates silently; main rejects them A AnnotationRelationshipValidator.cs:56-60; main :41-63 (8c67a0b86)
#2648 Study under custom Study parent Confirmed: A emits AQ009 for any parented Study question A CandidateProjectQuestionSetValidator.cs:231-238; main AnnotationQuestionPlacementValidator.cs:54-87
#2651 anchor split Confirmed: A treats any system parent as first-level A CandidateProjectQuestionSetValidator.cs:242; main AnnotationQuestionPlacementRules.cs:156, AnnotationQuestionPlacementValidator.cs:80
C's system-question _id collision Root cause is in A: the factory passes the fixed GUID as the aggregate ID per project SystemQuestionFactory.cs:28-29; AnnotationQuestionV2.cs:288-312
B's transition never rebases type or shape Consistent: A's primitive only copies, remaps strings or clears, and EnsureCompatible throws on a changed shape AnnotationAnswer.cs:27-57; Annotation.cs:351
PR-A's ADR-010 collides with main Confirmed and extended: ADR-011 and ADR-012 also collide main docs/decisions/ADR-010..012-*

New defects found at A's tip.

ID Defect Evidence @af51366
N1 Conditional-parent applicability is lost. The v2 question model has no field for Target.ConditionalParentAnswers; CreateMigratedFromEmbedded sets answerOptionFilters: null; C's converter never reads conditions (and "repairs" missing parents, against BC-R26's no-lossy-conversion rule) QV/AQVersion.cs:10-68 (no condition field; AnswerOptionFilters untyped at :56); QV/AnnotationQuestionV2.cs:255-286; #2574 Core/Services/ProjectQuestionMigrationDomainService.cs:132-165 @1b93cbb
N2 A publish-triggered session version copies the latest Status, so it can stay Completed after re-answer cleared answers (against RD-R23) AnnotationSession.cs:264-277
N3 ReAnswer clears the answer in the new version rather than keeping the pin and flagging it AnnotationAnswer.cs:54
N4 Mapping turns a null string answer into "" AnnotationAnswer.cs:78-83
N5 No-op detection compares record payloads holding List<T> by reference, so array answers always append a spurious version Annotation.cs:288-295; AnnotationAnswer.cs:138-174
N6 Unknown legacy annotation types become strings, and unknown data types become String, instead of failing closed AnnotationAnswer.cs:101; Annotation.cs:547
N7 System seed descriptions were edited ("double-space fix", 34171c104), so seq 1 would not equal production definitions SystemQuestionFactory.cs:119-127 vs main AnnotationQuestion.cs:724,739
N8 Rollback discards all PQS and SQS history; MarkQuestionManagementMigrated accepts RolledBack → Migrated Project.cs:221-283
N9 FromExtracted passes no child IDs, so the child-resolution check is skipped for extracted answers AnnotationValidationState.cs:32-42
N10 Stage.AnnotationQuestions silently switches to the latest SQS for migrated projects, so legacy readers see a set no session pinned Stage.cs:128-142
N11 Unbounded embedded version arrays in six documents (question, PQS, SQS, annotation, session, outcome) AnnotationQuestionV2.cs:119; ProjectQuestionSet.cs:149; StageQuestionSet.cs:77; Annotation.cs:44; AnnotationSession.cs:38; OutcomeData.cs:38

4. Superseded by main since the PR was written

  • Validator hardening: #2635 (b509595e6, 8c67a0b86, 11 May) owns the overlap and duplicate rules A rewrote.
  • Placement rules: #2648 (merged 19 May) and #2651 (1c39bbab0, 19 May) moved to AnnotationQuestionPlacementRules/AnnotationQuestionPlacementValidator; A's validator copies the older rules.
  • Stage capacity fields: EnforceAnnotationTarget, IdleSessionTimeoutMinutes, StageUpdateDto fields and AnnotationStageSettings are on main (Stage.cs:18,53-81,335-346,464 @7673ed0). A's Stage.cs and StageUpdateDto.cs edits duplicate them, and D2-07 moves them to the form.
  • Docs: #2398 (14f2dd375) deleted the three docs A edits and added docs/planning/qm-v2-context/, which preserves #2461's planning archive.
  • ADR numbers 010–012 were used on main for unrelated decisions.
  • Active-reviewer e2e: main's e2e/tests/session-lifecycle.spec.ts (79cf01ab5, 8f9659847) supersedes #2461's copy.

5. Closure-note drafts (for use after the hold lifts and G0-D4 is decided; not authorised now)

#2572. Harvested under Q-08 into the integrated review plan. Ideas ported in adapted form: the typed answer payload and its shape check, the legacy question-shape mapping, the system-question definitions as the global seed, the form-version pin guards, the composition rules and AQ rule codes, the legacy-write guard pattern, and the provenance and version-reference value objects. They now sit under T-RD-01, T-RD-02, T-RD-04, T-BC-01 and T-BC-06. Not carried: the extracted Annotation and AnnotationSession aggregates (embedded version arrays, stage-keyed), per-stage question sets, single mutable drafts, publish transitions that clear answers or copy status, and rollback to the embedded model. ADRs 010 to 012 stay as reference only, because their numbers are taken on main.

#2461. This umbrella was split into #2572–#2575. Every changed file is byte-identical to a file in that stack or on main, or is an older copy. Its planning context is preserved on main in docs/planning/qm-v2-context/. Nothing further is harvested. Close it with the stack.

6. Proposed tracker rows

Attach to existing rows where possible:

Row Attach Acceptance evidence to add
T-RD-01 (F1a) H-DOM-02 payload value object, H-DOM-06 shape mapping, H-DOM-07 D2-06 seed contract, H-DOM-23 provenance and reference value objects; H-DOM-10 and H-DOM-11 as ADR inputs RD-AE29 (D2-03, D2-06 fixtures) plus a seed-parity fixture: seq 1 equals main's system definitions for every SystemQuestionVersion
T-RD-02 (R2a) H-DOM-08 form-version pin guards, H-DOM-13 composition validation with option IDs C4-T conformance; the #2648 and #2651 cases pass through the new composition validator
T-RD-04 (F2) H-DOM-01 for policy generations; H-DOM-03, H-DOM-04 and H-DOM-17 as reference RD-AE16 includes N2 and N3 as negative fixtures
T-BC-01 H-DOM-06, H-DOM-14, H-DOM-07 parity The dry run reports N1-type loss: every legacy conditional parent maps to an option-ID condition, or is a manifest exception
T-BC-06 H-DOM-19 guard pattern (R0 has no tracker row) LegacyQuestionManagementBoundaryTests pattern rekeyed on CanonicalScopes
T-AC-04 H-DOM-24 as algorithm input —

New row (none fits AC-M0-04):

ID Scope Owner Depends on Decisions Spec sections Acceptance evidence Release/gate Brief Implementation authorisation PR/status Evidence Blockers
T-RD-10 M0: replace versioning-model §12.6 with the full QM v2 harvest-and-avoid map for #2461 and #2572–#2575 (this audit plus B, C and D); closure notes ready for G0-D4 Stream A lead T-G0 (G0-D4), T-HOLD for any closure Q-08 VM §12.6; RD §14 AC-M0-04; every H-DOM entry with a target row or "Avoid" reason M0 Drafted (this audit) On hold — This file Hold; G0-D4 not authorised

7. Owner-level questions

None. Every verdict follows from a decided rule or a recorded PROPOSAL. D2-03 (data type and multiplicity as version content) is the only open engineering contract that would revive H-DOM-24 as a versioning mechanism. It stays a brief item under T-RD-01.