Skip to content

Question Management v2: Mental Model Review Decisions

Comprehensive record of all decisions and corrections from the mental model audit conducted 2026-03-28 to 2026-03-30. This document should be used to update the existing specification documents (implementation-plan.md, publishing-versioning-ux.md, ui-specification.md, annotation-versioning-integration.md) and the prototype (prototype.html).


Table of Contents

  1. Background
  2. User-Facing Mental Model
  3. Assign View — Simplified Pending States
  4. First Publish Ceremony
  5. Copying Published Questions
  6. Replace with Corrected Version
  7. Unpublish Replaced by Forward-Only Lifecycle
  8. Breaking Changes — Fundamental Correctness Model
  9. When Decisions Are Made: Design Time AND Publish Time
  10. Publish Dialog as Step-by-Step Wizard
  11. Reassuring Language in Design View
  12. Impact Option Examples
  13. Answer Mapping Configuration
  14. Annotation Count Tracking and Display
  15. Session Handling — Completed vs In-Progress
  16. Multi-Question Conflict Resolution
  17. Annotator Experience for Re-Answer / Review
  18. Concurrency at Publish Time
  19. PublishDecision Domain Entity
  20. Audit Trail — Cascading Provenance
  21. Phases 1-7 Without Phase 8
  22. Training Rounds
  23. Forward Compatibility
  24. Corrections to Previous Specifications

1. Background

This document records the outcomes of a mental model audit of the QM v2 versioning, publishing, and breaking change handling. The audit examined:

  • The user-facing concepts and whether they create excessive cognitive load
  • The publishing ceremony and its interaction with existing annotations
  • Breaking change handling and data integrity guarantees
  • The domain model underpinning admin decisions
  • Forward compatibility between implementation phases

Source Documents Reviewed

  • implementation-plan.md — 9-phase implementation plan
  • publishing-versioning-ux.md — Publishing ceremony and versioning UX
  • ui-specification.md — Design/Assign/Preview view specifications
  • annotation-versioning-integration.md — PR2398/PR2461 reconciliation
  • migration-strategy.md — Data migration approach
  • prototype.html — Interactive HTML prototype
  • state-of-play.md — Current implementation status
  • Memory file: project_qm_design_decisions.md — Design session decisions
  • Current codebase: Annotation, AnnotationSession, Study entities

Key Principles Established

  1. Annotations are project-wide entities. They don't belong to stages. The stageId on an annotation version is provenance (which stage context the annotator was in), not ownership.
  2. The fundamental invariant: an annotation can only exist in a session version if its answer is valid for the AQ version referenced by that session's SQS version. No publish can create a session version containing an invalid annotation.
  3. Every edit to a published question with annotations requires explicit admin confirmation. No passive defaults that could silently compromise data integrity.
  4. The system flags objectively invalid states but the admin makes all judgement calls. The system cannot determine semantic intent.
  5. Previous answers are never deleted. They are preserved in annotation version history even when the admin asks annotators to re-answer.

2. User-Facing Mental Model

Core Lifecycle — Three Question States

State Icon Colour Meaning
Draft edit_note Purple Never published. Fully mutable.
Published task_alt Green Live on at least one stage. Matches last-published version.
Published with changes published_with_changes Amber Published, with unpublished changes layered on top.

These are the only states shown in the tree view. Version numbers are hidden — they appear only in the version history dialog accessed from the properties panel.

Design Page Framing

A persistent, subtle line at the top of the Design workspace:

Changes here are drafts — annotators won't see them until you publish to a stage.

This establishes the sandbox mental model. The admin has permission to experiment freely because nothing in the Design view is live.

Concepts Removed from User-Facing UI

Concept Decision Rationale
PQS (Project Question Set) Fully hidden. Never referenced in UI text. Removes an entire concept from the admin's mental model. Publishing creates new AQ versions, not "PQS versions."
SQS (Stage Question Set) Not referenced by name. Admin thinks "publishing to a stage," not "creating an SQS version."
"Question set version" Avoided entirely. Use temporal framing. "The current questions" vs "your changes." If identification is needed, use sequential labels + timestamps ("Update 3 — Mar 28, 14:32"). Dates alone are ambiguous (multiple publishes per day).
Version numbers on tree nodes Hidden. Only in version history dialogs. Most of the time, admins care about state (is this live?), not version (which version?).

What the Admin Needs to Understand (4 Concepts)

  1. Questions have two states: draft (not yet live) and published (live, with possible pending changes)
  2. Stages define what annotators see — you assign questions and publish the stage
  3. Publishing is the one deliberate action — everything else autosaves
  4. First publish locks structure; subsequent changes are version-tracked

3. Assign View — Simplified Pending States

