Skip to content
Merged
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
184 changes: 84 additions & 100 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,132 +56,116 @@ jobs:
use_sticky_comment: true
allowed_bots: "claude[bot],codeflash-ai[bot]"
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
EVENT: ${{ github.event.action }}
<context>
repo: ${{ github.repository }}
pr_number: ${{ github.event.pull_request.number }}
event: ${{ github.event.action }}
is_re_review: ${{ github.event.action == 'synchronize' }}
</context>

## STEP 1: Run prek and mypy checks, fix issues
<commitment>
Execute these steps in order. If a step has no work, state that and continue to the next step.
Post all review findings in a single summary comment only — never as inline PR review comments.
</commitment>

First, run these checks on files changed in this PR:
1. `uv run prek run --from-ref origin/main` - linting/formatting issues
2. `uv run mypy <changed_files>` - type checking issues
<step name="lint_and_typecheck">
Run checks on files changed in this PR and auto-fix what you can.

If there are prek issues:
- For SAFE auto-fixable issues (formatting, import sorting, trailing whitespace, etc.), run `uv run prek run --from-ref origin/main` again to auto-fix them
- For issues that prek cannot auto-fix, do NOT attempt to fix them manually — report them as remaining issues in your summary
1. Run `uv run prek run --from-ref origin/main` to check linting/formatting.
If there are auto-fixable issues, run it again to fix them.
Report any issues prek cannot auto-fix in your summary.

If there are mypy issues:
- Fix type annotation issues (missing return types, Optional/None unions, import errors for type hints, incorrect types)
- Do NOT add `type: ignore` comments - always fix the root cause
2. Run `uv run mypy <changed_files>` to check types.
Fix type annotation issues (missing return types, Optional unions, import errors).
Always fix the root cause instead of adding `type: ignore` comments.
Leave alone: type errors requiring logic changes, complex generics, anything changing runtime behavior.

After fixing issues:
- Stage the fixed files with `git add`
- Commit with message "style: auto-fix linting issues" or "fix: resolve mypy type errors" as appropriate
- Push the changes with `git push`
3. After fixes: stage with `git add`, commit ("style: auto-fix linting issues" or "fix: resolve mypy type errors"), push.

IMPORTANT - Verification after fixing:
- After committing fixes, run `uv run prek run --from-ref origin/main` ONE MORE TIME to verify all issues are resolved
- If errors remain, either fix them or report them honestly as unfixed in your summary
- NEVER claim issues are fixed without verifying. If you cannot fix an issue, say so
4. Verify by running `uv run prek run --from-ref origin/main` one more time. Report honestly if issues remain.
</step>

Do NOT attempt to fix:
- Type errors that require logic changes or refactoring
- Complex generic type issues
- Anything that could change runtime behavior
<step name="resolve_stale_threads">
Before reviewing, resolve any stale review threads from previous runs.

## STEP 2: Review the PR
1. Fetch unresolved threads you created:
`gh api graphql -f query='{ repository(owner: "${{ github.repository_owner }}", name: "${{ github.event.repository.name }}") { pullRequest(number: ${{ github.event.pull_request.number }}) { reviewThreads(first: 100) { nodes { id isResolved path comments(first: 1) { nodes { body author { login } } } } } } } }' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | select(.comments.nodes[0].author.login == "claude") | {id: .id, path: .path, body: .comments.nodes[0].body}'`

${{ github.event.action == 'synchronize' && 'This is a RE-REVIEW after new commits. First, get the list of changed files in this latest push using `gh pr diff`. Review ONLY the changed files. Check ALL existing review comments and resolve ones that are now fixed.' || 'This is the INITIAL REVIEW.' }}
2. For each unresolved thread:
a. Read the file at that path to check if the issue still exists
b. If fixed → resolve it: `gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "<THREAD_ID>"}) { thread { isResolved } } }'`
c. If still present → leave it

Review this PR focusing ONLY on:
1. Critical bugs or logic errors
Read the actual code before deciding. If there are no unresolved threads, skip to the next step.
</step>

<step name="review">
Review the diff (`gh pr diff ${{ github.event.pull_request.number }}`) for:
1. Bugs that will crash at runtime
2. Security vulnerabilities
3. Breaking API changes
4. Test failures (methods with typos that wont run)
5. Stale documentation — if files or directories were moved, renamed, or deleted, check that `.claude/rules/`, `CLAUDE.md`, and `AGENTS.md` don't reference paths that no longer exist
6. New language support — if new language modules are added under `languages/`, check that `.github/workflows/duplicate-code-detector.yml` includes the new language in its file filters, search patterns, and cross-module checks

IMPORTANT:
- First check existing review comments using `gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments`. For each existing comment, check if the issue still exists in the current code.
- If an issue is fixed, use `gh api --method PATCH repos/${{ github.repository }}/pulls/comments/COMMENT_ID -f body="✅ Fixed in latest commit"` to resolve it.
- Only create NEW inline comments for HIGH-PRIORITY issues found in changed files.
- Limit to 5-7 NEW comments maximum per review.
- Use CLAUDE.md for project-specific guidance.
- Use `mcp__github_inline_comment__create_inline_comment` sparingly for critical code issues only.

## STEP 3: Coverage analysis
Ignore style issues, type hints, and log message wording.
Record findings for the summary comment. Refer to CLAUDE.md for project conventions.
</step>

<step name="coverage">
Analyze test coverage for changed files:

1. Get the list of Python files changed in this PR (excluding tests):
`git diff --name-only origin/main...HEAD -- '*.py' | grep -v test`

