From 9f1a64be6beca01a16936cc6b09b5f1e5ce66c37 Mon Sep 17 00:00:00 2001 From: ancplua Date: Mon, 4 May 2026 20:47:35 +0200 Subject: [PATCH 1/3] ci: agentic Claude review pipeline + CodeRabbit Pro config Three-file rollout to bring this repo to ecosystem-wide review parity with ancplua-claude-plugins and qyl. Files: - .coderabbit.yaml: Pro config, schema-validated. SDK-focused path_instructions for src/Sdk, src/Build, src/Config, *.props/*.targets/*.nuspec. Custom_checks enforce no DateTime.Now, no .Result/.Wait, no null-forgiving without justification, no suppression of fixable diagnostics. ~30 irrelevant linters explicitly disabled. - .github/workflows/claude-code-review.yml: agentic Claude review on PR open/sync via the official code-review@claude-code-plugins skill. Loop- prevention, concurrency cancellation, --max-turns 25, allowed_bots filter. - .github/workflows/coderabbit-autofix.yml: auto-comments @coderabbitai autofix on PR open/sync, eliminating the manual checkbox click. CLAUDE_CODE_OAUTH_TOKEN already configured on this repo (set 2026-02-14). Co-Authored-By: Claude Opus 4.7 (1M context) --- .coderabbit.yaml | 332 +++++++++++++++++++++++ .github/workflows/claude-code-review.yml | 62 +++++ .github/workflows/coderabbit-autofix.yml | 30 ++ 3 files changed, 424 insertions(+) create mode 100644 .coderabbit.yaml create mode 100644 .github/workflows/claude-code-review.yml create mode 100644 .github/workflows/coderabbit-autofix.yml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..1c10c2a --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,332 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +# +# ANcpLua.NET.Sdk — MSBuild SDK + analyzer injection + Version.props +# Stack: C#/.NET, MSBuild props/targets, .nuspec packaging +# Release: Pattern A — auto-bump on push to main (compute_version → patch+1) +# +# Schema-validated against: https://coderabbit.ai/integrations/schema.v2.json +# + +language: en-US +tone_instructions: >- + Principal-engineer review. Direct, concise. Flag structural violations as blocking. + Focus: AOT safety, MSBuild correctness, analyzer-injection contract, + no suppression policy. +early_access: true +enable_free_tier: false + +reviews: + profile: assertive + request_changes_workflow: true + high_level_summary: true + high_level_summary_in_walkthrough: false + review_status: true + review_details: true + commit_status: true + fail_commit_status: true + collapse_walkthrough: true + changed_files_summary: false + sequence_diagrams: false + estimate_code_review_effort: false + assess_linked_issues: true + related_issues: false + related_prs: false + suggested_labels: false + suggested_reviewers: false + auto_assign_reviewers: false + in_progress_fortune: false + poem: false + enable_prompt_for_ai_agents: true + + labeling_instructions: + - label: 'area:sdk' + instructions: 'Apply when the PR modifies src/Sdk/ or the SDK csproj/nuspec.' + - label: 'area:build' + instructions: 'Apply when the PR modifies src/Build/ or MSBuild props/targets.' + - label: 'area:config' + instructions: 'Apply when the PR modifies src/Config/.' + - label: 'area:test-sdk' + instructions: 'Apply when the PR modifies the .Test.csproj or test SDK.' + - label: 'area:web-sdk' + instructions: 'Apply when the PR modifies the .Web.csproj or Web SDK.' + - label: 'area:tools' + instructions: 'Apply when the PR modifies tools/.' + - label: 'area:tests' + instructions: 'Apply when the PR modifies tests/.' + - label: 'area:infra' + instructions: 'Apply when the PR modifies .github/, eng/, or root build infrastructure.' + - label: 'breaking' + instructions: >- + Apply when the PR introduces breaking changes to SDK contract: + analyzer injection list, default props/targets, package version policy. + auto_apply_labels: true + + path_filters: + - 'src/**' + - 'tests/**' + - 'tools/**' + - 'eng/**' + - '.github/**' + - '*.props' + - '*.targets' + - '*.slnx' + - '*.nuspec' + - 'global.json' + - 'NuGet.config' + - 'Directory.*.props' + - 'Directory.*.targets' + - '!**/*.g.cs' + - '!**/*.Designer.cs' + - '!**/bin/**' + - '!**/obj/**' + - '!**/artifacts/**' + + path_instructions: + - path: 'src/**/*.cs' + instructions: | + C# 14 with preview features. File-scoped namespaces; primary constructors; + required init properties; switch expressions over if-else. + + ARCHITECTURAL INVARIANTS — flag violations as blocking: + - No `DateTime.Now`/`DateTime.UtcNow` — use `TimeProvider.System`. + - No `.Result`/`.Wait()`/`.GetAwaiter().GetResult()` — `await` always. + - No `ISourceGenerator` — use `IIncrementalGenerator`. + - No null-forgiving `!` — rewrite the code. + - No `dynamic`/`ExpandoObject` — use typed contracts. + - Storing `ISymbol` in incremental models — extract value-equatable data. + - `params T[]` where `params ReadOnlySpan` works (C# 13+). + - Suppressions only for documented exceptions (preview API markers, + AOT-verified safe code, `netstandard2.0` analyzer projects). + + - path: 'src/Sdk/**' + instructions: | + The SDK guts — props/targets imported by every consumer project. + Review for: stable property names (renames break consumers), correct + ordering of imports (consumer overrides win), and that new defaults + opt-out cleanly. Flag any property without a `` + guard that lets consumers override. + + Analyzer injection: this SDK injects ANcpLua.Analyzers via PackageReference + with PrivateAssets="all". Flag any change that breaks injection (wrong + IncludeAssets, missing analyzer asset). + + - path: 'src/Build/**' + instructions: | + Build targets shared across .NET.Sdk, .Test, .Web variants. Review for: + target-name collisions with consumer csproj (use unique prefixes), correct + BeforeTargets/AfterTargets ordering, and idempotent execution (target + should be safe to run twice). + + - path: '**/*.props' + instructions: | + MSBuild property files. Review for: condition guards on every override + (consumer must be able to opt out), no `` on items + that consumers may have set, and that defaults are sensible without + forcing a downstream cascade. + + - path: '**/*.targets' + instructions: | + MSBuild target files. Review for: correct target dependency declaration + (DependsOnTargets / BeforeTargets / AfterTargets), input/output + declarations for incremental builds, and no shell-out to platform- + specific commands without an OS guard. + + - path: '**/*.nuspec' + instructions: | + NuGet package manifest. Review for: correct package id, correct + dependency version ranges (no float-to-latest in stable releases), + proper file globs (no .pdb in release packages unless symbol package), + and that contentFiles paths match what's in src/. + + - path: 'tests/**/*.cs' + instructions: | + xUnit + FluentAssertions. AAA pattern. NSubstitute for mocks. + Flag: blocking-async patterns (`Task.Run(() => x.Result)`), missing + `async Task` (sync-void), `Thread.Sleep` instead of `await Task.Delay`, + tests asserting on private state via reflection. + + - path: 'tools/**' + instructions: | + Internal tooling — config file generators, build helpers. Lower bar than + production src/, but still flag obvious bugs (missing null check that + crashes the build, hardcoded paths, swallowed exceptions). + + - path: '.github/workflows/**' + instructions: | + Pin third-party actions to SHA. First-party (actions/*) tag-pin OK. + Concurrency groups required on push-triggered workflows. + Secrets via env: not inline. No secrets in logs. + Minimal permissions per job. + Pattern A release: changes to compute_version logic affect every push to + main — flag carefully. + + - path: 'AGENTS.md' + instructions: | + Coordination file for AI agents. Review for: consistency with actual repo + structure, accurate references to CLAUDE.md, and that release-flow + documentation matches nuget-publish.yml behavior. + + auto_review: + enabled: true + auto_incremental_review: true + auto_pause_after_reviewed_commits: 0 + drafts: false + ignore_title_keywords: + - 'deps(' + - '[skip ci]' + - '[skip review]' + - 'wip' + labels: [] + base_branches: [] + ignore_usernames: + - 'dependabot[bot]' + - 'renovate[bot]' + + finishing_touches: + docstrings: + enabled: false + unit_tests: + enabled: false + + pre_merge_checks: + docstrings: + mode: 'off' + title: + mode: error + requirements: | + Conventional commits: feat|fix|refactor|chore|docs|test|ci|perf|deps. + Under 72 chars, no trailing period. + Examples: feat(sdk): add WarningsAsErrors default, + fix(build): correct analyzer injection IncludeAssets + description: + mode: warning + issue_assessment: + mode: warning + custom_checks: + - mode: error + name: 'No DateTime.Now/UtcNow' + instructions: | + Scan added/modified C# files for `DateTime.Now` or `DateTime.UtcNow`. + Pass if none. Fail if any usage — use `TimeProvider.System` instead. + Exception: test fixtures with explicit reason commented inline. + - mode: error + name: 'No .Result/.Wait() blocking async' + instructions: | + Scan added/modified C# files for `.Result`, `.Wait()`, or + `.GetAwaiter().GetResult()`. Pass if none. Fail if any blocking-async + pattern — `await` always. + - mode: warning + name: 'No null-forgiving operator without justification' + instructions: | + Scan added/modified C# files for `!` (null-forgiving). Pass if none. + Fail if any `!` is added without an inline comment explaining why + the code can't be rewritten to avoid it. Per repo policy: rewrite, + don't suppress. + - mode: warning + name: 'No suppression of fixable diagnostics' + instructions: | + Scan added/modified C# files for `#pragma warning disable` or + `[SuppressMessage]` attributes. Pass if none added. Fail if any + added without inline comment matching the acceptable-suppressions + allowlist in CLAUDE.md (preview API markers MEAI001/OPENAI002, + source-gen contexts, DevUI, upstream framework requirements, + AOT/trimming verified safe, netstandard2.0 analyzer projects). + + tools: + shellcheck: + enabled: true + actionlint: + enabled: true + markdownlint: + enabled: true + gitleaks: + enabled: true + github-checks: + enabled: true + timeout_ms: 180000 + ast-grep: + essential_rules: true + eslint: { enabled: false } + biome: { enabled: false } + oxc: { enabled: false } + ruff: { enabled: false } + pylint: { enabled: false } + flake8: { enabled: false } + phpstan: { enabled: false } + phpmd: { enabled: false } + phpcs: { enabled: false } + swiftlint: { enabled: false } + detekt: { enabled: false } + pmd: { enabled: false } + semgrep: { enabled: false } + opengrep: { enabled: false } + trufflehog: { enabled: false } + checkov: { enabled: false } + tflint: { enabled: false } + fortitudeLint: { enabled: false } + rubocop: { enabled: false } + buf: { enabled: false } + regal: { enabled: false } + clang: { enabled: false } + cppcheck: { enabled: false } + circleci: { enabled: false } + clippy: { enabled: false } + sqlfluff: { enabled: false } + trivy: { enabled: false } + prismaLint: { enabled: false } + shopifyThemeCheck: { enabled: false } + luacheck: { enabled: false } + brakeman: { enabled: false } + dotenvLint: { enabled: false } + htmlhint: { enabled: false } + stylelint: { enabled: false } + checkmake: { enabled: false } + osvScanner: { enabled: false } + blinter: { enabled: false } + yamllint: { enabled: false } + psscriptanalyzer: { enabled: false } + languagetool: { enabled: false } + hadolint: { enabled: false } + golangci-lint: { enabled: false } + +chat: + auto_reply: true + art: false + integrations: + jira: + usage: disabled + linear: + usage: disabled + +knowledge_base: + opt_out: false + web_search: + enabled: true + code_guidelines: + enabled: true + filePatterns: + - '**/CLAUDE.md' + - '**/AGENTS.md' + - 'Directory.Build.props' + - 'Directory.Packages.props' + learnings: + scope: auto + issues: + scope: auto + pull_requests: + scope: auto + jira: + usage: disabled + linear: + usage: disabled + mcp: + usage: auto + +issue_enrichment: + auto_enrich: + enabled: true + planning: + auto_planning: + enabled: false + labeling: + auto_apply_labels: true diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 0000000..8811965 --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,62 @@ +name: Claude Code Review + +on: + pull_request: + types: [opened, synchronize, ready_for_review, reopened] + paths-ignore: + - 'CHANGELOG.md' + - '**/*.lock' + +permissions: + contents: write + pull-requests: write + issues: write + id-token: write + actions: read + +jobs: + claude-review: + if: | + github.actor != 'coderabbitai[bot]' && + !contains(github.event.pull_request.title, '[skip review]') && + !contains(github.event.pull_request.labels.*.name, 'skip-review') + concurrency: + group: claude-review-${{ github.event.pull_request.number }} + cancel-in-progress: true + runs-on: ubuntu-latest + steps: + - name: Checkout PR head + uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 20 + + - name: Run Claude Code Review (agentic) + id: claude-review + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + allowed_bots: 'dependabot[bot],renovate[bot]' + track_progress: true + plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' + plugins: 'code-review@claude-code-plugins' + claude_args: '--model claude-opus-4-7 --max-turns 25' + prompt: | + /code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }} + + Operating mode: **agentic**. You have write access to this PR branch. + + Decision tree: + 1. **Mechanically fixable** (formatting, naming, missing CancellationToken, + IDisposable not disposed, .Result/.Wait blocking-async, DateTime.Now, + null-forgiving `!`, suppression that can be rewritten, ISourceGenerator + that should be IIncrementalGenerator, MSBuild property without condition + guard) → fix in a commit pushed to this branch. Don't ask permission. + 2. **Structural concern needing human judgment** (architectural trade-off, + novel pattern, transitive-dependency conflict, breaking SDK contract, + analyzer-injection mechanism change, ghost-tag scenario) → flag in a + comment and stop. + 3. **Clean** → post a single approval-style comment and stop. + + Read AGENTS.md / CLAUDE.md / .coderabbit.yaml for repo invariants. + The .coderabbit.yaml ARCHITECTURAL INVARIANTS sections are authoritative. diff --git a/.github/workflows/coderabbit-autofix.yml b/.github/workflows/coderabbit-autofix.yml new file mode 100644 index 0000000..ba6a841 --- /dev/null +++ b/.github/workflows/coderabbit-autofix.yml @@ -0,0 +1,30 @@ +name: CodeRabbit Autofix Trigger + +on: + pull_request: + types: [opened, synchronize] + +jobs: + trigger: + if: | + github.actor != 'coderabbitai[bot]' && + github.actor != 'dependabot[bot]' && + github.actor != 'renovate[bot]' && + !contains(github.event.pull_request.labels.*.name, 'skip-autofix') + concurrency: + group: coderabbit-autofix-${{ github.event.pull_request.number }} + cancel-in-progress: true + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Comment "@coderabbitai autofix" + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: '@coderabbitai autofix' + }); From c15ccef6f5c12f6d6914994bdd0b2c332a572a7a Mon Sep 17 00:00:00 2001 From: ancplua Date: Mon, 4 May 2026 20:57:39 +0200 Subject: [PATCH 2/3] fix(ci): SHA-pin claude-code-action + env-mapped secret (CodeRabbit autofix) Addresses CodeRabbit findings on this PR (also applied across all 6 PRs in the ecosystem rollout, which collectively introduced the same pattern violations): 1. Pin anthropics/claude-code-action@v1 to commit SHA fefa07e9c665b7320f08c3b525980457f22f58aa per the '.coderabbit.yaml' path_instructions for .github/workflows/** ('Pin third- party actions to SHA. First-party (actions/*) tag-pin OK'). Renovate will bump the SHA on new releases. 2. Move CLAUDE_CODE_OAUTH_TOKEN to job-level env: mapping rather than inline with:, per the same path_instructions ('Secrets via env: not inline'). Self-correction via the agentic loop: the policy in .coderabbit.yaml flagged my own workflow files written under that policy. Working as designed. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/claude-code-review.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 8811965..dca97ca 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -24,6 +24,8 @@ jobs: group: claude-review-${{ github.event.pull_request.number }} cancel-in-progress: true runs-on: ubuntu-latest + env: + CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} steps: - name: Checkout PR head uses: actions/checkout@v6 @@ -33,9 +35,9 @@ jobs: - name: Run Claude Code Review (agentic) id: claude-review - uses: anthropics/claude-code-action@v1 + uses: anthropics/claude-code-action@fefa07e9c665b7320f08c3b525980457f22f58aa # v1 with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + claude_code_oauth_token: ${{ env.CLAUDE_CODE_OAUTH_TOKEN }} allowed_bots: 'dependabot[bot],renovate[bot]' track_progress: true plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' From edd211973025fd3d96d8cd8de48053a89340637f Mon Sep 17 00:00:00 2001 From: ancplua Date: Mon, 4 May 2026 21:46:23 +0200 Subject: [PATCH 3/3] fix(ci): exclude github-actions[bot] from claude review trigger Closes the self-retrigger loop CodeRabbit identified: when claude-code-action pushes a mechanical fix to the PR branch, the commit is authored by github-actions[bot]. Without this guard, the synchronize event re-fires the workflow on the bot's own push, potentially looping until --max-turns kicks in. Now skips runs where the triggering actor is github-actions[bot] in addition to coderabbitai[bot]. Real human pushes still trigger review normally. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/claude-code-review.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index dca97ca..5cdf433 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -18,6 +18,7 @@ jobs: claude-review: if: | github.actor != 'coderabbitai[bot]' && + github.actor != 'github-actions[bot]' && !contains(github.event.pull_request.title, '[skip review]') && !contains(github.event.pull_request.labels.*.name, 'skip-review') concurrency: