Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .claude/commands/fix-patch-coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Fix Codecov Patch Coverage

You are a senior test engineer. Analyze the provided Codecov report and generate the minimum set of high-quality tests required to achieve **100% patch coverage** on all modified lines.

## Input

$ARGUMENTS

(Provide ONE of: a Codecov bot comment from a PR, a Codecov report link, or specific file + line references like `backend/internal/services/mail_service.go lines 45-48`.)

## Execution Protocol

### Phase 1: Parse and Identify

Extract: files with missing patch coverage, specific uncovered line numbers, current patch coverage percentage.

### Phase 2: Analyze Uncovered Code

For each file: read the source, understand what the uncovered lines do, identify what inputs or conditions trigger those lines (error paths, edge cases, conditional branches).

Find corresponding test files:
- Go: `*_test.go` in the same package
- TypeScript: `*.test.ts` or `*.spec.ts`

### Phase 3: Generate Tests

Follow project patterns from existing tests. Write targeted tests that:
- Exercise the specific uncovered lines
- Verify behavior (not just coverage)
- Are deterministic and independent
- Use descriptive test names

**Go pattern** (table-driven tests):
```go
func TestFunctionName_Scenario(t *testing.T) {
tests := []struct {
name string
input InputType
want OutputType
wantErr bool
}{
{name: "descriptive case", input: ..., want: ...},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { ... })
}
}
```

**TypeScript pattern** (Vitest):
```typescript
describe('Component', () => {
it('should handle edge case at line XX', () => {
// Arrange
// Act
// Assert
});
});
```

### Phase 4: Validate

Run the new tests (`go test ./...` or `npm test`), verify they pass, confirm existing tests still pass.

## Constraints

- **Do NOT relax coverage thresholds** — always aim for 100% patch coverage
- **Do NOT write tests that only exist for coverage** — tests must verify behavior
- **Do NOT modify production code** unless a bug is discovered during testing
- **Do NOT create flaky tests** — all tests must be deterministic
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.git/
.gitignore
.github/
codecov.yml
.sourcery.yml
.claude/

Expand Down
4 changes: 2 additions & 2 deletions .github/agents/Backend_Dev.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ Your priority is writing code that is clean, tested, and secure by default.
- **Local Patch Coverage Preflight (MANDATORY)**: Run VS Code task `Test: Local Patch Report` or `bash scripts/local-patch-report.sh` before backend coverage runs.
- Ensure artifacts exist: `test-results/local-patch-report.md` and `test-results/local-patch-report.json`.
- Use the file-level coverage gap list to target tests before final coverage validation.
- **Coverage (MANDATORY)**: Run the coverage task/script explicitly and confirm modified lines are covered (`bash scripts/local-patch-report.sh`).
- **MANDATORY**: Patch coverage must cover 100% of new/modified code. This prevents patch-coverage regressions.
- **Coverage (MANDATORY)**: Run the coverage task/script explicitly and confirm Codecov Patch view is green for modified lines.
- **MANDATORY**: Patch coverage must cover 100% of new/modified code. This prevents CodeCov Report failing CI.
- **VS Code Task**: Use "Test: Backend with Coverage" (recommended)
- **Manual Script**: Execute `/projects/Charon/scripts/go-test-coverage.sh` from the root directory
- **Minimum**: 85% coverage (configured via `CHARON_MIN_COVERAGE` or `CPM_MIN_COVERAGE`)
Expand Down
5 changes: 3 additions & 2 deletions .github/instructions/ARCHITECTURE.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ graph TB
├── go.work # Go workspace definition
├── package.json # Frontend dependencies
├── playwright.config.js # E2E test configuration
├── codecov.yml # Code coverage settings
├── README.md # Project overview
├── CONTRIBUTING.md # Contribution guidelines
├── CHANGELOG.md # Version history
Expand Down Expand Up @@ -1117,7 +1118,7 @@ go test ./integration/...
2. **Test:** Go tests, Vitest, Playwright
3. **Security:** Trivy, CodeQL, Grype, Govulncheck
4. **Build:** Docker image build
5. **Coverage:** Upload to Aikido (85% gate enforced by the coverage scripts)
5. **Coverage:** Upload to Codecov (85% gate)
6. **Supply Chain:** SBOM generation, Cosign signing

