Skip to content

Superseded. This plan is kept as the design record of the 2026-08-05 discussion. The decisions that carried forward, and the ones that did not, are in annotation-question-extensibility-architecture.md, which is authoritative. Read this for the reasoning; read that for what is being built.

Question Management v2: Configurable Response Modes and Metadata

Purpose and scope

This proposal extends Question Management v2 (QM v2), rather than changing the morning BRCA1 pilot templates. The immediate pilot should use the current, simple question-tree model. This proposal is a separately versioned product capability for later design, usability review, and implementation.

The aim is to let a project define useful additional response context without turning each annotation form into a second questionnaire. It separates:

  1. Normal answer: the question's typed value or selected option.
  2. Project-configured response mode: an alternative to giving a normal answer, with a project-defined label and controlled hierarchy behaviour.
  3. Project-configured metadata: structured supporting details about the response, such as a unit, evidence location, confidence, or note.

The platform defines mechanics, not review-specific labels. For example, "Not reported", "Not assessed", and "Unable to determine" are optional, project-defined response modes—not global SyRF states.

Design principles

  • Preserve SyRF's current nested-question model as the primary workflow.
  • Make all new behaviour additive and opt-in; existing projects must look and work unchanged.
  • Keep reviewer decisions explicit: an unanswered available question is not the same as an inapplicable/suppressed question.
  • Let project administrators configure labels, allowed options, and metadata field types, but use stable machine keys for exports and APIs.
  • Metadata must not become a second conditional-logic engine. Only response modes may affect descendants.
  • Treat a question hidden by an ancestor as a derived UI/runtime result, not a reviewer-selectable answer.

Proposed data model

Question definition

type AnswerType = "text" | "number" | "singleSelect" | "multiSelect" | "boolean";

interface MetadataFieldDefinition {
  key: string; // Stable project-defined export key
  label: string;
  type: "text" | "number" | "singleSelect" | "boolean";
  options?: string[];
  required?: boolean;
  display: "inline" | "details";
}

interface ResponseModeDefinition {
  id: string; // Stable project-defined key
  label: string; // e.g. "Not reported"; no global label is imposed
  suppressDescendants?: boolean;
  requiresReason?: boolean;
  metadataFields?: MetadataFieldDefinition[];
}

interface AnnotationQuestionDefinition {
  id: string;
  text: string;
  answerType: AnswerType;
  options?: string[];
  parentId?: string;
  showWhen?: { parentAnswerEquals?: string | boolean };
  responseModes?: ResponseModeDefinition[];
  metadataFields?: MetadataFieldDefinition[];
}

Response and derived availability

interface AnnotationResponse {
  questionId: string;
  value?: string | number | boolean | string[];
  responseModeId?: string; // mutually exclusive with value
  metadata?: Record<string, string | number | boolean>;
}

interface DerivedQuestionStatus {
  questionId: string;
  status: "available" | "suppressedByAncestor";
  suppressedByQuestionId?: string;
}

DerivedQuestionStatus is calculated from assignment, the existing parent conditions, and any selected response mode with suppressDescendants: true. It is not a response option and need not be persisted.

Annotation form behaviour

The main answer remains visually central. The annotation form should not show extra controls unless a question definition enables them.

For a numeric dose question with a unit metadata field:

What was the intervention dose?

[ 5 ] [ mg/kg v ]                 <- ordinary answer plus inline unit

I cannot provide this answer  v    <- only if response modes are configured
Add details                        <- evidence location, confidence, note

Selecting a configured mode such as "Not reported" replaces the ordinary answer control. If that mode suppresses descendants, children are removed from the active form and receive a derived suppressedByAncestor status. A small, non-editable explanation may be shown in review/audit views.

Required validation applies only to currently available questions. A suppressed child cannot cause an incomplete-form error.

Metadata field presentation:

  • Inline: semantically inseparable qualifiers such as a unit, currency, time basis, or measurement scale.
  • Details disclosure: evidence location, confidence, reviewer note, or other context that would otherwise clutter routine data entry.
  • Never flow-controlling: changes to metadata must not reveal, hide, or require other questions.

Question Management v2 interface

