Skip to content

Continuous Integration (CI)

This document describes the CI workflow defined in .github/workflows/ci.yml.

Triggers

The workflow runs on:

  • push to main
  • pull requests targeting main

The workflow ignores documentation-only and temporary changes (README.md, AGENTS.md, docs/**, sandbox/**, tmp/**).

Jobs

1. frontend-ci

Purpose: validate frontend source quality and buildability (app/).

Steps:

  1. npm ci
  2. npm run lint
  3. npm run build

2. graph-validation

Purpose: validate curriculum graph/data integrity and schema constraints.

Steps:

  1. npm ci (in app/)
  2. npm run validate:graph
  3. npm run validate:view-filters
  4. npm run check:he-math-duration-projection
  5. npm run quality:source-coverage-audit:check
  6. npm run check:generated-doc-notices
  7. npm run check:generated-status-registry
  8. npm run check:docs-links
  9. npm run check:docs-indexes
  10. npm run validate:composition-views
  11. npm run quality:memory-card-review:check:all
  12. python scripts/validate_schemas.py
  13. python scripts/validate_goal_ids_uuid.py
  14. python scripts/validate_hessen_upper_secondary_archive_paths.py
  15. python scripts/validate_hessen_upper_secondary_legacy_refs.py
  16. python scripts/validate_chemistry_exam_pipeline.py
  17. python scripts/validate_hessen_lower_secondary_archive_paths.py
  18. python scripts/validate_hessen_lower_secondary_legacy_refs.py
  19. python scripts/validate_bavaria_gymnasium_archive_paths.py
  20. python scripts/validate_bavaria_gymnasium_legacy_refs.py

The graph rule catalog is documented in:

  • docs/qa-ci/graph-validation-rules.md
  • docs/qa-ci/curriculum-quality-dashboard.md for the generated Workbench quality-status view
  • docs/qa-ci/curriculum-quality-maturity-and-routes.md for detailed M0-M4, QA-scope, route, and CQR-* semantics

validate:graph supports two enforcement profiles:

  • default: GVR-* rules are strict (failing)
  • legacy-warn mode: VALIDATE_GRAPH_STRICT_RULES=0 npm run validate:graph

Current scope note:

  • this job validates the full authored landscapes as committed
  • it additionally validates projected filtered learner graphs via validate:view-filters
  • it additionally enforces the Hessen Mathematik Sek-I G8/G9 duration projection via check:he-math-duration-projection; the check fails if G8/G9 evidence is missing, no G8/G9 differences are detected, or any canonical-duration-grade evidence link is not represented by authored year structure or duration-specific goalPlacements
  • it additionally enforces visible curriculum source coverage for the canonical Mathematik/Physik projections via quality:source-coverage-audit:check; global missing source-backed goals may remain as non-visible rollout backlog, but visible atomic goals must have direct source/mapping evidence or explicitly accepted surrogate evidence
  • it additionally checks registered generated Markdown status artifacts for the standard "do not edit manually" notice via check:generated-doc-notices
  • it additionally checks that the generated QA status artifact registry is in sync with app/scripts/generatedMarkdownNoticeRegistry.ts via check:generated-status-registry
  • it additionally checks local Markdown links under docs/ via check:docs-links
  • it additionally checks coverage for the main documentation indexes via check:docs-indexes
  • it additionally validates explicit learner-facing composition-view files via validate:composition-views
  • it additionally enforces all configured memory-card review ledgers via quality:memory-card-review:check:all; in the dashboard, missing CQR-302 review configuration blocks M6, while M5 remains the core curriculum QA level
  • it additionally enforces the Hessen Oberstufe retained-asset boundary: under curricula/DE/Gymnasium/input/DE-HE/abi, legacy Gymnasiale_Oberstufe path strings may only remain inside allowlisted raw archival provenance files from curricula/DE/Gymnasium/input/DE-HE/retained-asset-registry.json
  • it also enforces the Hessen Oberstufe repo-handoff boundary: the retired legacy tree must stay absent from the active repo, and active tooling/runtime/test surfaces may mention it only from the explicit allowlist in curricula/DE/Gymnasium/provenance/hessen-upper-secondary-retirement-registry.json
  • it validates the Hessen 2026 chemistry exam pipeline artifacts (slot_matrix.json, coverage_requirements.json, task_bank.json, and source-landscape release anchors)
  • it now also enforces the Hessen Sek-I retained-asset boundary: under curricula/DE/Gymnasium/input/DE-HE/lower-secondary, legacy Gymnasium_9_Mittelstufe path strings are forbidden in retained operational archive content
  • it also enforces the Hessen Sek-I repo-handoff boundary: active tooling/runtime/test surfaces may mention the lower-secondary legacy tree only from the explicit allowlist in curricula/DE/Gymnasium/provenance/hessen-lower-secondary-retirement-registry.json
  • the current CI scope for validate:view-filters is the reviewed canonical DE Gymnasium set (Mathematik, Physik, Chemie, Biologie, Informatik, Deutsch, Englisch, Französisch, Griechisch, Chinesisch, Geschichte, Politik und Wirtschaft, Musik, Latein, Spanisch, Wirtschaft, Overview)
  • the validator can be widened locally via APPLICABILITY_VALIDATION_SCOPE=all npm run validate:view-filters, but CI does not enforce that broader scope yet
  • reviewed residual APV-201 warning cases are tracked in docs/qa-ci/applicability-accepted-warnings.json and are reported as accepted warnings, not active warnings; APV-202 is reported as a diagnostic finding, not as warning debt

Optional local status snapshot:

cd app
npm run quality:curriculum-status

This writes docs/qa-ci/status/curriculum-quality-status.json and .md, which are read by the local Workbench route /quality-dashboard.

Optional MEM/FWU endpoint review snapshot:

cd app
npm run quality:mem-sparql-consistency

This writes the MEM audit and review-queue artifacts under docs/qa-ci/status/. It is not part of the blocking CI workflow because the MEM endpoint is external and currently exposes concrete curriculum data only for some configured jurisdictions. See docs/qa-ci/mem-sparql-consistency-runbook.md for the operational workflow.

3. backend-ci

Purpose: validate backend (backend/) via Gradle checks.

Steps:

  1. ./gradlew check

Status checks

All CI jobs must pass for a successful workflow run.

Run CI locally

From repository root:

bash run_ci.sh

This runs:

  1. app checks (validate:graph, validate:view-filters, check:he-math-duration-projection, quality:source-coverage-audit:check, check:generated-doc-notices, check:generated-status-registry, check:docs-links, check:docs-indexes, validate:composition-views, quality:memory-card-review:check:all, lint, build)
  2. repo-level data checks (validate_schemas.py, validate_goal_ids_uuid.py, validate_hessen_upper_secondary_archive_paths.py, validate_hessen_upper_secondary_legacy_refs.py, validate_chemistry_exam_pipeline.py, validate_hessen_lower_secondary_archive_paths.py, validate_hessen_lower_secondary_legacy_refs.py, validate_bavaria_gymnasium_archive_paths.py, validate_bavaria_gymnasium_legacy_refs.py)
  3. backend checks (./gradlew clean check --no-daemon)