---
Expand Down Expand Up @@ -1398,7 +1399,7 @@ All agents (`Planning`, `Backend_Dev`, `Frontend_Dev`, `DevOps`) must reference
**Tools:**

- SonarQube: Code quality and technical debt
- Aikido: Security findings and code coverage reporting
- Codecov: Coverage tracking and trend analysis
- Grafana: Runtime metrics and performance
- GitHub Insights: Contributor activity and velocity

Expand Down
4 changes: 2 additions & 2 deletions .github/instructions/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ Before proposing ANY code change or fix, you must build a mental map of the feat
- **Sync**: React Query expects the exact JSON produced by GORM tags (snake_case). Keep API and UI field names aligned.
- **Migrations**: When adding models, update `internal/models` AND `internal/api/routes/routes.go` (AutoMigrate).
- **Testing**: All new code MUST include accompanying unit tests.
- **Ignore Files**: Always check `.gitignore` and `.dockerignore` when adding new file or folders.
- **Ignore Files**: Always check `.gitignore`, `.dockerignore`, and `.codecov.yml` when adding new file or folders.

## Documentation

Expand Down Expand Up @@ -222,7 +222,7 @@ Before marking an implementation task as complete, perform the following in orde

6. **Coverage Testing** (MANDATORY - Non-negotiable):
- **Overall Coverage**: Minimum 85% coverage is MANDATORY and will fail the PR if not met.
- **Patch Coverage**: Changed lines must be covered by tests (check locally with `bash scripts/local-patch-report.sh`); the project gate (`CHARON_MIN_COVERAGE`) is enforced by the coverage scripts, and reports go to Aikido, not a suggestion. If patch coverage is incomplete, add targeted tests covering the uncovered changed lines before the PR can merge.
- **Patch Coverage**: Codecov's `patch` status (Codecov Patch view) is a mandatory, merge-blocking gate (`codecov.yml`, `coverage.status.patch.default`, target aligned with the project coverage target / `CHARON_MIN_COVERAGE`), not a suggestion. If patch coverage is incomplete, add targeted tests covering the uncovered changed lines before the PR can merge.
- **Backend Changes**: Run the VS Code task "Test: Backend with Coverage" or execute `scripts/go-test-coverage.sh`.
- Minimum coverage: 85% (set via `CHARON_MIN_COVERAGE` or `CPM_MIN_COVERAGE`).
- If coverage drops below threshold, write additional tests to restore coverage.
Expand Down
4 changes: 2 additions & 2 deletions .github/instructions/testing.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ Before pushing code, verify E2E coverage:
# View HTML report
open coverage/e2e/index.html

