From ce529a82f795dc7e27d742dc77d3333637491e89 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 12 Aug 2026 14:42:19 -0500 Subject: [PATCH] fix(hybrid-gate): filter blobs from the two metadata-only checkouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `check-trailer` and `ai-attribution` both clone full history under a 5-minute budget, but neither reads file content — one reads commit trailers and changed path names, the other scans commit messages and PR metadata. On a large adopting repo the unfiltered clone is effectively the whole job. When it overruns, the job reports `cancelled`, which the gate cannot distinguish from a supersede. The PR goes red with nothing wrong with it, and `full-gate-build` is skipped because it needs `check-trailer`. Measured in aletheia: two runs cancelled at exactly 5m04s and 5m02s, both inside this checkout step, on unrelated PRs whose own code was fine. `blob:none` keeps every commit and tree and leaves blobs unfetched. Git lazily fetches any blob a step turns out to need, so this cannot break a future step that does read content — it only stops paying for content nothing reads. `full-gate-build` keeps its unfiltered clone: it compiles the tree. --- .github/workflows/hybrid-gate.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/hybrid-gate.yml b/.github/workflows/hybrid-gate.yml index f296535..761a8d9 100644 --- a/.github/workflows/hybrid-gate.yml +++ b/.github/workflows/hybrid-gate.yml @@ -159,9 +159,20 @@ jobs: found: ${{ steps.trailer.outputs.found }} docs_only: ${{ steps.docs-only.outputs.docs_only }} steps: + # WHY the blob filter: this job needs full history (`fetch-depth: 0`) to + # read commit trailers and name changed paths, but it never reads file + # CONTENT. On a large adopting repo the unfiltered clone is the entire + # job, and when it exceeds `timeout-minutes: 5` the job reports + # `cancelled` — which the gate cannot distinguish from a supersede, so it + # fails a PR that nothing is wrong with. Measured in aletheia: two runs + # cancelled at exactly 5m04s and 5m02s, both inside this checkout step, + # on unrelated PRs. `blob:none` keeps every commit and tree while leaving + # blobs unfetched; git lazily fetches any it turns out to need, so a + # future step that does read content still works. - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 + filter: blob:none persist-credentials: false - name: Check for docs-only changeset @@ -371,9 +382,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: + # WHY the blob filter: same reasoning as check-trailer above — this job + # scans commit messages and PR metadata, never file content, so the + # unfiltered full clone is pure cost against a 5-minute budget. - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 + filter: blob:none persist-credentials: false - name: Verify no AI attribution