## Frontend Coverage Fast-Recovery Plan (Minimum Threshold First) Date: 2026-02-16 Owner: Planning Agent Scope: Raise frontend unit-test coverage to project minimum quickly, without destabilizing ongoing flaky E2E CI validation. ## 1) Objective Recover frontend coverage to the minimum required gate with the fewest iterations by targeting the biggest low-coverage modules first, starting with high-yield API files and then selected large UI files. Primary gate: - Frontend lines coverage >= 85% (Codecov project `frontend` + local Vitest gate) Hard constraints: - Do not modify production behavior unless a testability blocker is proven. - Keep E2E stabilization work isolated (final flaky E2E already in CI validation). ## 2) Research Findings (Current Snapshot) Baseline sources discovered: - `frontend/coverage.log` (recent Vitest coverage table with uncovered ranges) - `frontend/vitest.config.ts` (default gate from `CHARON_MIN_COVERAGE`/`CPM_MIN_COVERAGE`, fallback `85.0`) - `codecov.yml` (frontend project target `85%`, patch target `100%`) Observed recent baseline in `frontend/coverage.log`: - All files lines: `86.91%` - Note: this run used a stricter environment gate (`88%`) and failed that stricter gate. ### Ranked High-Yield Candidates (size + low current line coverage) Estimates below use current file length as approximation and prioritize modules where added tests can cover many currently uncovered lines quickly. | Rank | Module | File lines | Current line coverage | Approx uncovered lines | Existing test target to extend | Expected project lines impact | |---|---|---:|---:|---:|---|---| | 1 | `src/api/securityHeaders.ts` | 188 | 10.00% | ~169 | `frontend/src/api/__tests__/securityHeaders.test.ts` | +2.0% to +3.2% | | 2 | `src/api/import.ts` | 137 | 31.57% | ~94 | `frontend/src/api/__tests__/import.test.ts` | +1.0% to +1.9% | | 3 | `src/pages/UsersPage.tsx` | 775 | 75.67% | ~189 | `frontend/src/pages/__tests__/UsersPage.test.tsx` | +0.5% to +1.3% | | 4 | `src/pages/Security.tsx` | 643 | 72.22% | ~179 | `frontend/src/pages/__tests__/Security.test.tsx` | +0.4% to +1.1% | | 5 | `src/pages/Uptime.tsx` | 591 | 74.77% | ~149 | `frontend/src/pages/__tests__/Uptime.test.tsx` | +0.4% to +1.0% | | 6 | `src/pages/SecurityHeaders.tsx` | 340 | 69.35% | ~104 | `frontend/src/pages/__tests__/SecurityHeaders.test.tsx` | +0.3% to +0.9% | | 7 | `src/pages/Plugins.tsx` | 391 | 62.26% | ~148 | `frontend/src/pages/__tests__/Plugins.test.tsx` | +0.3% to +0.9% | | 8 | `src/components/SecurityHeaderProfileForm.tsx` | 467 | 58.97% | ~192 | `frontend/src/components/__tests__/SecurityHeaderProfileForm.test.tsx` | +0.4% to +1.0% | | 9 | `src/components/CredentialManager.tsx` | 609 | 75.75% | ~148 | `frontend/src/components/__tests__/CredentialManager.test.tsx` | +0.3% to +0.8% | | 10 | `src/api/client.ts` | 71 | 34.78% | ~46 | `frontend/src/api/__tests__/client.test.ts` | +0.2% to +0.6% | Planning decision: - Start with API modules (`securityHeaders.ts`, `import.ts`, optional `client.ts`) for fastest coverage-per-test effort. - Move to large pages only if the threshold is still not satisfied. ## 3) Requirements in EARS Notation - WHEN frontend lines coverage is below the minimum threshold, THE SYSTEM SHALL prioritize modules by uncovered size and low coverage first. - WHEN selecting coverage targets, THE SYSTEM SHALL use existing test files before creating new test files. - WHEN collecting baseline and post-change metrics, THE SYSTEM SHALL use project-approved tasks/scripts only. - WHEN E2E is already being validated in CI, THE SYSTEM SHALL avoid introducing E2E test/config changes in this coverage effort. - IF frontend threshold is still not met after minimal path execution, THEN THE SYSTEM SHALL execute fallback targets in priority order until threshold is met. - WHEN coverage work is complete, THE SYSTEM SHALL pass frontend coverage gate, type-check, and manual pre-commit checks required by project testing instructions. ## 4) Technical Specification (Coverage-Only) ### In Scope - Frontend unit tests (Vitest) only. - Extending existing tests under: - `frontend/src/api/__tests__/` - `frontend/src/pages/__tests__/` - `frontend/src/components/__tests__/` ### Out of Scope - Backend changes. - Playwright test logic changes. - CI workflow redesign. - Product behavior changes unrelated to testability. ### No Schema/API Contract Changes - No backend API contract changes are required for this plan. - No database changes are required. ## 5) Phased Execution Plan ### Phase 0 — Baseline and Target Lock (single pass) Goal: establish current truth and exact gap to 85%. 1. Run approved frontend coverage task: - Preferred: VS Code task `Test: Frontend Coverage (Vitest)` - Equivalent script path: `.github/skills/scripts/skill-runner.sh test-frontend-coverage` 2. Capture baseline artifacts: - `frontend/coverage/coverage-summary.json` - `frontend/coverage/lcov.info` 3. Record baseline: - total lines pct - delta to 85% - top 10 uncovered modules (from `coverage.log`/summary) 4. Early-exit gate (immediately after baseline capture): - Read active threshold from the same gate source used by the coverage task (`CHARON_MIN_COVERAGE`/`CPM_MIN_COVERAGE`, fallback `85.0`). - IF baseline frontend lines pct is already >= active threshold, THEN stop further test additions for this plan cycle. Exit criteria: - Baseline numbers captured once and frozen for this cycle. - Either baseline is below threshold and Phase 1 proceeds, or execution exits early because baseline already meets/exceeds threshold. ### Phase 1 — Minimal Path (fewest requests/iterations) Goal: cross 85% quickly with smallest change set. Target set A (execute in order): 1. `frontend/src/api/__tests__/securityHeaders.test.ts` 2. `frontend/src/api/__tests__/import.test.ts` 3. `frontend/src/api/__tests__/client.test.ts` (only if needed after #1-#2) Test focus inside these files: - error mapping branches - non-2xx response handling - optional parameter/query serialization branches - retry/timeout/cancel edge paths where already implemented Validation after each target (or pair): - run frontend coverage task - read updated total lines pct - stop as soon as >= 85% Expected result: - Most likely to reach threshold within 2-3 targeted API test updates. ### Phase 2 — Secondary Path (only if still below threshold) Goal: add one large UI target at a time, highest projected return first. Target set B (execute in order, stop once >= 85%): 1. `frontend/src/pages/__tests__/UsersPage.test.tsx` 2. `frontend/src/pages/__tests__/Uptime.test.tsx` 3. `frontend/src/pages/__tests__/SecurityHeaders.test.tsx` 4. `frontend/src/pages/__tests__/Plugins.test.tsx` 5. `frontend/src/components/__tests__/SecurityHeaderProfileForm.test.tsx` 6. `frontend/src/pages/__tests__/Security.test.tsx` (de-prioritized because it is currently fully skipped; only consider if skip state is removed) Test focus: - critical uncovered conditional render branches - form validation and submit error paths - loading/empty/error states not currently asserted ### Phase 3 — Final Verification and Gates 1. E2E verification-first check (run-first policy): - Run `Test: E2E Playwright (Skill)` first. - Use `Test: E2E Playwright (Targeted Suite)` only when scoped execution is sufficient for the impacted area. - No E2E code/config changes are allowed in this plan. 2. Frontend coverage: - VS Code task `Test: Frontend Coverage (Vitest)` 3. Frontend type-check: - VS Code task `Lint: TypeScript Check` 4. Manual pre-commit checks: - VS Code task `Lint: Pre-commit (All Files)` 5. Confirm Codecov expectations: - project frontend target >= 85% - patch coverage target = 100% for modified lines ## 6) Baseline vs Post-Change Collection Protocol Use this exact protocol for both baseline and post-change snapshots: 1. Execute `Test: Frontend Coverage (Vitest)`. 2. Save metrics from `frontend/coverage/coverage-summary.json`: - lines, statements, functions, branches. 3. Keep `frontend/coverage/lcov.info` as Codecov upload source. 4. Compare baseline vs post: - absolute lines pct delta - per-target module line pct deltas Reporting format: - `Baseline lines: X%` - `Post lines: Y%` - `Net gain: (Y - X)%` - `Threshold status: PASS/FAIL` ## 6.1) Codecov Patch Triage (Explicit, Required) Patch triage must capture exact missing/partial patch ranges from Codecov Patch view and map each range to concrete tests. Required workflow: 1. Open PR Patch view in Codecov. 2. Copy exact missing/partial ranges into the table below. 3. Map each range to a specific test file and test case additions. 4. Re-run coverage and update status until all listed ranges are covered. Required triage table template: | File | Patch status | Exact missing/partial patch range(s) | Uncovered patch lines | Mapped test file | Planned test case(s) for exact ranges | Status | |---|---|---|---:|---|---|---| | `frontend/src/...` | Missing or Partial | `Lxx-Lyy`; `Laa-Lbb` | 0 | `frontend/src/.../__tests__/...test.ts[x]` | `it('...')` cases covering each listed range | Open / In Progress / Done | Rules: - Ranges must be copied exactly from Codecov Patch view (not paraphrased). - Non-contiguous ranges must be listed explicitly. - Do not mark triage complete until every listed range is covered by passing tests. ## 7) Risk Controls (Protect Ongoing Flaky E2E Validation) - No edits to Playwright specs, fixtures, config, sharding, retries, or setup. - No edits to `.docker/compose/docker-compose.playwright-*.yml`. - No edits to global app runtime behavior unless a testability blocker is proven. - Keep all changes inside frontend unit tests unless absolutely required. - Run E2E verification-first as an execution gate using approved task labels, but make no E2E test/config changes; keep flaky E2E stabilization scope in CI. ## 8) Minimal Path and Fallback Path ### Minimal Path (default) - Baseline once. - Apply the early-exit gate immediately after baseline capture. - Update tests for: 1) `securityHeaders.ts` 2) `import.ts` - Re-run coverage. - If >= 85%, stop and verify final gates. ### Fallback Path (if still below threshold) - Add `client.ts` API tests. - If still below, add one UI target at a time in this order: `UsersPage` -> `Uptime` -> `SecurityHeaders` -> `Plugins` -> `SecurityHeaderProfileForm` -> `Security (de-prioritized while fully skipped)`. - Re-run coverage after each addition; stop immediately when threshold is reached. ## 9) Config/Ignore File Recommendations (Only If Needed) Current assessment for this effort: - `.gitignore`: already excludes frontend coverage artifacts. - `codecov.yml`: already enforces frontend 85% and patch 100% with suitable ignores. - `.dockerignore`: already excludes frontend coverage/test artifacts from image context. - `Dockerfile`: no changes required for unit coverage-only work. Decision: - No config-file modifications are required for this coverage recovery task. ## 10) Acceptance Checklist - [ ] Baseline coverage collected with approved frontend coverage task. - [ ] Target ranking confirmed from largest-lowest-coverage modules. - [ ] Minimal path executed first (API targets before UI targets). - [ ] Early-exit gate applied after baseline capture. - [ ] Frontend lines coverage >= 85%. - [ ] TypeScript check passes. - [ ] Manual pre-commit run passes. - [ ] E2E verification-first gate executed with approved task labels (no E2E code/config changes). - [ ] No Playwright/E2E infra changes introduced. - [ ] Post-change coverage summary recorded. - [ ] Codecov patch triage table completed with exact missing/partial ranges and mapped tests. ## 11) Definition of Done (Coverage Task Specific) Done is achieved only when all are true: 1. Frontend lines coverage is >= 85% using project-approved coverage task output. 2. Coverage gains come from targeted high-yield modules listed in this plan. 3. Type-check and manual pre-commit checks pass. 4. No changes were made that destabilize or alter flaky E2E CI validation scope. 5. Codecov patch coverage expectations remain satisfiable (100% for modified lines). 6. Baseline/post-change metrics and final threshold status are documented in the task handoff. ## 12) Backend Patch-Coverage Remediation (Additive, Frontend Plan Intact) Date: 2026-02-16 Owner: Planning Agent Scope: Add backend-only remediation to recover Codecov patch coverage for changed backend lines while preserving existing frontend unit-test coverage work. ### 12.1 Objective and Constraints - Raise backend patch coverage by targeting missing/partial changed lines from Codecov Patch view. - Preserve all existing frontend coverage plan content and execution order; this section is additive only. - No E2E requirement for this backend remediation section. - Source of truth for prioritization and totals is the provided Codecov patch report. ### 12.2 Codecov Patch Snapshot (Source of Truth) Current patch coverage: **58.78378%** Files with missing/partial changed lines: | Priority | File | Patch % | Missing | Partial | |---|---|---:|---:|---:| | 1 | `backend/internal/services/mail_service.go` | 0.00% | 22 | 0 | | 2 | `backend/internal/crowdsec/hub_sync.go` | 0.00% | 10 | 6 | | 3 | `backend/internal/api/handlers/auth_handler.go` | 0.00% | 15 | 0 | | 4 | `backend/internal/services/backup_service.go` | 0.00% | 5 | 3 | | 5 | `backend/internal/services/proxyhost_service.go` | 55.88% | 14 | 1 | | 6 | `backend/internal/api/handlers/crowdsec_handler.go` | 30.00% | 9 | 5 | | 7 | `backend/internal/api/handlers/user_handler.go` | 72.09% | 6 | 6 | | 8 | `backend/internal/services/log_service.go` | 73.91% | 6 | 6 | | 9 | `backend/internal/api/handlers/import_handler.go` | 67.85% | 3 | 6 | | 10 | `backend/internal/cerberus/rate_limit.go` | 93.33% | 3 | 3 | Execution rule: **zero-coverage files are first-pass mandatory** for fastest patch gain. ### 12.3 Explicit Patch-Triage Table (Exact Range Placeholders + Test Targets) Populate exact ranges from local Codecov Patch output before/while implementing tests. | File | Codecov exact missing/partial range placeholders (fill from local output) | Mapped backend test file target(s) | Planned test focus for those exact ranges | Status | |---|---|---|---|---| | `backend/internal/services/mail_service.go` | Missing: `L-L`, `L-L` | `backend/internal/services/mail_service_test.go` | happy path send/build; SMTP/auth error path; boundary for empty recipient/template vars | Open | | `backend/internal/crowdsec/hub_sync.go` | Missing: `L-L`; Partial: `L-L` | `backend/internal/crowdsec/hub_sync_test.go` | happy sync success; HTTP/non-200 + decode/network errors; boundary/partial branch on optional fields and empty decisions list | Open | | `backend/internal/api/handlers/auth_handler.go` | Missing: `L-L`, `L-L` | `backend/internal/api/handlers/auth_handler_test.go` | happy login/refresh/logout response; invalid payload/credentials error path; boundary on missing token/cookie/header branches | Open | | `backend/internal/services/backup_service.go` | Missing: `L-L`; Partial: `L-L` | `backend/internal/services/backup_service_test.go` | happy backup/restore flow; fs/io/sql error path; boundary/partial for empty backup set and retention edge | Open | | `backend/internal/services/proxyhost_service.go` | Missing: `L-L`; Partial: `L-L` | `backend/internal/services/proxyhost_service_test.go` | happy create/update/delete/list; validation/duplicate/not-found error path; boundary/partial for optional TLS/security toggles | Open | | `backend/internal/api/handlers/crowdsec_handler.go` | Missing: `L-L`; Partial: `L-L` | `backend/internal/api/handlers/crowdsec_handler_test.go` | happy config/get/update actions; bind/service error path; boundary/partial on query params and empty payload behavior | Open | | `backend/internal/api/handlers/user_handler.go` | Missing: `L-L`; Partial: `L-L` | `backend/internal/api/handlers/user_handler_test.go` | happy list/create/update/delete; validation/permission/not-found errors; boundary/partial for pagination/filter defaults | Open | | `backend/internal/services/log_service.go` | Missing: `L-L`; Partial: `L-L` | `backend/internal/services/log_service_test.go` | happy read/stream/filter; source/read failure path; boundary/partial for empty logs and limit/offset branches | Open | | `backend/internal/api/handlers/import_handler.go` | Missing: `L-L`; Partial: `L-L` | `backend/internal/api/handlers/import_handler_test.go` | happy import start/status; bind/parse/service failure path; boundary/partial for unsupported type/empty payload | Open | | `backend/internal/cerberus/rate_limit.go` | Missing: `L-L`; Partial: `L-L` | `backend/internal/cerberus/rate_limit_test.go` | happy allow path; blocked/over-limit error path; boundary/partial for burst/window thresholds | Open | Patch triage completion rule: - Replace placeholders with exact Codecov ranges and keep one-to-one mapping between each range and at least one concrete test case. - Do not close this remediation until every listed placeholder range is replaced and verified as covered. ### 12.4 Backend Test Strategy by File (Happy + Error + Boundary/Partial) #### Wave 1 — Zero-Coverage First (fastest patch gain) 1. `backend/internal/services/mail_service.go` (0.00%, 22 missing) - Happy: successful send/build with valid config. - Error: transport/auth/template failures. - Boundary/partial: empty optional fields, nil config branches. 2. `backend/internal/crowdsec/hub_sync.go` (0.00%, 10 missing + 6 partial) - Happy: successful hub sync and update path. - Error: HTTP error, non-2xx response, malformed payload. - Boundary/partial: empty decision set, optional/legacy field branches. 3. `backend/internal/api/handlers/auth_handler.go` (0.00%, 15 missing) - Happy: valid auth request returns expected status/body. - Error: bind/validation/service auth failures. - Boundary/partial: missing header/cookie/token branches. 4. `backend/internal/services/backup_service.go` (0.00%, 5 missing + 3 partial) - Happy: backup create/list/restore success branch. - Error: filesystem/database operation failures. - Boundary/partial: empty backup inventory and retention-window edges. #### Wave 2 — Mid-Coverage Expansion 5. `backend/internal/services/proxyhost_service.go` (55.88%, 14 missing + 1 partial) 6. `backend/internal/api/handlers/crowdsec_handler.go` (30.00%, 9 missing + 5 partial) For both: - Happy path operation success. - Error path for validation/bind/service failures. - Boundary/partial branches for optional flags/default values. #### Wave 3 — High-Coverage Tail Cleanup 7. `backend/internal/api/handlers/user_handler.go` (72.09%, 6 missing + 6 partial) 8. `backend/internal/services/log_service.go` (73.91%, 6 missing + 6 partial) 9. `backend/internal/api/handlers/import_handler.go` (67.85%, 3 missing + 6 partial) 10. `backend/internal/cerberus/rate_limit.go` (93.33%, 3 missing + 3 partial) For all: - Close remaining missing branches first. - Then resolve partials with targeted boundary tests matching exact triaged ranges. ### 12.5 Concrete Run Sequence (Backend Coverage + Targeted Tests + Re-run) Use this execution order for each wave: 1. Baseline backend coverage (project-approved): - VS Code task: `Test: Backend with Coverage` (if present) - Script: `scripts/go-test-coverage.sh` 2. Targeted package-level test runs for quick feedback: - `cd /projects/Charon/backend && go test -cover ./internal/services -run 'Mail|Backup|ProxyHost|Log'` - `cd /projects/Charon/backend && go test -cover ./internal/crowdsec -run 'HubSync'` - `cd /projects/Charon/backend && go test -cover ./internal/api/handlers -run 'Auth|CrowdSec|User|Import'` - `cd /projects/Charon/backend && go test -cover ./internal/cerberus -run 'RateLimit'` 3. Full backend coverage re-run after each wave: - `scripts/go-test-coverage.sh` 4. Patch verification loop: - Re-open Codecov Patch view. - Replace remaining placeholders with exact unresolved ranges. - Add next targeted tests for those exact ranges. - Re-run Step 2 and Step 3 until all patch ranges are covered. 5. Final validation: - `cd /projects/Charon/backend && go test ./...` - `scripts/go-test-coverage.sh` - Confirm Codecov patch coverage for backend modified lines reaches 100%. ### 12.6 Acceptance Criteria (Backend Remediation Section) - Patch-triage table is fully populated with exact Codecov ranges (no placeholders left). - Zero-coverage files (`mail_service.go`, `hub_sync.go`, `auth_handler.go`, `backup_service.go`) are covered first. - Each file has tests for happy path, error path, and boundary/partial branches. - Concrete run sequence executed: baseline -> targeted go test -> coverage re-run -> patch verify loop. - Existing frontend unit-test coverage plan remains unchanged and intact. - No E2E requirement is introduced in this backend remediation section.