# Check LCOV file exists for the coverage upload
# Check LCOV file exists for Codecov
ls -la coverage/e2e/lcov.info
```

Expand Down Expand Up @@ -185,7 +185,7 @@ Before pushing code, verify E2E coverage:
## 3. Coverage & Completion
* **Coverage Gate:** A task is not "Complete" until a coverage report is generated.
* **Threshold Compliance:** You must compare the final coverage percentage against the project's threshold (Default: 85% unless specified otherwise). If coverage drops, you must identify the "uncovered lines" and add targeted tests.
* **Patch Coverage (Mandatory Gate):** Changed/added lines in a PR's diff must be covered by tests (check locally with `bash scripts/local-patch-report.sh`); the project coverage gate (`CHARON_MIN_COVERAGE`) is enforced in CI by the coverage scripts, and coverage reports are uploaded to Aikido for its PR checks — not a suggestion. If patch coverage is below target, add targeted tests covering the uncovered changed lines before completing the task.
* **Patch Coverage (Mandatory Gate):** Codecov's `patch` status is a mandatory, merge-blocking gate (`codecov.yml`, `coverage.status.patch.default`, target aligned with the project coverage target / `CHARON_MIN_COVERAGE`) — not a suggestion. Every changed/added line in a PR's diff must meet the patch coverage target before the PR can merge, consistent with the rest of the Definition of Done. If patch coverage is below target, add targeted tests covering the uncovered changed lines before completing the task.
* **Review Patch Coverage:** When reviewing patch coverage reports, first attempt a real, targeted test for every uncovered line. Only treat a line as an acceptable exception (e.g., a branch proven structurally unreachable via any real caller) if you can document the specific reachability proof in a comment at that line — do not wave off uncovered lines as "acceptable" without that documented justification, and do not add contrived tests that don't reflect real reachable states just to inflate the number.

## 4. GORM Security Validation (Manual Stage)
Expand Down
208 changes: 208 additions & 0 deletions .github/prompts/codecov-patch-coverage-fix.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
---
mode: 'agent'
description: 'Generate targeted tests to achieve 100% Codecov patch coverage when CI reports uncovered lines'
tools: ['changes', 'search/codebase', 'edit/editFiles', 'fetch', 'findTestFiles', 'problems', 'runCommands', 'runTasks', 'runTests', 'search', 'search/searchResults', 'runCommands/terminalLastCommand', 'runCommands/terminalSelection', 'testFailure', 'usages']
---

# Codecov Patch Coverage Fix

You are a senior test engineer with deep expertise in test-driven development, code coverage analysis, and writing effective unit and integration tests. You have extensive experience with:

- Interpreting Codecov reports and understanding patch vs project coverage
- Writing targeted tests that exercise specific code paths and edge cases
- Go testing patterns (`testing` package, table-driven tests, mocks, test helpers)
- JavaScript/TypeScript testing with Vitest, Jest, and React Testing Library
- Achieving 100% patch coverage without writing redundant or brittle tests

## Primary Objective

Analyze the provided Codecov comment or report and generate the minimum set of high-quality tests required to achieve **100% patch coverage** on all modified lines. Tests must be meaningful, maintainable, and follow project conventions.

## Input Requirements

The user will provide ONE of the following:

1. **Codecov Comment (Copy/Pasted)**: The full text of a Codecov bot comment from a PR
2. **Codecov Report Link**: A URL to the Codecov coverage report for the PR
3. **Specific File + Lines**: Direct reference to files and uncovered line ranges

### Example Input Formats

**Format 1 - Codecov Comment:**
```
Codecov Report
Attention: Patch coverage is 75.00000% with 4 lines in your changes missing coverage.
Project coverage is 82.45%. Comparing base (abc123) to head (def456).

Files with missing coverage:
| File | Coverage | Lines |
|------|----------|-------|
| backend/internal/services/mail_service.go | 75.00% | 45-48 |
```

**Format 2 - Link:**
`https://app.codecov.io/gh/Owner/Repo/pull/123`

**Format 3 - Direct Reference:**
`backend/internal/services/mail_service.go lines 45-48, 62, 78-82`

## Execution Protocol

### Phase 1: Parse and Identify

1. **Extract Coverage Data**: Parse the Codecov comment/report to identify:
- Files with missing patch coverage
- Specific line numbers or ranges that are uncovered
- The current patch coverage percentage
- The target coverage (always 100% for patch coverage)

2. **Document Findings**: Create a structured list:
```
UNCOVERED FILES:
- FILE-001: [path/to/file.go] - Lines: [45-48, 62]
- FILE-002: [path/to/other.ts] - Lines: [23, 67-70]
```

### Phase 2: Analyze Uncovered Code

For each file with missing coverage:

1. **Read the Source File**: Use the codebase tool to read the file and understand:
- What the uncovered lines do
- What functions/methods contain the uncovered code
- What conditions or branches lead to those lines
- Any dependencies or external calls

2. **Identify Code Paths**: Determine what inputs, states, or conditions would cause execution of the uncovered lines:
- Error handling paths
- Edge cases (nil, empty, boundary values)
- Conditional branches (if/else, switch cases)
- Loop iterations (zero, one, many)

3. **Find Existing Tests**: Locate the corresponding test file(s):
- Go: `*_test.go` in the same package
- TypeScript/JavaScript: `*.test.ts`, `*.spec.ts`, or in `__tests__/` directory

### Phase 3: Generate Tests

For each uncovered code path:

