Skip to content

Feature Documentation Reorganisation Plan

Goal: Reorganise the documentation so that every planned feature is a clearly identifiable entity with a consistent structure, known dependencies, traceable funding obligations, and surfaced open questions — making it obvious what SyRF is building, why, what's decided, and what remains open.


Table of Contents

  1. Diagnosis: What's Wrong Today
  2. Design Principles
  3. The Feature Catalogue
  4. Feature Taxonomy & Identity
  5. Directory Restructure
  6. MkDocs Navigation Redesign
  7. Standardised Feature Template
  8. Cross-Reference System
  9. Open Questions Register
  10. Codebase & Deployment as Source of Truth
  11. Fixing the Documentation Validation Pipeline
  12. Tooling
  13. Execution Plan
  14. What Success Looks Like
  15. Open Questions About This Plan

1. Diagnosis: What's Wrong Today

The documentation has strong content — the product roadmap is detailed, feature briefs are thorough, and the phase structure is well-thought-out. But there are structural problems that make it hard to navigate, cross-reference, and understand what differentiates one feature from the next.

1.1 Feature vs Phase vs Task Conflation

The docs/features/ directory contains 49 items. These are fundamentally different types of document treated as the same thing:

What it is Examples Count
True product features screening-profiles, reconciliation, annotation-form-v2 ~20
True platform capabilities mongodb-testing-strategy, change-stream-resilience ~12
Migration/release tasks release-1-migration, release-2-migration 3
Analysis/reference docs seed-data-quality-analysis, annotation-questions ~3
Completed work argocd-deployment-gitops-migration, lambda-gitops 3
Deprecated changestream-otel-metrics, lambda-environment-isolation 4
Overlapping features reconciliation + annotation-management-reconciliation ~4

A researcher trying to understand "what features is SyRF building?" has to wade through all 49 to find the ~20 that actually answer that question.

1.2 No Unique Feature Identifiers

There is no stable way to reference a feature across documents. The roadmap uses phase numbers, the features directory uses folder names, the funding docs use deliverable descriptions, and the user guide drafts use phase numbers again. When docs/funding/nc3rs.md says "Question Editing (annotation questions design interface)" and the roadmap says "Phase 4: Question Lifecycle" and the features directory says annotation-versioning/ — are these the same thing? Related but different? It's not immediately clear.

1.3 Inconsistent Frontmatter

Feature docs have varying frontmatter fields:

Field Present in Missing from
category ~35 docs ~14 docs
depends-on 4 docs 45 docs
priority ~12 docs ~37 docs
phase 0 docs all docs
feature-id 0 docs all docs
funding-refs 0 docs all docs
domain 0 docs all docs

1.4 No Feature-to-Funder Mapping

The funding docs list deliverables by funder. The feature docs describe what's being built. No cross-reference exists. When NC3Rs asks "where is our Question Editing deliverable?", you'd have to manually search across multiple documents to piece together the answer.

1.5 Scattered Open Questions

Design decisions and open questions are buried within individual feature documents. There's no way to get a view of "what are all the unresolved questions?" — which is exactly what a team lead, funder, or new contributor would need.

1.6 MkDocs Navigation Doesn't Help

The Features section in MkDocs lists all 49 items in a flat alphabetical list with no semantic grouping. Infrastructure items sit next to product features; deprecated items sit next to active ones. The navigation doesn't help a reader understand what SyRF is building — it's a file listing, not a feature map.

1.7 Overlapping Directories

Several directories cover overlapping or identical features: - reconciliation/ AND annotation-management-reconciliation/ — same feature, two directories - project-groups/ AND project-groups-ui-ux-redesign.md — same feature, split across directory and file - annotation-versioning/ AND annotation-questions/ — closely related, no clear boundary

1.8 Documentation Validation Blocks PRs Repeatedly

The docs validation pipeline (docs-validation.yml and embedded in ci-cd.yml) fails frequently and wastes developer time. Analysis of the last 100 CI runs reveals a pattern of recurring, preventable failures — most commonly stale generated files (indexes and MkDocs nav), missing frontmatter on new docs, and broken links from moved files. The commit history shows at least 25 commits whose sole purpose is fixing docs validation (fix(docs): regenerate stale documentation indexes, etc.). The local pre-commit hooks don't reliably prevent these because they can't auto-stage generated files — they fail and require a manual two-commit workflow. See Section 11 for detailed analysis.

1.9 Feature Statuses May Not Reflect Reality