Previous Design (Three Simultaneous Pending States)

The original spec showed three independent indicators on each question in the Assign tree: 1. "Published with changes" badge (content changes) 2. Green/red border (assignment change) 3. Blue update icon (newer version from another stage)

Problem: Three overlapping reasons for "pending-ness" creates cognitive overload in the critical decision-making view.

Revised Design (Two Visual Dimensions)

Dimension 1: Change status (icon, per-question)

Indicator Meaning
No indicator Identical to what's currently published for this stage
Small amber dot / edit_note Has changes that will be included in next publish — whether from admin's own edits OR from another stage's publish (merged concept, no distinction in tree)
Warning icon (amber warning) Validation error that blocks publishing

Dimension 2: Assignment changes (row treatment)

Treatment Meaning
Normal row Currently published on this stage, will remain
Left green border + "+" prefix NOT currently published, will be added
Left red border + "−" prefix Currently published, will be removed
Unchecked, no border, muted Not assigned, never has been

Cross-Stage Publish Communication

The distinction between "your edits" and "updates from other stages" is shown:

  • Assign view entry: Quiet inline notice (not a banner): "3 questions were updated when Screening was published on Mar 15."
  • Publish dialog (Step 1): Changes grouped by source — "Content changes (your edits)" vs "Updated from other stages"
  • Properties panel: On-demand detail when selecting a changed question

4. First Publish Ceremony

When a DraftQuestion is published for the first time, it becomes an AnnotationQuestion with frozen structural properties. This is permanent and needs explicit communication.

What Freezes

  • Category (e.g., Treatment, Outcome)
  • Data type (e.g., Text, Integer, Decimal)
  • Parent relationship (which question this is nested under)
  • Group as single (whether units share answers)

What Stays Mutable

  • Question text, options, help text
  • Control type, required/optional, multiple answer settings
  • Answer option filters (conditional logic)

UI Treatment

A visually distinct info card (not warning) in the publish wizard (Step 1 or Step 5) for first-time publishes:

First-time publish: 2 questions

These questions will become permanent entries in the project.
After publishing, the following properties cannot be changed:
• Category • Data type • Parent relationship • Group as single

You can always change: question text, options, help text,
control type, required/optional, and multiple answer settings.

► "Drug Name" — Dropdown, Text, under Treatment
► "Dose Regimen" — Input, Decimal, under Drug Name

Only shown for first-time publishes. Not shown for routine version bumps.


5. Copying Published Questions

  • Copying/duplicating a published question (or subtree) always creates Draft copies with new GUIDs.
  • No relationship to the original's version history.
  • All descendants are also Draft, regardless of the original's state.
  • A subtle toast: "Copy created as draft"

6. Replace with New Version

Single Action, Adaptive Behaviour

A single "Replace with new version" action is available in the properties panel for ALL published questions, regardless of whether they have annotations. The behaviour adapts based on annotation state.

Why all published descendants must also be redrafted: Published children have parentQuestionId pointing to the old AQ. Changing parentQuestionId is a structural change, which is forbidden on published AQs. Therefore, replacing a parent necessarily requires replacing the entire published subtree.

Dialog (adapts to show annotation counts)

Replace "Drug Name" with a new editable version

"Drug Name" has 3 published descendants:
  • Dose (published, 31 annotations)
  • Dose Unit (published, 31 annotations)
  • Dose Regimen Type (published, 12 annotations)

Published questions cannot be reparented (structural freeze).
All descendants will also be replaced with new draft copies.

The new drafts will be linked to the originals.
Original questions and their annotations remain in
project history. When you publish the replacements,
you'll choose how to handle existing annotations.

            [Cancel]    [Replace all (4 questions)]

For questions with zero annotations, the annotation-related text is omitted and the dialog is simpler.

Mechanics (Same for Both Cases)

  • New DraftQuestions created (new GUIDs, full copy of content)
  • Each stores replacesAnnotationQuestionId: Guid? pointing to the original AQ
  • Placed at same tree positions
  • Originals removed from draft PQS (a new draft PQS is created without them)
  • Originals remain in pmAnnotationQuestion (never deleted, annotation references intact)
  • Admin can now change data type, parent, category freely on the new drafts
  • To make live: go to Assign, re-check, publish

Breaking Change Handling in Design View (Replacement Drafts with Lineage)

When a replacement DraftQuestion has replacesAnnotationQuestionId pointing to an original AQ with annotations, the Impact & Mapping section appears in the properties panel — even though the question itself is a draft. The system resolves the lineage link and shows the original's annotation counts and answer distribution.

