|
| 1 | +# ADR-003: TDD as a Mandatory Pipeline Gate |
| 2 | + |
| 3 | +## Status |
| 4 | + |
| 5 | +Accepted |
| 6 | + |
| 7 | +## Date |
| 8 | + |
| 9 | +2026-03-29 |
| 10 | + |
| 11 | +## Context |
| 12 | + |
| 13 | +Nerva's `/build-from-schema` pipeline generates route handlers, middleware, and service code from an OpenAPI specification. Code generation introduces a specific risk: **generated code can appear correct without actually matching the contract it was generated from.** Without tests that independently verify the OpenAPI contract, there is no guarantee that the generated API behaves as specified. |
| 14 | + |
| 15 | +The pipeline has 10 phases. The question is whether integration tests should be written before route handlers (TDD, phases 2 then 3) or after (traditional testing, phases 3 then a later test phase). |
| 16 | + |
| 17 | +Key considerations: |
| 18 | + |
| 19 | +- **The OpenAPI spec is the contract.** Tests derived from the spec verify that the API conforms to what was promised, independent of how the code was generated. |
| 20 | +- **Code generation can drift.** If tests are written after handlers, there is a risk of writing tests that verify the implementation rather than the specification — testing what the code does rather than what it should do. |
| 21 | +- **Pipeline phases are sequential.** A hard gate between test writing (Phase 2) and code generation (Phase 3) ensures tests are never skipped or deferred. |
| 22 | +- **80% coverage threshold.** The quality gate at Phase 7 requires minimum 80% code coverage. Writing tests first makes this threshold achievable by design rather than requiring retroactive test writing. |
| 23 | + |
| 24 | +## Decision |
| 25 | + |
| 26 | +**TDD is enforced as a hard gate in the pipeline.** Phase 2 (test writing) must complete before Phase 3 (route generation) can begin. This is configured in `.claude/pipeline.config.json`: |
| 27 | + |
| 28 | +```json |
| 29 | +{ |
| 30 | + "tdd": { |
| 31 | + "enforced": true, |
| 32 | + "redPhaseRequired": true, |
| 33 | + "greenPhaseRequired": true, |
| 34 | + "coverageThreshold": 80, |
| 35 | + "integrationTestRequired": true, |
| 36 | + "contractTestRequired": true, |
| 37 | + "testExistenceGate": true |
| 38 | + } |
| 39 | +} |
| 40 | +``` |
| 41 | + |
| 42 | +The pipeline orchestration enforces this dependency: |
| 43 | + |
| 44 | +- Phase 2 (`tdd-scaffold`) depends on Phase 1 (`database-design`) and is **blocking**. |
| 45 | +- Phase 3 (`route-generation`) depends on Phase 2 (`tdd-scaffold`) and cannot start until all tests are confirmed failing (RED phase). |
| 46 | + |
| 47 | +## Consequences |
| 48 | + |
| 49 | +### Positive |
| 50 | + |
| 51 | +- **Tests verify the spec, not the implementation.** Because tests are written from the OpenAPI specification before any handler code exists, they are an independent check on contract conformance. |
| 52 | +- **Coverage by design.** Every endpoint has integration tests before its handler is written, so the 80% coverage threshold is met naturally rather than requiring a separate test-writing effort. |
| 53 | +- **Regressions caught immediately.** When modifying generated code or adding features, the pre-existing test suite catches contract violations. |
| 54 | +- **Tests serve as executable documentation.** Integration tests demonstrate how each endpoint is called and what it returns, serving as living documentation for API consumers. |
| 55 | +- **Confidence in refactoring.** Generated code can be restructured (extracting services, optimizing queries) with confidence that the test suite will catch behavioral changes. |
| 56 | + |
| 57 | +### Negative |
| 58 | + |
| 59 | +- **Slower initial pipeline execution.** Writing tests before code adds time to the generation process. The pipeline cannot produce a running API until both Phase 2 and Phase 3 complete. |
| 60 | +- **Test maintenance burden.** If the OpenAPI spec changes, tests must be updated before route handlers can be regenerated. This is by design (the spec is the source of truth) but adds friction to spec changes. |
| 61 | +- **Hard gate can block progress.** If tests cannot be written for a particular endpoint (e.g., due to external dependencies), the entire pipeline stalls. The `refactorPhaseOptional: true` config provides some flexibility, but the RED and GREEN phases are mandatory. |
| 62 | + |
| 63 | +### Neutral |
| 64 | + |
| 65 | +- The TDD approach follows the Red-Green-Refactor cycle: tests fail first (Red), handlers make them pass (Green), then code is cleaned up (Refactor, optional). This is a well-established methodology, not a Nerva invention — but enforcing it in an automated pipeline is unusual. |
0 commit comments