2. Run tests with coverage on the PR branch:
`uv run coverage run -m pytest tests/ -q --tb=no`
`uv run coverage json -o coverage-pr.json`

3. Get coverage for changed files only:
`uv run coverage report --include="<changed_files_comma_separated>"`

4. Compare with main branch coverage:
- Checkout main: `git checkout origin/main`
- Run coverage: `uv run coverage run -m pytest tests/ -q --tb=no && uv run coverage json -o coverage-main.json`
- Checkout back: `git checkout -`
1. Get changed Python files (excluding tests): `git diff --name-only origin/main...HEAD -- '*.py' | grep -v test`
2. Run coverage on PR branch: `uv run coverage run -m pytest tests/ -q --tb=no` then `uv run coverage json -o coverage-pr.json`
3. Get per-file coverage: `uv run coverage report --include="<changed_files>"`
4. Compare with main: checkout main, run coverage, checkout back
5. Flag: new files below 75%, decreased coverage, untested changed lines
</step>

5. Analyze the diff to identify:
- NEW FILES: Files that don't exist on main (require good test coverage)
- MODIFIED FILES: Files with changes (changes must be covered by tests)
<step name="summary_comment">
Post exactly one summary comment containing all results from previous steps.

6. Report in PR comment with a markdown table:
- Coverage % for each changed file (PR vs main)
- Overall coverage change
- For NEW files: Flag if coverage is below 75%
- For MODIFIED files: Flag if the changed lines are not covered by tests
- Flag if overall coverage decreased

Coverage requirements:
- New implementations/files: Must have ≥75% test coverage
- Modified code: Changed lines should be exercised by existing or new tests
- No coverage regressions: Overall coverage should not decrease

## STEP 4: Post ONE consolidated summary comment

CRITICAL: You must post exactly ONE summary comment containing ALL results (pre-commit, review, coverage).
DO NOT post multiple separate comments. Use this format:
To ensure one comment: find an existing claude[bot] comment and update it, or create one if none exists.
Delete any duplicate claude[bot] comments.

```
## PR Review Summary
gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments --jq '.[] | select(.user.login == "claude[bot]") | .id' | head -1
```

Format:
## PR Review Summary
### Prek Checks
[status and any fixes made]

### Code Review
[critical issues found, if any]

### Test Coverage
[coverage table and analysis]

---
*Last updated: <timestamp>*
```

To ensure only ONE comment exists:
1. Find existing claude[bot] comment: `gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments --jq '.[] | select(.user.login == "claude[bot]") | .id' | head -1`
2. If found, UPDATE it: `gh api --method PATCH repos/${{ github.repository }}/issues/comments/<ID> -f body="<content>"`
3. If not found, CREATE: `gh pr comment ${{ github.event.pull_request.number }} --body "<content>"`
4. Delete any OTHER claude[bot] comments to clean up duplicates: `gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments --jq '.[] | select(.user.login == "claude[bot]") | .id' | tail -n +2 | xargs -I {} gh api --method DELETE repos/${{ github.repository }}/issues/comments/{}`

## STEP 5: Merge pending codeflash optimization PRs

Check for open optimization PRs from codeflash and merge if CI passes:

1. List open PRs from codeflash bot:
`gh pr list --author "codeflash-ai[bot]" --state open --json number,title,headRefName`

2. For each optimization PR:
- Check if CI is passing: `gh pr checks <number>`
- If all checks pass, merge it: `gh pr merge <number> --squash --delete-branch`
claude_args: '--model us.anthropic.claude-opus-4-6-v1 --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*),Bash(gh pr checks:*),Bash(gh pr merge:*),Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh api:*),Bash(uv run prek *),Bash(uv run mypy *),Bash(uv run coverage *),Bash(uv run pytest *),Bash(git status*),Bash(git add *),Bash(git commit *),Bash(git push*),Bash(git diff *),Bash(git checkout *),Read,Glob,Grep,Edit"'
</step>

<step name="simplify">
Run /simplify to review recently changed code for reuse, quality, and efficiency opportunities.
If improvements are found, commit with "refactor: simplify <description>" and push.
Only make behavior-preserving changes.
</step>

<step name="merge_optimization_prs">
Check for open PRs from codeflash-ai[bot]:
`gh pr list --author "codeflash-ai[bot]" --state open --json number,title,headRefName,createdAt,mergeable`

For each PR:
- If CI passes and the PR is mergeable → merge with `--squash --delete-branch`
- Close the PR as stale if ANY of these apply:
- Older than 7 days
- Has merge conflicts (mergeable state is "CONFLICTING")
- CI is failing
- The optimized function no longer exists in the target file (check the diff)
Close with: `gh pr close <number> --comment "Closing stale optimization PR." --delete-branch`
</step>

<verification>
Before finishing, confirm:
- All steps were attempted (even if some had no work)
- Stale review threads were checked and resolved where appropriate
- All findings are in a single summary comment (no inline review comments were created)
- If fixes were made, they were verified with prek
</verification>
claude_args: '--model us.anthropic.claude-opus-4-6-v1 --allowedTools "Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*),Bash(gh pr checks:*),Bash(gh pr merge:*),Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh api:*),Bash(uv run prek *),Bash(uv run mypy *),Bash(uv run coverage *),Bash(uv run pytest *),Bash(git status*),Bash(git add *),Bash(git commit *),Bash(git push*),Bash(git diff *),Bash(git checkout *),Read,Glob,Grep,Edit,Skill"'
additional_permissions: |
actions: read

Expand Down
Loading