This works identically to editing the draft field on an existing published AQ (see Section 9):

  • The Impact & Mapping section auto-expands when the admin edits a replacement draft that has an original with annotations
  • The admin sees annotation counts and answer distribution from the original AQ
  • The admin configures preliminary decisions: classification, handling (keep/map/re-answer), answer mappings
  • Stored as DraftPublishDecision on the DraftQuestion itself (not on AQ.draft, since this is a DraftQuestion not an AQ)
  • The admin can compare their new structural choices against the original's annotations and adjust either the question design or the handling decisions accordingly

This is particularly valuable for replacement questions because the admin is likely making structural changes (the whole reason for replacing rather than editing). Seeing that "23 annotators selected 'Weight drop' on the original version" while changing the data type from Text to Dropdown allows the admin to configure the mapping (e.g., map free-text "Weight drop" answers to the new dropdown option "WD") at the moment they're making the design decision.

The DraftPublishDecision on the replacement DraftQuestion travels to the publish wizard as a pre-populated suggestion, just like DraftPublishDecision on AQ.draft does for regular edits.

At Publish Time

Zero annotations on original: Straightforward first-publish ceremony. No annotation handling needed. Any DraftPublishDecision is ignored (nothing to apply it to).

Annotations exist on original (Phase 8 required): The system detects the lineage link via replacesAnnotationQuestionId, loads the DraftPublishDecision from the replacement DraftQuestion, and pre-populates the publish wizard (Step ⅔) with the admin's Design-time decisions. The admin reviews, confirms, adjusts, or overrides as usual.


7. Unpublish Replaced by Forward-Only Lifecycle

The "unpublish" concept is removed. Instead:

  • Any published question: Use "Replace with new version" to create new editable drafts. If the original has annotations, handling decisions are made at publish time (Phase 8).
  • The original AQ document always persists in pmAnnotationQuestion — it is removed from the draft PQS but never deleted.

This preserves a clean forward-only lifecycle model.


8. Breaking Changes — Fundamental Correctness Model

All Edits to Published Questions Are Potentially Breaking

The system cannot determine semantic intent. A text change, new option, or help text change can all recontextualise the question in ways that affect how existing answers should be interpreted.

breakingChange: boolean on AQVersion is always set by the admin, never auto-computed. The system's role is to: 1. Detect and highlight objectively invalid states (option removal with annotations) 2. Require explicit confirmation for all changes to questions with annotations 3. Default to non-breaking classification ONLY after explicit admin confirmation

Two Tracks of Change

Track 2 — Objectively invalid annotations (e.g., option removed that was selected by annotators, option renamed): - System requires explicit decisions before publishing - No default — admin must actively choose handling - Publish button disabled until all decided

Track 1 — Subjectively breaking changes (text edit, new option, help text change): - Every change to a published question with annotations requires explicit per-question confirmation - Radio selection: "This change does not affect existing answers" / "This change may affect existing answers" - No passive defaults. Publish wizard disabled until all confirmed. - If "may affect" is selected, the Track 2 decision flow expands - Questions with zero annotations are auto-confirmed

The Options for Handling Affected Annotations

For sessions whose annotations are affected by a question change, the admin chooses per-question:

Option Effect on Session
Don't update these sessions Sessions stay on the current questions. No transition. Annotators see no changes.
Map to a different option Answer value mapped. Optionally: ask annotator to review the mapped answer.
Ask annotators to re-answer Answer cleared, previous answer in history. Annotator must provide new response.

"Keep answers as they are" (carry forward) is only available when the answer is objectively valid for the new AQ version. If an option was removed and the annotator selected it, carry-forward is not an option — the admin must choose map or re-answer.

Wording

The UI avoids "breaking change" as terminology: - "This change does not affect existing answers" / "This change may affect existing answers" - Flag checkbox: "Flag this change for review — annotators who have already answered may need to reconsider" - The breakingChange field is metadata for audit/transitivity, not a user-facing concept


9. When Decisions Are Made: Design Time AND Publish Time

Design Time (Properties Panel in Design View)

When a published AQ with annotations is edited, the Impact & Mapping section auto-expands in the properties panel. The admin configures:

  • Classification: "does not affect" / "may affect"
  • Handling: keep/map/re-answer (if "may affect")
  • Answer mappings (per-option, for option-based questions)
  • Change note

Stored as DraftPublishDecision on AQ.draft.draftPublishDecision. This is mutable — can be changed any time before publish.

Value: The admin is in the context of making the change. The change and its impact can influence each other: - The impact of changes can influence what changes the admin makes to the question - The changes being made can influence how the admin wants to handle existing annotations

Impact & Mapping section (auto-expands when AQ with annotations is edited):

This question has 47 annotations.
Editing here updates your draft only.

When published, how should existing answers be handled?

