fix(reusables): survive large PRs (gh pr diff 406) and symlinked prettier targets#106
Conversation
Two mechanical failure modes observed on topcoder1/dotclaude#121 (23,448 insertions / 161 files): 1. `gh pr diff --name-only` HTTP-406s past 20k diff lines, killing every workflow that used it as its changed-file source. Switch claude-author-automerge, safe-paths-automerge, pr-classify, and codex-review to the paginated files API (the idiom lint.yml / prettier-autofix.yml already used). The gating workflows fail closed at the API's 3000-file listing cap instead of silently under-classifying; codex-review takes its line count from the PR's additions+deletions instead of fetching the diff body. 2. prettier hard-errors on explicitly specified symlinks (dotclaude tracks symlinked SKILL.md files by convention). lint.yml and prettier-autofix.yml now drop symlinks from the explicit target list; the guarded empty-array assignment keeps the block bash-3.2 safe so the selftest can execute it on macOS. Selftests: test_pr_files_listing.sh bans executable `gh pr diff` in the reusables and pins the files-API idiom; test_prettier_symlink_filter.sh extracts the shipped filter block, runs it against a fixture tree, and guards lint/prettier-autofix drift; test_workflow_guards.py wires the host-independent .sh selftests into the pytest self-test path so CI enforces them. Failing runs: dotclaude runs 28676286316 (automerge) and 28676286301 (prettier-autofix). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex round-1 finding: a truncated file list could hide an always_review path from codex-gate.mjs and silently skip a required review. Same guard as the other gating workflows. Co-Authored-By: Claude Fable 5 <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. Files-API migration and symlink filter are correctly guarded (3000-cap fail-closed, bash 3.2 empty-array handling), env/repo refs are right, and the new selftests execute the shipped YAML. |
What broke
Two mechanical failure modes surfaced on dotclaude#121 (23,448 insertions / 161 files):
gh pr diff --name-onlyHTTP-406s past 20k diff lines ("Sorry, the diff exceeded the maximum number of lines (20000)"), killing every reusable that used it as its changed-file source. Failing run: 28676286316.What changed
Failure mode 1 — all four consumers of
gh pr diff --name-onlynow list changed files via the paginated files API (gh api repos/{o}/{r}/pulls/{n}/files --paginate), the idiom lint.yml/prettier-autofix.yml already used:claude-author-automerge.yml— risk-tier path scan (the reported failure); also updates the Option-A bypass-label comment, which documented the 406 as unfixablesafe-paths-automerge.yml— safe-path classify (same one-liner, was set to 406 on any >20k-line docs PR)pr-classify.yml— itsrisk:*label is load-bearing for automerge, so fixing automerge alone wouldn't unbrick large PRscodex-review.yml— file list from the API; diff line count from PRadditions + deletions(identical to the oldgh pr diff | awkcount) instead of fetching the diff bodyThe files-listing endpoint caps at 3000 files. Each gating workflow now handles that cap explicitly instead of silently under-classifying: automerge risk scan fails closed (bypass label remains the human override), safe-paths defers (
all_safe=0, like its empty-diff branch), pr-classify and the codex cost gate stay red.Failure mode 2 —
lint.ymlandprettier-autofix.yml(kept-in-sync duplicates) drop symlinks from the explicit target list before invoking prettier. Link targets still get formatted when they appear in the diff themselves; glob-fallback mode is unaffected (prettier skips glob-expanded symlinks on its own). The empty-array assignment is guarded so the block also runs on bash 3.2 (macOS), where the selftest executes it.Selftests
selftest/test_pr_files_listing.sh— bans executablegh pr diffin the reusables and pins the paginated files-API idiom in all six changed-file consumersselftest/test_prettier_symlink_filter.sh— extracts the shipped filter block from the YAML, runs it against a fixture tree (regular file, symlink, dangling symlink), and asserts lint/prettier-autofix haven't driftedselftest/test_workflow_guards.py— wires the host-independent.shselftests into the pytest self-test path (tests-runner.ymlrunsuv run pytest -qon this repo's PRs), so these guards are CI-enforced rather than run-manually-only.test_bb_automerge_risk_patterns.shstays manual-only (needs the local~/.claude/templatescheckout +requests)Local validation: all four
.shselftests pass,uv run pytest -q6/6, YAML parse clean on all six edited workflows.Auto-merge rationale: manual-merge category — PRs to topcoder1/ci-workflows are always manual merge, and this touches
.github/workflows/**.Codex rounds: 3 (round 1: one P2 — codex cost gate could be silently fooled by a truncated 3000+-file listing — fixed; rounds 2–3 clean).
HUMAN_READABLE_SUMMARY: Large PRs (>20k diff lines) were killing the automerge/risk/prettier CI jobs because GitHub refuses to serve huge diffs; the workflows now ask for the file list page-by-page instead, and prettier no longer chokes on symlinked markdown files. New selftests keep both fixes from regressing.
🤖 Generated with Claude Code