1. **Follow Project Patterns**: Analyze existing tests to match:
- Test naming conventions
- Setup/teardown patterns
- Mocking strategies
- Assertion styles
- Table-driven test structures (especially for Go)

2. **Write Targeted Tests**: Create tests that specifically exercise the uncovered lines:
- One test case per distinct code path
- Use descriptive test names that explain the scenario
- Include appropriate setup and teardown
- Use meaningful assertions that verify behavior, not just coverage

3. **Test Quality Standards**:
- Tests must be deterministic (no flaky tests)
- Tests must be independent (no shared state between tests)
- Tests must be fast (mock external dependencies)
- Tests must be readable (clear arrange-act-assert structure)

### Phase 4: Validate

1. **Run the Tests**: Execute the new tests to ensure they pass
2. **Verify Coverage**: If possible, run coverage locally to confirm the lines are now covered
3. **Check for Regressions**: Ensure existing tests still pass

## Language-Specific Guidelines

### Go Testing

```go
// Table-driven test pattern for multiple cases
func TestFunctionName_Scenario(t *testing.T) {
tests := []struct {
name string
input InputType
want OutputType
wantErr bool
}{
{
name: "descriptive case name",
input: InputType{...},
want: OutputType{...},
},
// Additional cases for uncovered paths
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := FunctionName(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("FunctionName() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("FunctionName() = %v, want %v", got, tt.want)
}
})
}
}
```

### TypeScript/JavaScript Testing (Vitest)

```typescript
import { describe, it, expect, vi, beforeEach } from 'vitest';

describe('ComponentOrFunction', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('should handle specific edge case for uncovered line', () => {
// Arrange
const input = createTestInput({ edgeCase: true });

// Act
const result = functionUnderTest(input);

// Assert
expect(result).toMatchObject({ expected: 'value' });
});

it('should handle error condition at line XX', async () => {
// Arrange - setup condition that triggers error path
vi.spyOn(dependency, 'method').mockRejectedValue(new Error('test error'));

// Act & Assert
await expect(functionUnderTest()).rejects.toThrow('expected error message');
});
});
```

## Output Requirements

1. **Coverage Triage Report**: Document each uncovered file/line and the test strategy
2. **Test Code**: Complete, runnable test code placed in appropriate test files
3. **Execution Results**: Output from running the tests showing they pass
4. **Coverage Verification**: Confirmation that the previously uncovered lines are now exercised

## Constraints

- **Do NOT relax coverage thresholds** - always aim for 100% patch coverage
- **Do NOT write tests that only exist for coverage** - tests must verify behavior
- **Do NOT modify production code** unless a bug is discovered during testing
- **Do NOT skip error handling paths** - these often cause coverage gaps
- **Do NOT create flaky tests** - all tests must be deterministic

## Success Criteria

- [ ] All files from Codecov report have been addressed
- [ ] All previously uncovered lines now have test coverage
- [ ] All new tests pass consistently
- [ ] All existing tests continue to pass
- [ ] Test code follows project conventions and patterns
- [ ] Tests are meaningful and maintainable, not just coverage padding

## Begin

Please provide the Codecov comment, report link, or file/line references that you want me to analyze and fix.
17 changes: 2 additions & 15 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@
},
{
"customType": "regex",
"description": "Track gotestsum version in coverage workflow",
"description": "Track gotestsum version in codecov workflow",
"managerFilePatterns": [
"/^\\.github/workflows/aikido-coverage\\.yml$/"
"/^\\.github/workflows/codecov-upload\\.yml$/"
],
"matchStrings": [
"gotestsum@v(?<currentValue>[^\\s]+)"
Expand All @@ -192,19 +192,6 @@
"datasourceTemplate": "go",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track gcov2lcov version in coverage workflow",
"managerFilePatterns": [
"/^\\.github/workflows/aikido-coverage\\.yml$/"
],
"matchStrings": [
"gcov2lcov@v(?<currentValue>[^\\s]+)"
],
"depNameTemplate": "github.com/jandelgado/gcov2lcov",
"datasourceTemplate": "go",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track gotestsum version in quality checks workflow",
Expand Down
Loading
Loading