In the QM v2 properties panel, add an optional Response handling section after answer/control configuration:

  1. Toggle: “Allow alternative response modes”.
  2. Editable response-mode list: label, stable ID, suppress descendants, require reason, and per-mode metadata fields.
  3. Editable metadata-field list: label, stable key, type, allowed options, required flag, and display placement (inline/details).
  4. Live preview of the normal control, mode chooser, and details disclosure.
  5. Validation warnings for duplicate IDs/keys, invalid option lists, or a mode that suppresses descendants where no descendants exist.

The tree should show compact badges only—for example + 2 response modes or + unit metadata—rather than expanding nodes with configuration detail.

Metadata fields and response modes must be included in draft/publish diffs and admin impact decisions. Changing a stable key, deleting a mode used in existing annotations, or changing suppressDescendants is a breaking change.

Condition resolver

The existing condition resolver remains authoritative for normal parent answer conditions. QM v2 adds one guard before evaluating a child's own condition:

If any ancestor has a selected response mode with suppressDescendants = true:
  status = suppressedByAncestor
Else if the existing parent condition is unmet:
  status = suppressedByAncestor
Else:
  status = available

The resolver may compute a status for every question assigned to a stage, but the annotation form renders only currently available questions. This gives completion/audit logic a clear distinction between missing and suppressed data without storing a redundant record for each hidden question.

Export and API contract

The canonical API response remains nested, with normal values, response mode, and metadata separate:

{
  "questionId": "intervention-dose",
  "value": 5,
  "metadata": {
    "unit": "mg/kg",
    "evidenceLocation": "Table 2"
  }
}

For a response mode:

{
  "questionId": "intervention-dose",
  "responseModeId": "not-reported",
  "metadata": { "evidenceLocation": "Methods, p. 4" }
}

Flat quantitative exports generate predictable columns based on stable keys: intervention-dose__value, intervention-dose__response_mode, intervention-dose__unit, and intervention-dose__evidence_location. The exported question-definition/version manifest must accompany data exports so later analysts can interpret project-defined IDs and labels.

Backwards compatibility and migration

  • Existing question definitions have no responseModes or metadataFields; their UI and logic are unchanged.
  • Existing answers remain ordinary value responses.
  • New fields are optional in API DTOs and persistence documents.
  • suppressedByAncestor is a runtime-derived status, not a migration of old annotations.
  • New configuration is feature-flagged by project and is unavailable until the compatible annotation form/API version is deployed.
  • Reject an answer containing both value and responseModeId.

Delivery sequence

  1. Discovery and prototype: confirm terminology, mode selection UX, metadata editor, inline unit treatment, and accessibility with projects.
  2. Domain and persistence: versioned definitions, validation, API DTOs, event/audit fields, and migration-safe serialization.
  3. Resolver and annotation form: derived status calculation, mode chooser, metadata components, required validation, autosave, and audit explanation.
  4. QM v2 authoring: properties-panel editor, preview, assignment/publish validation, diffs, and impact decisions.
  5. Exports and analysis: nested API export, flat export columns, manifest, filtering, and quantitative-export tests.
  6. Pilot and rollout: feature flag, one opt-in pilot, usability review, telemetry, documentation, then broader release.

Open decisions to resolve before implementation

  1. Which metadata types are needed initially: text, number, select, boolean, date, unit, evidence pointer, repeating group?
  2. Should a configured response mode be a selectable button group, a dropdown, or a link opening a small chooser? This must be tested for accessibility.
  3. Which configuration changes count as breaking for already-annotated data?
  4. How should mode labels and metadata keys be localised while their export IDs remain stable?
  5. Are repeatable groups required for ROBINS-I confounding factors? If so, they should be designed as a separate, explicit capability—not emulated with unbounded metadata fields.
  6. What review/export representation best distinguishes a value absent from a paper, a value not applicable, and a question suppressed by hierarchy?

Immediate BRCA1 pilot decision

Do not implement this feature as part of the morning pilot. Continue with the existing formula-free templates and their current question hierarchy. Any optionality or explicit “Not reported” decisions for the pilot should be made question by question and recorded in its audit trail, rather than assuming this proposed product capability already exists.