● Keep answers as they are                           (default where valid)
  Best for: wording improvements, adding help text,
  or changes that don't affect how answers are interpreted.

○ Map answers to updated options
  Best for: fixing a typo in an option name, merging
  duplicate options, or renaming for consistency.
  [Configure mapping →]

○ Ask annotators to re-answer
  Best for: significant changes to question meaning,
  new options that may better fit previous responses.

☐ Flag this change for review — annotators who have
  already answered may need to reconsider

[Change note: ________________________________]

Publish Time (Publish Wizard on Assign View)

DraftPublishDecisions from Design view are loaded as pre-populated suggestions in the wizard.

The admin reviews in the context of all changes together. They can: - Confirm Design-time decisions - Adjust or override per-question - Add stage-specific overrides (same question, different decision for different stages) - Configure session scope (completed vs in-progress, filtering by answer value)

On publish: DraftPublishDecision promoted to immutable PublishDecision on AQVersion. Draft cleared.


10. Publish Dialog as Step-by-Step Wizard

The publish dialog is organised as a step-by-step wizard to prevent overwhelming the admin with simultaneous decisions.

Wizard Steps

Step 1: Review Changes
  "Here's what's changed since this stage was last published."
  Grouped: your edits, updates from other stages, new assignments, removals.
  First-publish info card shown here if applicable.
  No decisions — just orientation.
  [Next →]

Step 2: Confirm Impact on Annotations
  For each changed question WITH annotations:
  Radio: "Does not affect existing answers" / "May affect"
  Pre-populated from Design-time DraftPublishDecisions.
  Questions with zero annotations: auto-confirmed.
  Objectively invalid annotations: pre-expanded with required decisions.
  [Next →]  (disabled until all confirmed)

Step 3: Configure Answer Handling
  (CONDITIONAL — only appears if Step 2 had "May affect" or Track 2 items)
  Per-question decisions with answer distribution shown.
  Mapping configuration for option-based questions.
  Separate sections for in-progress and completed sessions.
  Pre-populated from Design-time configurations.
  [Next →]  (disabled until all configured)

Step 4: Resolve Conflicts
  (CONDITIONAL — only appears if multi-question conflicts detected)
  Sessions where per-question decisions conflict.
  Admin resolves each conflict.
  [Next →]  (disabled until all resolved)

Step 5: Review & Publish
  Session impact summary: computed effective state.
  Final review of all decisions.
  Change notes summary.
  [Publish]

Step Indicator

A progress indicator at the top shows: Review → Confirm impact → [Configure handling] → [Resolve conflicts] → Publish

Conditional steps are greyed out or hidden when not needed. For a simple publish (no annotations or all non-breaking), the wizard is: Step 1 → Step 2 (quick confirmations) → Step 5.


11. Reassuring Language in Design View

Properties Panel Header (Published Question)

Published · 47 annotations · 12 studies

Passive fact. No verb, no imperative. The admin draws their own conclusion.

Inline Note on Potentially Significant Edit

Styled as info (blue/grey), not warning (amber). Appears below the field being edited:

23 annotations reference this option. Editing here updates your draft only — existing data is unaffected until you publish.

Follows the Mailchimp/NNg structure: what's relevant → what's safe → what stays the same → when it matters.

Confidence Hierarchy (from UX research)

  1. Architecture (strongest): sandbox model — drafts cannot affect live data
  2. Visual environment: persistent "drafts" framing line
  3. Factual context: annotation count, answer distribution
  4. Explicit reassurance: "editing here updates your draft only"
  5. Consequence explanation: "existing data is unaffected until you publish"

12. Impact Option Examples

Each option in the Impact & Mapping section includes contextual guidance:

● Keep answers as they are
  Best for: wording improvements, adding help text,
  or changes that don't affect how answers are interpreted.

○ Map answers to updated options
  Best for: fixing a typo in an option name, merging
  duplicate options, or renaming for consistency.
  [Configure mapping →]

○ Ask annotators to re-answer
  Best for: significant changes to question meaning,
  new options that may better fit previous responses,
  or when the admin needs fresh judgements.

13. Answer Mapping Configuration

Per-option granularity. For each removed/changed option that has annotations:

"Weight drop" (23 annotations)
  ○ Map to: [Select option... ▾]
  ○ Ask annotator to re-answer
  ○ Keep original answer (only if option still exists)

Mapping can be combined with "ask annotators to review" — the mapped answer is pre-filled but the annotator must acknowledge it (dismissible alert).


14. Annotation Count Tracking and Display

What's Tracked (Computed On-Demand)

