# Strict TDD Module — Verify Phase > **This module is loaded ONLY when Strict TDD Mode is enabled AND a test runner is available.** > If you are reading this, the orchestrator already verified both conditions. Follow every instruction. ## TDD Verification Philosophy When Strict TDD Mode is active, verification goes beyond "does the code work?" to "was the code built correctly?" — meaning: was TDD actually followed? The apply phase reports TDD evidence; your job is to validate that evidence against reality. ## Step 5a: TDD Compliance Check (includes Assertion Quality Audit) Read the `apply-progress` artifact and verify that TDD was actually followed: ``` Read apply-progress artifact: ├── Find the "TDD Cycle Evidence" table ├── FOR EACH task row: │ ├── RED column: │ │ ├── Must say "✅ Written" │ │ ├── Verify: test file EXISTS in the codebase │ │ └── Flag: CRITICAL if test file does not exist │ │ │ ├── GREEN column: │ │ ├── Must say "✅ Passed" │ │ ├── Cross-reference with Step 5b test execution results: │ │ │ └── The test file listed must PASS when you run it │ │ └── Flag: CRITICAL if test fails now (was it really green?) │ │ │ ├── TRIANGULATE column: │ │ ├── If "✅ N cases" → verify N test cases exist in the test file │ │ ├── If "➖ Single" → verify spec truly has only one scenario for this task │ │ └── Flag: WARNING if spec has multiple scenarios but only 1 test case │ │ │ ├── SAFETY NET column: │ │ ├── If "✅ N/N" → existing tests were run before modification (good) │ │ ├── If "N/A (new)" → verify the file was actually NEW (not modified) │ │ └── Flag: WARNING if file was modified but safety net shows "N/A" │ │ │ └── REFACTOR column: │ ├── Not strictly verifiable (subjective quality) │ └── Skip verification, trust the report │ ├── If NO "TDD Cycle Evidence" table found: │ └── Flag: CRITICAL — apply phase did not report TDD evidence │ (Strict TDD was enabled but apply did not follow the protocol) │ └── Summary: "{N}/{total} tasks have complete TDD evidence" ``` ## Step 5 Expanded: Test Layer Validation Classify ALL test files related to this change by their testing layer: ``` Scan test files created/modified by this change: ├── Classify each test file: │ ├── Unit test: tests a single function/class in isolation │ │ └── Indicators: no render(), no page., no HTTP calls, mocked dependencies │ ├── Integration test: tests component interaction or user behavior │ │ └── Indicators: render(), screen., userEvent., testing-library imports │ ├── E2E test: tests full system through real browser/HTTP │ │ └── Indicators: page.goto(), playwright/cypress imports, browser context │ └── Unknown: cannot classify → report as-is │ ├── Report distribution: │ ├── Unit: {N} tests across {N} files │ ├── Integration: {N} tests across {N} files │ ├── E2E: {N} tests across {N} files │ └── Total: {N} tests │ ├── Cross-reference with capabilities: │ ├── If integration tests exist but tools not in capabilities → how? │ ├── If E2E tests exist but tools not in capabilities → how? │ └── Flag: WARNING if tests use tools not detected in capabilities │ └── For each spec scenario: note which layer covers it └── Flag: SUGGESTION if critical business logic only has unit tests (only if integration/E2E tools are available) ``` ## Step 5d Expanded: Changed File Coverage When coverage tool is available, report coverage for CHANGED files specifically: ``` IF coverage tool available (from cached capabilities): ├── Run: {test_command} --coverage (or equivalent) ├── Parse the coverage report ├── Filter to ONLY files created or modified in this change │ (get file list from apply-progress "Files Changed" table) ├── Report per-file: │ ├── File path │ ├── Line coverage % │ ├── Branch coverage % (if available) │ ├── Uncovered line ranges (specific lines, not just %) │ └── Flag per file: │ ├── ≥ 95% → ✅ Excellent │ ├── ≥ 80% → ⚠️ Acceptable │ └── < 80% → ⚠️ Low (list uncovered lines) ├── Report aggregate: │ ├── Average coverage of changed files │ ├── Total uncovered lines in changed files │ └── Compare to threshold if configured └── Flag: WARNING if any changed file < 80% coverage IF coverage tool NOT available: └── Report: "Coverage analysis skipped — no coverage tool detected" (NOT a failure — just not available) ``` ## Step 5e: Quality Metrics (if tools available) Run quality checks ONLY on changed files, ONLY if tools are available: ``` Read quality tools from cached capabilities: IF linter available: ├── Run linter on changed files only ├── Report: errors and warnings └── Flag: WARNING for errors, SUGGESTION for warnings IF type checker available: ├── Run type checker (usually whole-project, not per-file) ├── Filter output to changed files ├── Report: type errors in changed files └── Flag: WARNING for type errors IF neither available: └── Report: "Quality metrics skipped — no tools detected" ``` ## Report Template Extension When Strict TDD Mode is active, your verification report MUST include these additional sections: ```markdown ### TDD Compliance | Check | Result | Details | |-------|--------|---------| | TDD Evidence reported | ✅ / ❌ | {Found in apply-progress / Missing} | | All tasks have tests | ✅ / ❌ | {N}/{total} tasks have test files | | RED confirmed (tests exist) | ✅ / ⚠️ | {N}/{total} test files verified | | GREEN confirmed (tests pass) | ✅ / ❌ | {N}/{total} tests pass on execution | | Triangulation adequate | ✅ / ⚠️ / ➖ | {N} tasks triangulated / {N} single-case | | Safety Net for modified files | ✅ / ⚠️ | {N}/{total} modified files had safety net | **TDD Compliance**: {N}/{total} checks passed --- ### Test Layer Distribution | Layer | Tests | Files | Tools | |-------|-------|-------|-------| | Unit | {N} | {N} | {tool} | | Integration | {N} | {N} | {tool or "not installed"} | | E2E | {N} | {N} | {tool or "not installed"} | | **Total** | **{N}** | **{N}** | | --- ### Changed File Coverage | File | Line % | Branch % | Uncovered Lines | Rating | |------|--------|----------|-----------------|--------| | `path/to/file.ext` | 95% | 90% | — | ✅ Excellent | | `path/to/other.ext` | 82% | 75% | L45-48, L62 | ⚠️ Acceptable | | `path/to/new.ext` | 100% | 100% | — | ✅ Excellent | **Average changed file coverage**: {N}% {or "Coverage analysis skipped — no coverage tool detected"} --- ### Assertion Quality | File | Line | Assertion | Issue | Severity | |------|------|-----------|-------|----------| | ... | ... | ... | ... | ... | **Assertion quality**: {N} CRITICAL, {N} WARNING {or "✅ All assertions verify real behavior"} --- ### Quality Metrics **Linter**: ✅ No errors / ⚠️ {N} warnings / ❌ {N} errors / ➖ Not available **Type Checker**: ✅ No errors / ❌ {N} errors / ➖ Not available ``` ## Step 5f: Assertion Quality Audit (MANDATORY) Scan ALL test files created or modified by this change and check for trivial/meaningless assertions: ``` FOR EACH test file related to the change: ├── Read the file content ├── Scan for BANNED assertion patterns: │ ├── Tautologies: expect(true).toBe(true), assert True, expect(1).toBe(1) │ ├── Orphan empty checks: expect(result).toEqual([]) or assert len(result) == 0 │ │ └── UNLESS there is a companion test with same setup that asserts NON-EMPTY │ ├── Type-only assertions used alone: toBeDefined(), not.toBeNull(), typeof checks │ │ └── These are OK if COMBINED with value assertions in the same test │ ├── Assertions that never call production code (no function call, no render, no request) │ ├── Ghost loops: assertions inside for/forEach over queryAll/filter results │ │ └── Check if the collection could be empty — if so, the assertions NEVER RUN │ │ Flag: CRITICAL — a loop over an empty array is a test that ALWAYS passes │ ├── Incomplete TDD cycle: test passes because preconditions prevent code from running │ │ └── e.g., testing behavior of a component that is never rendered due to state │ │ Flag: CRITICAL — test must set up conditions where the code path IS exercised │ ├── Smoke-test-only: render() + toBeInTheDocument() without behavioral assertions │ │ └── "Renders without crash" is NOT a valid test — it must assert WHAT was rendered │ │ Flag: WARNING — smoke tests do not count toward TDD coverage │ ├── Implementation detail coupling: assertions on CSS classes, internal state, mock call counts │ │ └── expect(el.className).toContain("text-xs") or expect(mock.calls.length).toBe(3) │ │ Flag: WARNING — tests must assert behavior, not implementation │ └── Mock/assertion ratio: count vi.mock() calls vs expect() calls per test file │ └── If mocks > 2× assertions → Flag: WARNING — "Mock-heavy test ({N} mocks, {N} assertions)" │ Recommend: extract logic to pure function or move to higher test layer │ ├── For each violation found: │ ├── Record: file, line number, the assertion, why it's trivial │ └── Classify: │ ├── CRITICAL: tautology (expect(true).toBe(true)) — test proves NOTHING │ ├── CRITICAL: assertion without production code call — test exercises nothing │ ├── CRITICAL: ghost loop — assertions inside loop over possibly-empty collection │ ├── WARNING: empty collection without companion non-empty test │ ├── WARNING: type-only assertion without value assertion │ ├── WARNING: smoke-test-only — render + toBeInTheDocument without behavioral check │ ├── WARNING: CSS class / implementation detail assertion │ └── WARNING: mock-heavy test (mocks > 2× assertions) — wrong test layer │ ├── Check triangulation quality: │ ├── Count distinct test cases per behavior │ ├── If only 1 test case exists for a behavior with multiple spec scenarios: │ │ └── Flag: WARNING — "Insufficient triangulation for {behavior}" │ ├── If all test cases assert the SAME type of value (e.g., all check empty arrays): │ │ └── Flag: WARNING — "No variance in test expectations — all assert empty/trivial" │ └── A well-triangulated behavior has tests asserting DIFFERENT expected values │ └── Summary: "{N} trivial assertions found across {N} files" ``` ### Assertion Quality Report Table Include this table in the verification report when any issues are found: ```markdown ### Assertion Quality | File | Line | Assertion | Issue | Severity | |------|------|-----------|-------|----------| | `path/test.ts` | 15 | `expect(true).toBe(true)` | Tautology — proves nothing | CRITICAL | | `path/test.ts` | 23 | `expect(result).toEqual([])` | Empty without companion non-empty test | WARNING | | `path/test.ts` | 31 | `expect(result).toBeDefined()` | Type-only — no value asserted | WARNING | **Assertion quality**: {N} CRITICAL, {N} WARNING ``` If zero issues found, report: "**Assertion quality**: ✅ All assertions verify real behavior" ## Rules (Strict TDD Verify specific) - ALWAYS check the TDD Cycle Evidence table from apply-progress — it's the primary artifact - ALWAYS cross-reference reported test files against actual execution — don't trust the report blindly - ALWAYS run the Assertion Quality Audit (Step 5f) — trivial tests are WORSE than missing tests - If apply-progress has no TDD evidence table, flag as CRITICAL — the protocol was not followed - If tautology assertions are found (expect(true).toBe(true)), flag as CRITICAL — these MUST be rewritten - Coverage and quality metrics are informational, NOT blocking — only flag as WARNING, never CRITICAL - Test layer distribution is informational — SUGGESTION level only - DO NOT fix issues — only report. The orchestrator decides. - If coverage/quality tools are not available, say so cleanly and move on — never flag missing tools as failures