fix(automerge): narrow infra/ regex; let cron-only changes auto-merge#70
Conversation
The broad `^infra/.*` pattern over-classified cron-only changes as manual-
merge. Concrete case: wxa_vpn#439 (rDNS-driven CDN upgrade, Tier B3) and
wxa_vpn#441 (per-operator CloudWatch telemetry, Tier B5) both added a single
weekly/daily cron entry to `infra/crontabs/wxa-scanner.crontab` and were
blocked on auto-merge by the bot's classifier. Per the wxa_vpn#250 lesson
(codified 2026-05-04) about over-classification, those PRs are auto-merge
territory: "the existing system runs slightly differently for one cycle,
git revert and we're back."
Replaces the single `^infra/.*` rule with explicit risky-subcategory rules:
* ^infra/iam/.* — IAM trust policies (security-critical)
* ^infra/(deploy|terraform|pulumi|k8s|cloudformation|ansible|
digitalocean|scanner-id)/.* — IaC + host config
* ^infra/nginx.* — nginx prod config (top-level + subdir form)
* ^infra/.*\.(service|slice|timer|tf|hcl|sh)$ — systemd units +
Terraform files + shell scripts anywhere under infra/
What's now correctly auto-merge eligible under infra/:
* infra/crontabs/*.crontab — cron schedule changes
* infra/*.md — runbook docs
* infra/crontab.example — example config
What stays manual-merge (genuinely risky):
* IAM policies, nginx configs, systemd units, Terraform .tf, deploy
shell scripts, host identity, IaC under infra/
Adds selftest/test_automerge_risk_patterns.sh with 33 RISKY cases that MUST
match and 11 SAFE cases that MUST NOT match. The test mirrors the regex
block from claude-author-automerge.yml — if you edit one, edit the other.
The script keeps the wxa_vpn#439/#441-style false positives (cron files,
runbook docs) explicitly listed in the SAFE bucket so a future broadening
of the pattern fails the test instead of silently regressing.
Refs the 2026-05-04 over-classification lesson + the 2026-05-20 wxa_vpn
incidents (#439, #441) that surfaced the bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Risk class: This PR touches one of the blocked path categories from Auto-merge is refused by (This is a policy notice, not a code-quality failure. The classify job itself does not fail — required CI checks remain authoritative for "is the code green.") |
|
Coverage Floor — mode:
|
|
No issues found. Regex narrowing is deliberate and correct; the 44-case self-test script validates all risky and safe buckets. One minor uncovered gap: |
Summary
Replaces the over-broad
^infra/.*pattern inclaude-author-automerge.ymlwith explicit risky-subcategory rules. Cron-only changes, runbook docs, and example configs underinfra/are now correctly auto-merge eligible; IAM policies, nginx configs, systemd units, Terraform, and deploy scripts stay manual-merge.Adds
selftest/test_automerge_risk_patterns.shto lock the matching behavior in version control so future regex edits can't silently regress.Why
The bot's
^infra/.*rule over-classified cron-only changes as manual-merge. Concrete cases triggering this PR:Both PRs touched only
infra/crontabs/wxa-scanner.crontabunder infra/, and both were blocked on auto-merge by the bot's path classifier. Per the wxa_vpn#250 lesson codified in CLAUDE.md (2026-05-04) about over-classification, those PRs are auto-merge territory: the existing system runs slightly differently for one cycle, git revert and we're back. The bot saying "manual-merge required" was wrong; the policy text in CLAUDE.md says `infra/iam/**`, not all of `infra/`.What changes
Risky (manual-merge): unchanged for IAM, deploy/terraform/pulumi/k8s/cloudformation/ansible/digitalocean/scanner-id subdirs, nginx, .service/.slice/.timer/.tf/.hcl/.sh anywhere under infra/.
Auto-merge eligible (the historical false positives):
Tests
`selftest/test_automerge_risk_patterns.sh` — 33 paths that MUST match (risky) + 11 paths that MUST NOT match (safe). Mirrors the regex block; edit both in lockstep.
The two `infra/crontabs/*.crontab` and `infra/aws-scanner-setup.md` cases that motivated this fix are explicitly in the SAFE bucket — a future broadening of the regex would fail the test instead of silently re-introducing the false positive.
Test plan
Auto-merge rationale
This PR itself touches `.github/workflows/claude-author-automerge.yml` — caught by the `^\.github/workflows/.*` rule (correctly), so it'll click-merge. Expected and policy-aligned.
🤖 Generated with Claude Code