Metric How Computed When
Total annotations for a question Count Annotation docs by QuestionId (project-wide, not per-stage) On question selection in properties panel
Studies with annotations Count distinct studyId values On question selection
Answer distribution Group latest AVs by answer value When publish wizard opens
Annotations by AQ version Group by aqVersionRef When publish wizard opens
Sessions: completed vs in-progress Group by latest ASV status When publish wizard opens

Key Model Facts

  • Annotations are project-wide entities. stageId on an annotation version is provenance, not ownership.
  • The count does not discriminate by stage.
  • Answer distribution is the critical information for mapping decisions.
  • AV (annotation version) history is the annotator's edit history — not shown to admin. Admin sees latest answer per annotation.

Display

  • Properties panel: "Published · 47 annotations · 12 studies"
  • Publish wizard (Step ⅔): full breakdown by answer value, by AQ version, by session status

15. Session Handling — Completed vs In-Progress

Separate Sections in Publish Wizard (Step 3)

The wizard separates completed and in-progress sessions because the admin's instincts differ: - In-progress: annotator is actively working, disruption is expected - Completed: annotator considers work done, reopening is a bigger imposition

Options for In-Progress Sessions

Option Effect
Don't update Session continues with current questions. No transition.
Map answers Answer mapped. Optionally: ask to review.
Re-answer Answer cleared. Previous in history.

Options for Completed Sessions

Option Effect
Leave as they are (default) Sessions stay complete. No disruption.
Map (keep complete) Answers silently mapped.
Map + reopen for review Answers mapped. Session reopened. Annotator must acknowledge and re-complete.
Reopen for re-answer Answers cleared. Session reopened. Annotator must answer and re-complete.

Filtering Which Completed Sessions to Affect

Admin can filter by answer value: - None (default) / All / By specific answer values

Example: Only reopen sessions where annotator selected "Weight drop" (because those answers are now invalid), leaving "CCI" and "Fluid percussion" sessions alone.


16. Multi-Question Conflict Resolution

The Fundamental Invariant

An annotation can only exist in a session version if its answer is valid for the AQ version referenced by that session's SQS version.

Per-Question Decisions Are Conditional on Session Transition

"Don't update sessions for this question" means: don't trigger a transition because of this question. But if the session transitions anyway (due to another question), this question's annotation must still be validated against the new AQ version.

Conflict Detection

After all per-question decisions, the system computes the effective per-session outcome. Sessions where per-question decisions conflict are flagged in Step 4 of the wizard.

Example conflict: Question A says "don't update" but Question B says "reopen for re-answer." Session #42 has answers for both. Because Question B requires transitioning Session #42, Question A's annotation is now in the context of the new AQ version. If Question A's new version removed the option the annotator selected, Question A has an invalid answer in the transitioned session.

Resolution: The admin must provide a handling decision for Question A in the context of Session #42's transition — either map the answer or ask to re-answer.

Wizard Step 4 (Conditional)

Consistency check: 3 sessions have conflicting decisions

Session #42 (Alice, Study "Smith 2024"):
  Question A: you chose "don't update"
  Question B: you chose "reopen for re-answer"

  Because Question B requires updating this session,
  Question A must also be validated. "Weight drop" is
  not available in the updated question.

  How should Question A be handled in these sessions?
  ○ Map "Weight drop" to: [CCI ▾]
  ○ Ask annotator to re-answer

Publish disabled until all conflicts resolved.

Session Exclusion (Advanced)

Optional: admin can exclude specific sessions entirely from all transitions. These sessions remain on the old SQS version regardless of per-question decisions. This is the only way to guarantee a session is truly untouched.

Session Impact Summary (Wizard Step 5)

After all decisions and conflict resolution:

Session impact summary

  28 completed sessions, 15 in-progress sessions

  In-progress:
    6 will be updated (details per question)
    9 unaffected

  Completed:
    3 will be reopened (details per question)
    5 left as-is (excluded or unaffected)
    20 unaffected

17. Annotator Experience for Re-Answer / Review

Dismissible Inline Alert (Not Checkbox)

When an annotator must review a changed question, a dismissible inline alert appears on the question. Dismissing it removes the alert entirely — no lingering visual noise.

Before dismissal:
┌──────────────────────────────────────────────────┐
│  ℹ  This question was updated — please review     │
│                                                    │
│  The options for this question have changed.       │
│  Your previous answer: "Weight drop"               │
│                                                    │
│  [Dismiss — I've reviewed this]                    │
└──────────────────────────────────────────────────┘

After dismissal:
(alert gone, question looks normal)
(brief "Reviewed ✓" indicator fades)

Dismissed state persists across page loads (stored on session). Session cannot be marked complete until all flagged questions are dismissed or answered.

Validation Rules

Required? Previous Answer? Annotator Must... Can Complete?
Required Yes (re-answer requested) Provide a new answer No, until answered
Not required Yes (re-answer requested) Dismiss the review alert No, until dismissed
Required No Provide answer (normal required) No, until answered
Not required No Nothing Yes

"Use Previous Answer" Constraints

  • Only available if the previous answer is still a valid option in the new version
  • If previous option removed: button NOT shown
  • If previous option renamed and admin configured mapping: pre-fills mapped value

Annotator History Access

Always available: - Answer history per question (all AVs) — timeline showing what was answered, when, on which version - Session history (all ASVs) — timeline of session state changes


18. Concurrency at Publish Time

Problem

Annotations may be submitted between the admin opening the publish dialog and clicking Publish, invalidating the impact assessment.

Solution: Optimistic Concurrency with Re-Validation

1. Admin opens publish wizard
   → System computes annotation impact, stores snapshot

2. Admin makes decisions, clicks Publish

3. System acquires brief lock on relevant stage/studies

4. System re-computes annotation impact

5. Compares against snapshot from step 1:
   If unchanged → proceed
   If changed → abort, refresh dialog with updated counts
     Admin's previous decisions preserved, they re-confirm
     Auto-confirmed questions that now have annotations
     lose auto-confirm status

6. Publish executes atomically within lock
   → AQVersions, PQSVersion, SQSVersion created
   → Session transitions executed
   → Lock released

7. Lock duration is brief (sub-second for write operations)

What the reviewer experiences: If they save at the exact moment of publish, brief retry delay. On retry, they load the new question version.

What the admin experiences: In the rare case where state changed, a clear message and refreshed dialog with previous decisions preserved.


19. PublishDecision Domain Entity

DraftPublishDecision (mutable, two locations)

Stored on AQ.draft.draftPublishDecision for edits to existing published questions, OR on DraftQuestion.draftPublishDecision for replacement drafts with lineage (replacesAnnotationQuestionId != null). Same schema in both cases:

draftPublishDecision: {
  classification: "non-breaking" | "breaking" | null
  handling: "no-action" | "keep-sessions" | "map-answers" | "re-answer" | null
  answerMappings: [{fromValue, toValue, requiresReview}]?
  // No session scope — that's stage-specific, decided at publish time
}

PublishDecision (on AQVersion, immutable)

PublishDecision {
  questionId: Guid
  aqVersionId: Guid                    ← the new AQVersion
  previousAqVersionId: Guid?           ← the version being superseded

  classification: "non-breaking" | "breaking"
  classificationSource: "admin-confirmed" | "system-detected"

  handling: "no-action" | "keep-sessions" | "map-answers" | "re-answer"

  answerMappings: [
    {
      fromValue: string                ← old answer value
      toValue: string                  ← mapped new value
      requiresReview: bool             ← annotator must acknowledge
    }
  ]?

  inProgressSessionHandling: handling
  completedSessionHandling: handling
  completedSessionFilter: {
    filterType: "none" | "all" | "by-answer"
    answerValues: string[]?
  }

  decidedBy: Guid                      ← InvestigatorId of admin
  decidedAt: DateTime
  changeNote: string?
}

Where Stored

  • AQVersion.publishDecisions: PublishDecision[] — immutable record of what was decided
  • SQSVersion.publishDecisionSummary — summary for session transition engine
  • Transition ASV.transitionDecisionRef — points to the SQSVersion that triggered it

20. Audit Trail — Cascading Provenance

VersionAudit (on every versioned entity)

VersionAudit {
  initiatedBy: Guid                    ← InvestigatorId
  createdAt: DateTime
  action: string                       ← "publish", "adminTransition",
                                          "annotatorSave", "sessionComplete", etc.
  reason: string?                      ← change note or auto-generated
  triggeredBy: {                       ← what caused this version
    entityType: string                 ← "SQSVersion", "AQVersion", etc.
    entityId: Guid
    versionId: Guid
  }?
}

Example Cascade

Admin Chris publishes a stage:

AQVersion v3 (TBI Model Type)
  audit: { initiatedBy: Chris, action: "publish",
           reason: "Consolidating TBI models" }

PQSVersion v4
  audit: { initiatedBy: Chris, action: "publish",
           triggeredBy: AQVersion v3 }

SQSVersion v3 (Data Extraction)
  audit: { initiatedBy: Chris, action: "publish",
           triggeredBy: PQSVersion v4 }

ASV v2 (Alice's session, Study #42)
  audit: { initiatedBy: Chris, action: "adminTransition",
           triggeredBy: SQSVersion v3,
           reason: "Mapped 'Weight drop' → 'CCI'" }

AV v2 (Alice's annotation for TBI Model Type)
  audit: { initiatedBy: Chris, action: "adminTransition",
           triggeredBy: AQVersion v3,
           reason: "Answer mapped: 'Weight drop' → 'CCI'" }

When Alice later reviews:

AV v3 (Alice confirms the mapped answer)
  audit: { initiatedBy: Alice, action: "annotatorSave",
           triggeredBy: ASV v2 }

21. Phases 1-7 Without Phase 8

The Risk

Shipping question versioning without annotation versioning creates a false sense of safety. The publishing ceremony promises controlled evolution, but the existing tree-shaking annotation replacement (AddAnnotations) silently destroys previous answers with no history. This is arguably worse than the current system because the admin has a false sense of control.

Block publishing new AQ versions to stages that have annotation sessions.

  • Admin CAN publish questions to a stage for the first time (initial setup)
  • Admin CAN publish to stages with no annotation sessions
  • Admin CANNOT publish a new AQ version to a stage with existing annotations
  • The system shows: "This stage has active annotations. Updating questions on annotated stages requires annotation versioning, which will be available in a future update."
  • Admin can still: edit drafts, publish to other unannotated stages, use full Design/Assign/Preview workflow

This is a per-publish check: each time the admin attempts to publish, the system checks whether the target stage has annotation sessions. This means the admin can continue iterating on unannotated stages while annotated stages are protected.


22. Training Rounds

A separate planning document has been created at training-rounds.md.

Key design decisions: - Training rounds pin to a specific SQS version (stay pinned by default — changing questions mid-training invalidates calibration) - Expected answers tied to specific AQ versions - Training annotations follow the same versioning model as regular annotations but are flagged as training - Pass criteria configurable (agreement threshold, specific correct answers, minimum studies) - Independent workstream, recommended after Phases 1-7, benefits from Phase 8

Cross-referenced from the implementation plan.


23. Forward Compatibility

Current (Phases 1-7) Must Support (Phase 8) How
QuestionVersionId on Annotation Full AV history with aqVersionRef Same field — becomes first AV's aqVersionRef during extraction
Annotations embedded on Study Own collection pmAnnotation Interface-based design, swap storage later
Sessions embedded on Study Own collection pmAnnotationSession Interface-based design
No pendingAnswer Per-annotation auto-save buffer Additive field
No ASV Session version tracking Additive alongside existing Status
breakingChange on AQVersion Transitivity computation Flag stored; computation at query time
DraftPublishDecision on AQ.draft Promoted to PublishDecision at publish Data shape forward-compatible
replacesAnnotationQuestionId on DraftQuestion Annotation migration at publish (Phase 8) Lineage link enables Phase 8 engine
AddAnnotations tree-shaking Append-only AV history Must change in Phase 8.5. Flagged in codebase.

Transition ASV vs Regular ASV

Both are ASV entries in AnnotationSession.sessionVersions[]. The difference is createdByAction:

  • Regular ASV: Created by the annotator saving the form. action: "annotatorSave" or action: "sessionComplete".
  • Transition ASV: Created atomically at publish time by the system, per the admin's PublishDecision. action: "adminTransition". Points to the admin's InvestigatorId. Contains carried-forward, mapped, or cleared annotations per the admin's configuration.

There is no "draft ASV" concept. Transition ASVs are created atomically at publish time or not at all. The admin's decisions in the wizard determine what the ASV will contain, but the ASV itself is only created at the moment of publish.


24. Corrections to Previous Specifications

Cross-Reference Backport Tracker

This table tracks which decisions from this document have been incorporated into the other specification documents. Updated as corrections are applied.

implementation-plan.md

Decision Change Required Status
Phase 8 scope (§10-14) Expand from skeleton to 5 sub-phases: Assessment Engine, Impact & Mapping Config, Publish Wizard with Impact, Session Transition Engine, Annotator-Facing Version Transition ✅ Done (commit a4d29b49c)
Phase 8 dependencies (§6) Note that "Replace with new version" for questions WITH annotations requires Phase 8 for annotation handling at publish time ✅ Done (commit a4d29b49c)
Phase ordering rationale (§21) Add note about mitigation for Phases 1-7 without Phase 8: block publishing new AQ versions to stages with annotation sessions ✅ Done (commit a4d29b49c)
Data model updates (§2, §9, §13) Add DraftPublishDecision to AQ.draft schema; add replacesAnnotationQuestionId to DraftQuestion; add PublishDecision to AQVersion; add VersionAudit to all versioned entities; add publishDecisionSummary to SQSVersion ✅ Done (commit a4d29b49c)
Acceptance criteria (§10-14) Add criteria for publish wizard steps, concurrency re-validation, conflict detection, audit trail ✅ Done (commit a4d29b49c)
Terminology "Edited" → "Published with changes" (§2) Replace all occurrences of "Edited" state label ✅ Done (commit 4a8ba1de0)
GFS snapshot acceptance criteria (§—) Add tier promotion/demotion, cap enforcement, deduplication, and restore criteria ✅ Done (this commit)

publishing-versioning-ux.md

Decision Change Required Status
PQS/SQS terminology (§2) Remove all user-facing PQS/SQS terminology ✅ Done (commit a4d29b49c)
Two visual dimensions (§3) Collapse three pending states to two (change status + assignment delta) ✅ Done (commit a4d29b49c)
"Update available" merge (§3) Merge into generic "changed" indicator; source shown in publish dialog only ✅ Done (commit a4d29b49c)
Step-by-step wizard (§10) Replace single publish dialog with 5-step wizard ✅ Done (commit a4d29b49c)
Two-track breaking changes (§8) Add objectively invalid vs subjectively breaking model, explicit confirmation, PublishDecision flow ✅ Done (commit a4d29b49c)
Session handling (§11-12) Add completed vs in-progress separation, answer filtering, multi-question conflict resolution ✅ Done (commit a4d29b49c)
Change reasons at Design time (§9) Move primary capture to Design view, with cascading auto-propagation ✅ Done (commit a4d29b49c)
Terminology "Edited" → "Published with changes" (§2) Replace all occurrences ✅ Done (commit 4a8ba1de0)

ui-specification.md

Decision Change Required Status
Two-dimension Assign indicators (§3) Update to change status icon + assignment delta border ✅ Done (commit a4d29b49c)
Impact & Mapping in properties panel (§9) Add DraftPublishDecision fields, annotation count display ✅ Done (commit a4d29b49c)
Design view "drafts" framing line (§2) Add persistent "Changes here are drafts..." banner ✅ Done (commit a4d29b49c)
Publish wizard specification (§10) Replace single dialog with wizard spec ✅ Done (commit a4d29b49c)
Annotator form patterns (§11-12) Add dismissible alert, "Use previous answer" constraints, version history access ✅ Done (commit a4d29b49c)
Terminology "Edited" → "Published with changes" (§2) Replace all occurrences ✅ Done (commit 4a8ba1de0)
Zero-annotation adapted dialog (§6) Show adapted "Replace with new version" dialog when annotations = 0 ⬜ Pending

annotation-versioning-integration.md

Decision Change Required Status
Phase 8 expansion (§8-14) Expand with PublishDecision entity, wizard steps, conflict resolution, session transition rules ✅ Done (commit a4d29b49c)
Consistency invariant (§15) Add explicit statement: no session version can contain invalid answer for its AQ version ✅ Done (commit a4d29b49c)
Transition vs regular ASV (§12) Clarify audit trail on transition ASVs ✅ Done (commit a4d29b49c)
Concurrency re-validation (§18) Add re-validation at publish time specification ✅ Done (commit a4d29b49c)
Publish decision initialization at migration time (§—) Specify default breakingChange: false, empty publishDecisions, audit.action: "migration" ✅ Done (this commit, in migration-strategy.md)
Breaking change detection algorithm (§8) Capture inline — do not rely on PR2398 branch ✅ Done (this commit)

prototype.html

Decision Change Required Status
Two-dimension Assign indicators (§3) Update pending state indicators ✅ Done (commit a4d29b49c)
Publish wizard wireframe (§10) Replace single dialog with 5-step interactive wizard ✅ Done (this commit)
Impact & Mapping mockup (§9) Add section to properties panel ✅ Done (commit a4d29b49c)
Design view "drafts" framing line (§2) Add persistent banner ✅ Done (commit a4d29b49c)
First-publish info card (§5) Add card for first-time publishes ✅ Done (commit a4d29b49c)
Terminology "Edited" → "Published with changes" (§2) Replace all occurrences ✅ Done (commit 4a8ba1de0)

Glossary of Terms (User-Facing vs Internal)

User-Facing Term Internal Term Notes
"Draft" DraftQuestion / AQ.draft Question not yet published
"Published" AnnotationQuestion with AQVersion(s) Live on at least one stage
"Published with changes" AQ with non-null draft field Published + unpublished changes
"The current questions" Latest SQSVersion for a stage Avoid "question set version"
"Your changes" Draft PQS/SQS differences Avoid PQS/SQS terminology
"Update N (Mar 28, 14:32)" SQSVersion N If identification needed
"Does not affect existing answers" classification: "non-breaking" Admin confirmation
"May affect existing answers" classification: "breaking" Admin confirmation
(not shown) PQS / PQSVersion Fully hidden from UI
(not shown) SQS / SQSVersion Fully hidden from UI
(not shown) ASV / AnnotationSessionVersion Internal only
(not shown) AV / AnnotationVersion Internal only