Documentation statuses are self-reported and can drift from the actual state of the codebase and production deployments. A feature marked "Completed" may not actually be deployed; a feature marked "Draft" may already be partially implemented. The codebase and the cluster-gitops repo (which tracks what's deployed) are the real sources of truth for implementation and deployment status, but they're not cross-referenced with the docs. See Section 10 for the proposed approach.


2. Design Principles

2.1 Features Are First-Class Entities

Every feature has a unique identity (ID + canonical name) that persists regardless of when it's built, how the roadmap changes, or which funder cares about it. The feature ID is the stable anchor; everything else can change.

2.2 Separate What from When from How

  • Feature specs describe what the system will do (capabilities, data models, user workflows)
  • The roadmap describes when and in what order (phases, releases, dependencies)
  • Implementation plans describe how (technical approach, tasks, checklists)

A feature might span multiple phases, or a phase might deliver parts of multiple features. The relationship should be explicit, not implied by directory structure.

2.3 Single Source of Truth, Many Views

Each fact lives in one authoritative location. Other documents reference it, they don't duplicate it. A product specification should serve as "the blueprint your team will use, from designing and developing the feature to testing and writing user documentation."

2.4 Progressive Disclosure

Not everyone needs the same level of detail:

  • Catalogue → "What features exist?" (30-second scan)
  • Feature brief → "What does this feature do and why?" (5-minute read)
  • Technical spec → "How does this work technically?" (deep dive)
  • Open questions → "What's still unresolved?" (decision-makers)

2.5 Machine-Readable Metadata

Frontmatter should be consistent and structured enough for scripts to generate indexes, dependency graphs, status dashboards, and cross-reference tables automatically. A framework that "guides decisions rather than rigid rules that constrain effective communication" — but with enough structure for automation.

2.6 Navigation Reflects the Domain, Not the Filesystem

The MkDocs navigation should be organised by the systematic review workflow (the domain SyRF operates in), not by file structure. A reader should be able to follow the flow: import → deduplicate → screen → annotate → reconcile → export → PRISMA.


3. The Feature Catalogue

The Feature Catalogue is a new document at docs/features/catalogue.md that serves as the single, curated registry of every feature SyRF is building or has built.

3.1 What It Contains

For each feature:

Field Purpose Example
ID Stable, unique identifier FEAT-007
Name Canonical human-readable name "Screening Profiles"
One-liner What it does in ≤20 words "Named, reusable screening criteria assigned to stages for multi-stage screening pipelines"
Domain Functional area screening
Status Lifecycle position Planned / In-Progress / Completed / Deprecated
Release Which release R1 / R2 / R3
Phases Roadmap phase numbers 13
Depends on Feature IDs this requires FEAT-010
Funding Funder deliverable cross-refs NC3Rs: "Screening types"
Spec link Path to detailed spec directory ./screening-profiles/
Open Qs Count of unresolved questions 3

3.2 Structure

The catalogue is organised by domain, not by release or status:

# SyRF Feature Catalogue

## Systematic Review Workflow Features

### Data Import & Deduplication
| ID | Feature | One-liner | Status | Release | Phases | Open Qs |
|----|---------|-----------|--------|---------|--------|---------|
| FEAT-012 | Deduplication Service | Auto-identify duplicate citations using ASySD ... | Planned | R3 | 12 | 4 |
| FEAT-014 | Search & Upload | ... | Planned | — | — | 2 |

### Annotation
| FEAT-001 | Question Versioning | ... | Planned | R1 | 3, 4 | ... |
| FEAT-002 | Annotation Form v2 | ... | Planned | R1 | 5 | ... |
| FEAT-003 | Question Management UI | ... | Planned | R1 | 6 | ... |
| FEAT-004 | Annotation Import | ... | Planned | R1 | 6.1 | ... |

### Screening
| FEAT-007 | Screening Profiles | ... | Planned | R3 | 13 | ... |
| FEAT-008 | Stage Filtering | ... | Planned | R3 | 14 | ... |
| FEAT-009 | Screening Annotations | ... | Planned | R3 | 15 | ... |
| FEAT-010 | Stage Settings | ... | Planned | R3 | 13 | ... |

### Reconciliation & Quality Assurance
| FEAT-005 | Project Groups & Permissions | ... | Planned | R2 | 8 | ... |
| FEAT-006 | Reconciliation Workflow | ... | Planned | R2 | 9, 10 | ... |

### Export & Reporting
| FEAT-011 | PRISMA Flow Diagram | ... | Planned | R3 | 16 | ... |
| FEAT-013 | Data Export | ... | Planned | R3 | 16 | ... |

### Project Administration
| FEAT-015 | Project Templates | ... | Planned | — | — | ... |

## Platform Capabilities
(PLAT-001 through PLAT-NNN — infrastructure, DevOps, observability)

## Feature Relationships
(Mermaid dependency diagram showing cross-feature dependencies)

## Funding Cross-Reference
(Table mapping FEAT-* IDs to NC3Rs / SSI/RSMF / SEBI/Gates deliverables)

3.3 ID Scheme

  • FEAT-001 through FEAT-NNN — Product features (what users interact with)
  • PLAT-001 through PLAT-NNN — Platform capabilities (infrastructure)

Numbers are assigned in roughly chronological order of first documentation. Once assigned, an ID never changes. Phase numbers are not used as IDs because a feature may span multiple phases, and phases may contribute to multiple features.

3.4 The Catalogue Replaces the Auto-Generated Index

The current docs/features/index.md is auto-generated by generate-indexes.sh and serves as a flat listing. The catalogue replaces it as the primary entry point. The auto-generated index can be retained as a secondary file (e.g., _auto-index.md) for completeness, or the index generator can be updated to produce the catalogue format.


4. Feature Taxonomy & Identity

4.1 Product vs Platform

Product Features (FEAT-*): Change what end-users (researchers, admins, reviewers) can do.

Platform Capabilities (PLAT-*): Infrastructure, DevOps, observability, and technical improvements that enable product features but aren't directly user-visible.

4.2 Domain Grouping

Within product features, group by the functional area of the systematic review workflow:

Domain What it Covers Features
import-dedup Citation import, deduplication, study creation Deduplication Service, Search & Upload
annotation Question design, form interaction, data capture Question Versioning, Annotation Form v2, Question Management UI, Annotation Import
screening Screening decisions, criteria, pipelines Screening Profiles, Stage Filtering, Screening Annotations, Stage Settings
reconciliation Agreement resolution, gold-standard records Project Groups & Permissions, Reconciliation Workflow
export-reporting Data export, PRISMA, metrics Data Export, PRISMA Flow Diagram
project-admin Project setup, templates Project Templates

4.3 Reclassifying the Existing 49 Items

Every current item in docs/features/ is classified and handled:

True Product Features → Stay, get feature ID, follow standard template:

Current Directory/File → Feature ID Canonical Name
annotation-versioning/ FEAT-001 Question Versioning
annotation-form-v2/ FEAT-002 Annotation Form v2
question-management/ FEAT-003 Question Management UI
annotation-import/ FEAT-004 Annotation Import
project-groups/ FEAT-005 Project Groups & Permissions
reconciliation/ FEAT-006 Reconciliation Workflow
screening-profiles/ FEAT-007 Screening Profiles
stage-filtering/ FEAT-008 Stage Filtering
screening-annotations/ FEAT-009 Screening Annotations
stage-settings/ FEAT-010 Stage Settings
prisma-specification/ FEAT-011 PRISMA Specification & Data Model
project-template-feature.md FEAT-012 Project Templates
data-export-refactoring-plan.md FEAT-013 Data Export
search-upload-improvements.md FEAT-014 Search & Upload
bulk-update-blank-field-behavior.md FEAT-015 Bulk Study Update
backend-annotation-validation.md FEAT-016 Annotation Validation Service
job-progress-integration.md FEAT-017 Job Progress
environment-ui-indicator.md FEAT-018 Environment Indicator

Merged into parent features (eliminate duplication):

Current Merge Into Rationale
annotation-management-reconciliation/ FEAT-006 (Reconciliation) Same feature, different name
project-groups-ui-ux-redesign.md FEAT-005 (Project Groups) UI redesign is part of the feature
comments-in-quantitative-data-export.md FEAT-013 (Data Export) Sub-feature of export

True Platform Capabilities → Stay, get PLAT ID:

Current → PLAT ID Canonical Name
mongodb-testing-strategy/ PLAT-001 MongoDB Testing Strategy
change-stream-resilience/ PLAT-002 Change Stream Resilience
saga-duplicate-event-handling/ PLAT-003 Saga Duplicate Event Handling
data-snapshot-automation/ PLAT-004 Data Snapshot Automation
lambda-ack-gitops/ PLAT-005 Lambda ACK GitOps
e2e-testing-infrastructure/ PLAT-006 E2E Testing Infrastructure
masstransit-observability.md PLAT-007 MassTransit Observability
backend-service-health-version-endpoints.md PLAT-008 Service Health Endpoints
gpu-logging-monitoring.md PLAT-009 GPU Logging & Monitoring
mongo-unit-of-work-improvements.md PLAT-010 Mongo UnitOfWork Improvements
version-aggregation-service/ PLAT-011 Version Aggregation Service
dbl-operator-redesign/ PLAT-012 DBL Operator Redesign
aws-to-gcp-consolidation/ PLAT-013 AWS-to-GCP Consolidation
enhanced-database-seeding.md PLAT-014 Enhanced Database Seeding
preview-datasource-restructure/ PLAT-015 Preview Datasource Restructure

Moved out of docs/features/ (not features):

Current Move To Rationale
release-1-migration/ docs/roadmap/migrations/ Implementation task, not a feature
release-2-migration/ docs/roadmap/migrations/ Implementation task, not a feature
release-3-export-prisma/ docs/roadmap/migrations/ Implementation task, not a feature
seed-data-quality-analysis.md docs/architecture/ Analysis document, not a feature
annotation-questions/ docs/architecture/ Reference doc about existing business logic, not a planned feature

Archived (completed/deprecated — move to docs/features/_archive/):

Current Status
argocd-deployment-gitops-migration.md Completed
lambda-gitops/ Completed
preview-cleanup-improvements.md Completed
quantitative-seed-data-and-annotation-validation.md Completed
spec-resolution/ Completed
changestream-otel-metrics/ Deprecated
lambda-environment-isolation/ Deprecated
lambda-gitops-versioning/ Deprecated
zenhub-migration-status-update.md Deprecated

5. Directory Restructure

5.1 New Directory Layout

docs/
├── features/                              # Product features (FEAT-*)
│   ├── catalogue.md                       # THE Feature Catalogue (new, central)
│   ├── _open-questions.md                 # Aggregated open questions (new)
│   ├── _archive/                          # Completed and deprecated features (new)
│   │   ├── argocd-deployment-gitops-migration.md
│   │   ├── lambda-gitops/
│   │   ├── preview-cleanup-improvements.md
│   │   ├── quantitative-seed-data-and-annotation-validation.md
│   │   ├── spec-resolution/
│   │   ├── changestream-otel-metrics/
│   │   ├── lambda-environment-isolation/
│   │   ├── lambda-gitops-versioning/
│   │   └── zenhub-migration-status-update.md
│   │
│   ├── annotation-versioning/             # FEAT-001
│   ├── annotation-form-v2/               # FEAT-002
│   ├── question-management/              # FEAT-003
│   ├── annotation-import/                # FEAT-004
│   ├── project-groups/                   # FEAT-005 (absorbs project-groups-ui-ux-redesign.md)
│   ├── reconciliation/                   # FEAT-006 (absorbs annotation-management-reconciliation/)
│   ├── screening-profiles/               # FEAT-007
│   ├── stage-filtering/                  # FEAT-008
│   ├── screening-annotations/            # FEAT-009
│   ├── stage-settings/                   # FEAT-010
│   ├── prisma-specification/             # FEAT-011
│   ├── project-templates.md              # FEAT-012 (renamed from project-template-feature.md)
│   ├── data-export.md                    # FEAT-013 (renamed from data-export-refactoring-plan.md,
│   │                                     #           absorbs comments-in-quantitative-data-export.md)
│   ├── search-upload.md                  # FEAT-014 (renamed from search-upload-improvements.md)
│   ├── bulk-study-update.md              # FEAT-015 (renamed from bulk-update-blank-field-behavior.md)
│   ├── annotation-validation.md          # FEAT-016 (renamed from backend-annotation-validation.md)
│   ├── job-progress.md                   # FEAT-017 (renamed from job-progress-integration.md)
│   └── environment-indicator.md          # FEAT-018 (renamed from environment-ui-indicator.md)
├── platform/                              # Platform capabilities (PLAT-*) — NEW section
│   ├── index.md
│   ├── mongodb-testing-strategy/         # PLAT-001
│   ├── change-stream-resilience/         # PLAT-002
│   ├── saga-duplicate-event-handling/    # PLAT-003
│   ├── data-snapshot-automation/         # PLAT-004
│   ├── lambda-ack-gitops/               # PLAT-005
│   ├── e2e-testing-infrastructure/      # PLAT-006
│   ├── masstransit-observability.md     # PLAT-007
│   ├── service-health-endpoints.md      # PLAT-008
│   ├── gpu-logging-monitoring.md        # PLAT-009
│   ├── mongo-unit-of-work.md            # PLAT-010
│   ├── version-aggregation-service/     # PLAT-011
│   ├── dbl-operator-redesign/           # PLAT-012
│   ├── aws-to-gcp-consolidation/        # PLAT-013
│   ├── enhanced-database-seeding.md     # PLAT-014
│   └── preview-datasource-restructure/  # PLAT-015
├── roadmap/                               # Roadmap & release planning — NEW section
│   ├── index.md                           # Roadmap overview (promoted from planning/)
│   ├── product-features-roadmap.md        # The 3-release roadmap (moved from planning/)
│   └── migrations/                        # Release migration plans (moved from features/)
│       ├── release-1-migration.md
│       ├── release-2-migration.md
│       └── release-3-migration.md
├── architecture/                          # Unchanged, gains moved docs
│   ├── ...existing docs...
│   ├── annotation-questions/              # Moved from features/ (reference, not feature)
│   └── seed-data-quality-analysis.md      # Moved from features/ (analysis, not feature)
├── decisions/                             # Unchanged
├── funding/                               # Unchanged (gains feature-id cross-refs)
├── how-to/                                # Unchanged
├── planning/                              # Slimmed (roadmap moved out)
├── user-guide-drafts/                     # Unchanged (gains feature-refs in frontmatter)
└── ...

5.2 Handling Merged Features

When two directories cover the same feature, the canonical one stays and the other's unique content is moved in:

annotation-management-reconciliation/ → merge into reconciliation/: - product-overview.mdreconciliation/product-overview.md - design-decisions.mdreconciliation/design-decisions.md - data-model-migration.mdreconciliation/data-model-migration.md - brief-phase-06.md → This is actually about Question Management UI (Phase 6), so move to question-management/brief-phase-06.md - README.md → Merge relevant content into reconciliation/README.md

project-groups-ui-ux-redesign.md → merge into project-groups/: - Rename to project-groups/ui-ux-redesign.md

comments-in-quantitative-data-export.md → merge into data-export.md: - Append as a section in the data export spec, or keep as data-export/comments.md if promoted to a directory

Every file move or rename must be accompanied by: 1. A search-and-replace across all .md files in docs/ to update relative links 2. An update to the MkDocs nav in mkdocs.yml 3. An update to any cross-references in funding docs, user guide drafts, etc.

A script will be written to automate this (see Tooling).


6. MkDocs Navigation Redesign

6.1 Current Problem

The Features section in mkdocs.yml lists 49 items in flat alphabetical order with no semantic grouping. The nav generator (generate-mkdocs-nav.py) builds this from the filesystem, so it inherits the filesystem's lack of structure.

6.2 New Navigation Structure

nav:
  - Home:
      - index.md
      - Team Structure: team.md

  - Product Roadmap:                        # NEW top-level section
      - roadmap/index.md
      - "Three-Release Roadmap": roadmap/product-features-roadmap.md
      - Release Migrations:
          - "Release 1 Migration": roadmap/migrations/release-1-migration.md
          - "Release 2 Migration": roadmap/migrations/release-2-migration.md
          - "Release 3 Migration": roadmap/migrations/release-3-migration.md

  - Features:                               # RESTRUCTURED — grouped by domain
      - Feature Catalogue: features/catalogue.md
      - Open Questions: features/_open-questions.md
      - "Import & Deduplication":
          - "FEAT-012: Deduplication Service": features/prisma-specification/brief-deduplication.md
          - "FEAT-014: Search & Upload": features/search-upload.md
      - Annotation:
          - "FEAT-001: Question Versioning": features/annotation-versioning/README.md
          - "FEAT-002: Annotation Form v2": features/annotation-form-v2/README.md
          - "FEAT-003: Question Management UI": features/question-management/README.md
          - "FEAT-004: Annotation Import": features/annotation-import/brief.md
          - "FEAT-016: Annotation Validation": features/annotation-validation.md
      - Screening:
          - "FEAT-007: Screening Profiles": features/screening-profiles/README.md
          - "FEAT-008: Stage Filtering": features/stage-filtering/README.md
          - "FEAT-009: Screening Annotations": features/screening-annotations/README.md
          - "FEAT-010: Stage Settings": features/stage-settings/README.md
      - Reconciliation:
          - "FEAT-005: Project Groups": features/project-groups/brief.md
          - "FEAT-006: Reconciliation Workflow": features/reconciliation/README.md
      - "Export & Reporting":
          - "FEAT-011: PRISMA Specification": features/prisma-specification/README.md
          - "FEAT-013: Data Export": features/data-export.md
      - "Project Administration":
          - "FEAT-012: Project Templates": features/project-templates.md
          - "FEAT-015: Bulk Study Update": features/bulk-study-update.md
          - "FEAT-017: Job Progress": features/job-progress.md
          - "FEAT-018: Environment Indicator": features/environment-indicator.md
      - Archive:
          - ... (completed/deprecated features)

  - Platform:                               # NEW top-level section (moved from Features)
      - platform/index.md
      - ... (grouped by sub-domain: database, CI/CD, observability, etc.)

  - Architecture:
      - ... (unchanged, gains annotation-questions and seed-data-quality-analysis)

  - Decisions:
      - ... (unchanged)

  - How-To Guides:
      - ... (unchanged)

  - Funding & Contracts:
      - ... (unchanged)

  - User Guide Drafts:
      - ... (unchanged, gains feature-ref cross-links)

  # ... remaining sections unchanged

6.3 Key Navigation Changes

  1. New "Product Roadmap" top-level tab — the roadmap is a primary navigational concern, not buried under Planning
  2. Features grouped by domain — annotation, screening, reconciliation, export — matching the systematic review workflow
  3. Feature IDs in nav titles — e.g., "FEAT-007: Screening Profiles" — so the ID is visible at navigation time
  4. Platform separated from Features — infrastructure work is important but shouldn't dilute the product feature view
  5. Archive section — completed and deprecated items visible but clearly separated
  6. Catalogue as the section landing page — the first thing you see when clicking "Features"

6.4 Nav Generator Updates

The generate-mkdocs-nav.py script needs to be updated to: 1. Read feature-id and domain from frontmatter 2. Group features by domain in the nav output 3. Prefix nav titles with feature IDs 4. Handle the new platform/ and roadmap/ directories 5. Separate archived features into their own nav group


7. Standardised Feature Template

7.1 Frontmatter Schema

Every feature document must include:

---
# Identity (required)
feature-id: "FEAT-007"
title: "Screening Profiles"
doc-type: "Feature"
category: "product"                        # product | platform
domain: "screening"                        # import-dedup | annotation | screening |
                                           # reconciliation | export-reporting | project-admin |
                                           # infrastructure
status: "In-Review"                        # Draft | In-Review | Approved | In-Progress |
                                           # Completed | Deprecated

# Roadmap (required)
release: "R3"                              # Foundation | R1 | R2 | R3 | Standalone
phases: [13]                               # Roadmap phase number(s)

# Relationships (required — empty array if none)
depends-on: ["FEAT-010"]                   # Feature IDs this requires
enables: ["FEAT-008", "FEAT-009"]          # Feature IDs that require this

# Funding (include if applicable)
funding-refs:
  - funder: "NC3Rs"
    deliverable: "Screening types and study filtering"
    contract: "Contract 2"

# Standard fields
priority: "High"                           # Critical | High | Medium | Low
author: "Team"
created: 2025-01-19
updated: 2026-02-09
zenhub-ticket: "TBD"
tags: ["screening", "profiles", "criteria"]

# Tracking
open-questions: 3                          # Count of unresolved questions in this doc
---

7.2 Document Structure Template

# {Feature Name}

> **{feature-id}** | {status} | Release {release} | Phase(s) {phases}

## One-Liner

{≤20-word description of what this feature does for users}

## Problem

{What problem does this solve? Why can't users do this today?}

## Solution

{High-level description of the solution approach}

## Key Concepts

{Core domain concepts introduced by this feature, with definitions}

## User Impact

| Who | What Changes |
|-----|-------------|
| Researchers | ... |
| Admins | ... |

## Data Model

{Key entities, fields, relationships}

## Dependencies

### Depends On

| Feature | Why |
|---------|-----|
| [FEAT-010: Stage Settings](../features/stage-settings/) | Profiles are assigned to stages |

### Enables

| Feature | How |
|---------|-----|
| [FEAT-008: Stage Filtering](../features/stage-filtering/) | Filtering references screening outcomes |

## Funding Obligations

| Funder | Deliverable | Contract | Status |
|--------|------------|----------|--------|
| NC3Rs | "Screening types and study filtering" | Contract 2 | Outstanding |

## Open Questions

- [ ] **OQ-1**: Should profiles support versioning? → Decision needed before implementation
- [x] **OQ-2**: Project-scoped or system-scoped? → **Decided: Project-scoped** (2026-02-15)

## Specification

{Detailed spec, or links to sub-documents}

## Related Documents

- [Technical Plan](#7-standardised-feature-template) (if exists)
- [Roadmap: Phase 13](../roadmap/product-features-roadmap.md#phase-13)
- [User Guide Draft](../user-guide-drafts/FEAT-007-screening-profiles.md)
- [NC3Rs Funding](../funding/nc3rs.md)

8. Cross-Reference System

8.1 Feature ID as the Universal Anchor

When any document references a feature, it uses:

[FEAT-007: Screening Profiles](../features/screening-profiles/)

This is unambiguous, human-readable, clickable, and searchable via grep "FEAT-007".

8.2 Where Cross-References Appear

Document Type How It References Features
Product roadmap Feature IDs in phase descriptions: "Phase 13 delivers FEAT-007 and FEAT-010"
Funding docs Feature ID column in deliverable tables
User guide drafts feature-refs: ["FEAT-007"] in frontmatter + link in Related section
ADRs Feature ID when the decision relates to a feature
Architecture docs Feature ID when describing a system aspect driven by a feature

8.3 Funding Cross-Reference Table

Lives in docs/features/catalogue.md and is mirrored in docs/funding/index.md:

## Funding Cross-Reference

| Feature | NC3Rs Contract 1 | NC3Rs Contract 2 | SSI/RSMF | SEBI/Gates |
|---------|------------------|-------------------|----------|------------|
| FEAT-001: Question Versioning | "Question editing" (P4, Outstanding) | "Question Editing" (FS4) | "Annotation question versioning" | — |
| FEAT-005: Project Groups | "Customisable project groups" (P4) | — | — | — |
| FEAT-006: Reconciliation | "In-app reconciliation" (P4) | — | — | — |
| FEAT-007: Screening Profiles | "Screening types" (P4) | — | — | — |

9. Open Questions Register

9.1 Per-Feature Open Questions

Each feature's README.md includes an "Open Questions" section using a consistent format:

## Open Questions

- [ ] **OQ-1**: {Question text} → {Context: who needs to decide, what's blocking}
- [x] **OQ-2**: {Question text} → **Decided: {decision}** ({date})

9.2 Aggregated Register

docs/features/_open-questions.md — generated by a script that harvests OQ sections from all feature docs:

# Open Questions Register

**Summary**: 27 open | 14 resolved | across 18 features

## By Domain

### Screening (8 open)
| Feature | ID | Question | Blocking? |
|---------|-----|---------|-----------|
| FEAT-007 | OQ-1 | Should profiles support versioning? | Yes — before implementation |
| FEAT-008 | OQ-3 | How does filtering handle studies added mid-review? | No |

### Annotation (12 open)
| ... |

## Blocking Decisions (require resolution before implementation can start)
| Feature | ID | Question |
| ... |

9.3 Why This Matters

For a grant-funded academic project: - For the team: Prevents building on unresolved assumptions - For funders: Shows which deliverables have design uncertainty - For new contributors: Identifies where input is needed - For planning: Open question count is a proxy for spec maturity


10. Codebase & Deployment as Source of Truth

10.1 The Problem

Documentation feature statuses can drift from reality. A feature might be marked "Planned" in docs but already partially implemented in the codebase. Or a feature might be marked "Completed" based on when code merged, but the corresponding service hasn't been deployed to production yet.

The actual sources of truth for feature status are:

  1. The codebase — what's implemented (source code, tests, feature flags)
  2. The cluster-gitops repo — what's deployed (which service versions are live in production/staging via ArgoCD config)
  3. The documentation — what's planned and specified (specs, roadmaps, open questions)

Documentation should be the source of truth for what a feature is and how it works, but it shouldn't be the sole authority on whether a feature is done. That's derivable from the code and deployment state.

10.2 Status Determination

Feature status in the catalogue should be determined by cross-referencing multiple sources:

Status Determined by
Draft Feature doc exists with initial spec, no implementation started
In-Review Feature spec is written and under team review
Approved Spec is approved, ready for implementation
In-Progress Implementation has started — code exists on a branch or in main, but the feature isn't fully deployed
Completed Feature code is merged to main AND deployed to production (verified via cluster-gitops)
Deprecated Feature has been superseded or abandoned

The key distinction is between In-Progress and Completed. A feature should only be Completed when: - The code is merged to main - The service version containing that code is deployed to production (check cluster-gitops/syrf/environments/production/*/config.yaml for the deployed chartTag) - Feature flags (if any) are enabled in production

10.3 How to Check What's Actually Deployed

The cluster-gitops repo contains the deployment state. To verify a feature's deployment status:

# Check what version of a service is deployed in production
# In cluster-gitops repo:
cat syrf/environments/production/{service}/config.yaml  # look at chartTag/image tag

# Compare against the service version that contains the feature's code
# In syrf repo:
git log --oneline --grep="FEAT-007" --all  # find which commits relate to this feature

10.4 Feature Status Audit

As part of this reorganisation, each feature's status should be audited against the codebase:

  1. Check for existing implementation: Search the codebase for entities, services, and UI components that a feature describes. If they already exist, the feature isn't Planned — it's at least In-Progress or Completed.
  2. Check feature flags: Some features may be gated behind feature flags in the Angular app (src/services/web/src/app/generated/feature-flags.*.ts). A feature behind a disabled flag isn't fully Completed.
  3. Check deployment: Cross-reference the service version in production (cluster-gitops) against the git history to confirm deployed features.

This audit doesn't need to be fully automated immediately, but the catalogue should record the date of last status verification and the source used:

status: "Completed"
status-verified: 2026-03-16
status-source: "Code merged (PR #2300), deployed to production (api v3.15.2)"

10.5 Living Documentation Principle

The feature specs in docs/features/ should be updated as implementation progresses: - Before implementation: Spec is the plan — what we intend to build - During implementation: Spec is updated with implementation decisions that deviate from the original plan - After implementation: Spec becomes reference documentation — what was actually built

This means feature docs serve double duty: planning documents before implementation, and reference documentation after. The status field tells the reader which role the document is currently playing.


11. Fixing the Documentation Validation Pipeline

11.1 The Problem

Documentation validation is currently a significant pain point that wastes developer time. Analysis of the last 100 CI runs of the docs-validation.yml workflow reveals recurring failure patterns. These failures block PRs because docs validation is embedded in the CI/CD pipeline (ci-cd.yml) as a prerequisite for Docker builds.

11.2 Observed Failure Patterns (from CI History)

Analysis of all unique failure messages across recent CI runs, ranked by frequency:

Count Failure Root Cause
12 docs/guides/local-dev-setup.md: Missing required fields: doc-type author zenhub-ticket New doc created without frontmatter template
12 Documentation indexes are stale! Index not regenerated after adding/modifying docs
10 Broken link to '../../plans/2026-02-15-annotation-versioning-design.md' File was moved/deleted but 7+ docs still reference it
6 Broken link to '../features/lambda-ack-gitops/review-fixes-plan.md' Relative link uses wrong base path (../features/features/... — double features/)
6 docs/features/data-export-refactoring-plan.md: Missing required fields Doc created without required frontmatter
5 MkDocs navigation is stale! Nav not regenerated after adding docs
5 docs/planning/product-features-roadmap.md: Missing required fields Same — missing frontmatter
5 Missing YAML front matter (must start with ---) Doc has no frontmatter at all
2 Invalid doc-type 'Planning' Invented doc-type not in allowed list
2 Invalid status 'Active' Invented status not in allowed list
2 Feature doc missing required 'category' field Feature doc created without category
1 Invalid doc-type 'Planning' in auth0-openiddict-bff-migration.md Most recent failure (2026-03-16)

11.3 Root Cause Analysis

These failures fall into four categories:

Category A: Stale Generated Files (indexes + nav) — Most Frequent

The problem: When a developer adds or modifies a .md file in docs/, the index files and MkDocs nav must be regenerated. The pre-commit hooks run the generators and fail if the output has changed. But this creates a two-commit workflow: first commit fails, developer runs generators, stages the generated files, commits again.

Why the hooks don't catch it reliably: - The .husky/pre-commit hook and .pre-commit-config.yaml hooks both run generators, but they can't auto-stage files during a commit — they can only fail and tell the developer to stage manually - The husky hook runs generate-indexes.sh and then checks git diff --quiet on the generated files. But validate-docs.sh also calls generate-indexes.sh internally, creating a redundant and confusing double-run - If a developer uses --no-verify to bypass hooks (common when frustrated by repeated failures), the stale files go straight to CI

Why this keeps happening: Every PR that touches docs/ triggers this. The fundamental design assumes developers will always run pre-commit hooks and manually stage generated output. This assumption fails routinely.

Category B: Missing/Invalid Frontmatter — Second Most Frequent

The problem: New docs are created without the required YAML frontmatter, or with invalid values for constrained fields (doc-type, status, category).

Why the hooks don't catch it: They do — but only when docs/**/*.md files are staged. Developers creating docs on feature branches may not notice the frontmatter requirements until CI fails. The valid values aren't discoverable without reading the validation script source.

Why this keeps happening: There's no scaffolding tool that creates docs with correct frontmatter. The templates exist in docs/README.md but developers don't always use them.

The problem: Internal links between docs break when files are moved, renamed, or deleted. The most common case: ../../plans/2026-02-15-annotation-versioning-design.md is referenced by 7 different docs but the target file was moved or deleted. Also: relative paths that accidentally double a directory component (../features/features/...).

Why the hooks don't catch it: The broken link checker runs in validate-docs.sh, but it resolves links relative to the file's directory using realpath. This works locally but the path resolution can differ in CI (different checkout location). More importantly, broken links from moving a file are only detectable after the move — by which time the developer has already committed.

Why this keeps happening: There's no refactoring tool for doc renames that updates all references. Moving a file is a manual process and it's easy to miss cross-references.

Category D: Validation Script Architecture — Cross-Cutting

The problem: validate-docs.sh conflates multiple concerns and has internal coupling: - It runs generate-indexes.sh internally (line ~287), then checks git diff, then tries to git checkout -- to restore. This means validate-docs has side effects — it modifies the working tree - The index staleness check inside validate-docs.sh overlaps with the dedicated check-indexes.sh hook, creating confusion about which script is authoritative - In CI, the _validate-docs-indexes.yml workflow runs indexes, nav, and frontmatter as separate steps but uses set +e for frontmatter validation, meaning the step "passes" even when validation fails — the failure is only captured in $GITHUB_OUTPUT and surfaced in the "Determine overall validity" step, making the actual error hard to find in logs

11.4 Proposed Fixes

Fix 1: Auto-Stage Generated Files in Pre-Commit Hook

Replace the "fail and tell the developer to stage" pattern with auto-staging:

# In .husky/pre-commit — replace the current index/nav check with:
if git diff --cached --name-only | grep -qE "$DOCS_PATTERN"; then
  echo "📚 Regenerating documentation artifacts..."

  ./docs/scripts/generate-indexes.sh
  python3 ./docs/scripts/generate-mkdocs-nav.py

  # Auto-stage the generated files
  git add docs/*/index.md mkdocs.yml 2>/dev/null

  # Now validate frontmatter (no side effects)
  ./docs/scripts/validate-docs.sh --skip-indexes --skip-links
  if [ $? -ne 0 ]; then
    echo "❌ Documentation validation failed! Fix the issues above."
    exit 1
  fi

  echo "✅ Documentation is valid (generated files auto-staged)"
fi

This eliminates the two-commit workflow entirely. The pre-commit hook generates and stages in one step.

Note: git add during a pre-commit hook does add files to the current commit. The current hook comment "Note: git add during pre-commit doesn't add to the current commit" is incorrect — this is a common misconception. Git's pre-commit hook runs after the index is built but before the commit object is created. git add at this point updates the index, and the commit uses the updated index.

Decouple the validation concerns so they can be run independently:

# validate-docs.sh gains flags:
# --skip-indexes    Skip the index staleness check (handled by pre-commit separately)
# --skip-links      Skip the broken link check (slow, run only in CI)
# --skip-planning   Skip planning doc "temporary" check

This lets the pre-commit hook run just frontmatter validation (fast), while CI runs the full suite including link checking.

Fix 3: New Doc Scaffolding Script

Create docs/scripts/new-doc.sh that scaffolds a new document with correct frontmatter:

./docs/scripts/new-doc.sh feature screening-profiles
# Creates docs/features/screening-profiles/README.md with full template

./docs/scripts/new-doc.sh planning my-analysis
# Creates docs/planning/my-analysis.md with Discussion frontmatter

./docs/scripts/new-doc.sh how-to setup-something
# Creates docs/how-to/setup-something.md with How-To frontmatter

This eliminates the "missing frontmatter" failure class entirely by making it impossible to create a doc without correct frontmatter.

Create docs/scripts/move-doc.sh that moves a doc and updates all references:

./docs/scripts/move-doc.sh docs/plans/old-plan.md docs/architecture/old-plan.md
# Moves the file and updates all relative links in docs/ that reference it

This eliminates the "broken link after move" failure class.

Fix 5: Improve CI Error Reporting

Update _validate-docs-indexes.yml to surface errors clearly:

  • Run each validation step with continue-on-error: false and use step-level failure instead of output variables
  • Annotate failures directly on the PR using ::error file=... with specific file and line information
  • Group related errors (e.g., "7 docs reference a deleted file") into a single actionable message

Fix 6: Pre-Commit Config Simplification

The current setup has overlapping hooks: .husky/pre-commit runs index generation and nav generation, AND .pre-commit-config.yaml has separate hooks for the same things. This means: - If a developer uses husky (npm-based), they get one set of hooks - If a developer uses pre-commit (Python-based), they get another set - If both are installed, they might conflict

Consolidate to a single hook system and document which one is canonical.

11.5 Impact on This Reorganisation

The directory restructure in Section 5 will move ~30 files. Without the link refactoring tool (Fix 4), this would create dozens of broken link failures. The fixes should be implemented before or as part of the file moves:

  1. Build the move-doc.sh script first
  2. Use it for all file moves during the restructure
  3. Update the pre-commit hook (Fix 1) to auto-stage generated files
  4. Run the full validation suite to confirm zero failures before merging

12. Tooling

Tooling is a first-class deliverable, not deferred. Scripts in docs/scripts/:

12.1 New Scripts

new-doc.sh — Document Scaffolding

Creates new docs with correct frontmatter based on doc-type:

./docs/scripts/new-doc.sh feature my-feature     # → docs/features/my-feature/README.md
./docs/scripts/new-doc.sh platform my-platform    # → docs/platform/my-platform/README.md
./docs/scripts/new-doc.sh planning my-analysis    # → docs/planning/my-analysis.md
./docs/scripts/new-doc.sh how-to do-something     # → docs/how-to/do-something.md
./docs/scripts/new-doc.sh adr 008-my-decision     # → docs/decisions/ADR-008-my-decision.md

Moves a doc and updates all references across docs/:

./docs/scripts/move-doc.sh docs/features/old.md docs/architecture/old.md
# 1. Moves the file
# 2. Finds all .md files in docs/ that contain relative links to the old path
# 3. Rewrites those links to point to the new path
# 4. Reports what was updated

validate-feature-frontmatter.sh — Feature-Specific Validation

Validates feature docs have the extended frontmatter schema:

# Checks:
# - feature-id exists and matches FEAT-NNN or PLAT-NNN pattern
# - feature-id is unique across all docs
# - depends-on and enables reference valid feature IDs
# - domain is one of the allowed values
# - release is one of Foundation | R1 | R2 | R3 | Standalone
# - phases is an array of numbers

generate-open-questions.sh — Open Questions Register

Harvests open questions from all feature docs and generates docs/features/_open-questions.md:

# Scans docs/features/**/*.md and docs/platform/**/*.md for lines matching:
#   - [ ] **OQ-N**: ... (open)
#   - [x] **OQ-N**: ... (resolved)
# Groups by domain (read from frontmatter)
# Outputs aggregated register with counts

audit-feature-status.sh — Status Verification

Cross-references feature statuses against the codebase and cluster-gitops:

# For each feature with status "Completed":
# - Checks that related code exists in main
# - Checks feature flags (if any) are enabled
# - Optionally checks cluster-gitops for production deployment
# For each feature with status "Draft" or "Planned":
# - Warns if related code already exists (status may be outdated)

12.2 Updates to Existing Scripts

validate-docs.sh: - Add --skip-indexes, --skip-links, --skip-planning flags - Remove internal generate-indexes.sh call (decouple concerns) - Add --check-feature-frontmatter flag to run extended validation - Accept docs/platform/ as a valid directory for feature docs

generate-indexes.sh: - Handle docs/platform/ as a new directory - Read feature-id from frontmatter and include in index output

generate-mkdocs-nav.py: - Handle docs/platform/ and docs/roadmap/ as new sections - Read feature-id and domain from feature frontmatter - Group features by domain in the nav - Prefix nav titles with feature IDs - Place archived features in an Archive subsection

.husky/pre-commit: - Auto-stage generated files instead of failing - Run validate-docs.sh --skip-indexes --skip-links for fast frontmatter-only validation - Remove redundant overlap with .pre-commit-config.yaml


13. Execution Plan

This is a single, comprehensive reorganisation. The order is designed so that tooling is built first (to support the restructure), then the restructure itself, then validation and cross-references.

Step 1: Fix the Validation Pipeline First

Before touching any docs, fix the validation tooling so the restructure doesn't create a cascade of CI failures:

  1. Add --skip-indexes, --skip-links, --skip-planning flags to validate-docs.sh
  2. Remove the internal generate-indexes.sh call from validate-docs.sh
  3. Update .husky/pre-commit to auto-stage generated files
  4. Write docs/scripts/move-doc.sh — the link-safe file move tool
  5. Write docs/scripts/new-doc.sh — the document scaffolding tool
  6. Verify all existing docs pass validation before proceeding

Step 2: Create New Directories and Move Files

Using move-doc.sh for every file move to keep links intact:

  1. Create docs/platform/, docs/roadmap/, docs/features/_archive/
  2. Move platform capabilities from docs/features/docs/platform/
  3. Move migration plans from docs/features/docs/roadmap/migrations/
  4. Move analysis/reference docs from docs/features/docs/architecture/
  5. Move completed/deprecated items from docs/features/docs/features/_archive/
  6. Merge duplicate directories (annotation-management-reconciliation → reconciliation, etc.)
  7. Rename files to match canonical names

Step 3: Add Feature IDs and Standardise Frontmatter

  1. Assign feature-id to every remaining feature and platform doc
  2. Add missing required frontmatter fields (domain, release, phases, depends-on, enables)
  3. Add funding-refs where applicable (cross-reference with funding docs)

Step 4: Audit Feature Statuses Against the Codebase

  1. For each feature, check if implementation code exists in the codebase
  2. Cross-reference with cluster-gitops for deployment status
  3. Check feature flags for gated features
  4. Update status values and add status-verified date to frontmatter
  5. Document discrepancies in the catalogue

Step 5: Create the Feature Catalogue

  1. Write docs/features/catalogue.md with all features identified, ID'd, and described
  2. Include funding cross-reference table
  3. Include feature relationship Mermaid diagram
  4. Include status summary with verification dates

Step 6: Create the Open Questions Register

  1. Write docs/scripts/generate-open-questions.sh
  2. Standardise OQ format in existing feature docs
  3. Generate docs/features/_open-questions.md

Step 7: Fix All Cross-References

  1. Run link checker across all docs and fix any broken links from the restructure
  2. Add feature-id references to funding docs
  3. Add feature-refs frontmatter to user guide drafts
  4. Annotate the product roadmap with feature IDs per phase

Step 8: Update MkDocs Navigation

  1. Rewrite the Features section of mkdocs.yml to use domain grouping
  2. Add Product Roadmap as a new top-level section
  3. Add Platform as a new top-level section
  4. Move archived features to Archive subsection
  5. Update generate-mkdocs-nav.py to understand the new structure

Step 9: Build Remaining Validation Tooling

  1. Write docs/scripts/validate-feature-frontmatter.sh
  2. Write docs/scripts/audit-feature-status.sh
  3. Update docs/scripts/generate-indexes.sh for new directory layout
  4. Run full validation suite and confirm zero failures

Step 10: Update Framework Documentation

  1. Update docs/README.md to describe the feature framework, catalogue, and cross-reference system
  2. Update docs/how-to/feature-planning-workflow.md to reference the new template, ID scheme, and new-doc.sh
  3. Update docs/architecture/documentation-map.md to reflect the new structure
  4. Update AGENTS.md if documentation workflow guidance needs updating

14. What Success Looks Like

After this reorganisation:

  1. A new team member opens docs/features/catalogue.md and within 2 minutes understands what SyRF is building, how features relate, and which are most important.

  2. A funder looks at the funding cross-reference table and immediately sees which of their deliverables maps to which feature and what the status is.

  3. A developer picking up a feature sees its ID, dependencies, what it enables, what's decided, and what's still open — all from the feature's README.md.

  4. A project manager pulls up docs/features/_open-questions.md and sees where design uncertainty lives, what's blocking, and what can proceed.

  5. Every document that references a feature uses the same ID (FEAT-007), making it trivially easy to search for all mentions with grep "FEAT-007" docs/ -r.

  6. The MkDocs navigation is organised by domain (annotation → screening → reconciliation → export), matching how a researcher thinks about systematic reviews — not how the filesystem is laid out.

  7. Platform capabilities (infrastructure, DevOps) are clearly separated from product features, so a funder reading about what SyRF does for researchers isn't distracted by MongoDB testing strategies.

  8. Completed and deprecated work is visibly archived, not cluttering the active feature list.

  9. Feature statuses are verified against the codebase and deployment state, not just what someone wrote in a doc months ago.

  10. Documentation validation doesn't block PRs unnecessarily. Pre-commit hooks auto-stage generated files, scaffolding tools prevent frontmatter mistakes, and file-move tooling keeps links intact. The "fix docs validation" commit pattern (fix(docs): regenerate stale indexes) becomes a thing of the past.

  11. Validation scripts catch real inconsistencies — missing feature IDs, broken cross-references, orphan dependencies — without false positives from stale generated files.


15. Open Questions About This Plan

  • OQ-1: Should the Deduplication feature get its own top-level directory? → Decided: Yes — gets its own docs/features/deduplication/ directory. It's a major feature (Phase 12, ASySD integration, merge wizard) and deserves first-class status.
  • OQ-2: Should completed/deprecated features be in an Archive nav section or removed? → Decided: Archive section — keeps completed work discoverable for historical context.
  • OQ-3: Should user guide drafts be renamed from phase-based to feature-ID-based? → Decided: Rename to feature-ID-based (e.g., FEAT-007-screening-profiles.md) for consistency with the rest of the system.
  • OQ-4: Should docs/planning/ be slimmed? → Decided: Clean up now — archive stale items as part of this reorganisation.
  • OQ-5: Where should annotation-questions/ live? → Decided: Investigate first — check codebase and feature flags during the full audit to determine if annotation question management is fully complete or still in progress. If complete, move to docs/architecture/; if in progress, keep in docs/features/ as a reference doc.
  • OQ-6: Which hook system? → Decided: Husky only — remove .pre-commit-config.yaml overlap, keep .husky/pre-commit as the canonical system.
  • OQ-7: How thorough should the status audit be? → Decided: Full audit — trace every feature's implementation across all services, verify deployment via cluster-gitops, and document evidence.
  • OQ-8: Should move-doc.sh handle nav updates? → Decided: Separate stepsmove-doc.sh handles file moves and link updates only; nav regeneration remains a separate generate-mkdocs-nav.py step.