From 61f929e9163f62fab4e1465980958fa2bbcf4933 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 01:03:52 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=EC=8B=9C=EC=9E=91=20=E2=80=94=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=202=EB=8B=A8=EA=B3=84=20PR=2010:=20=EB=AC=B8=EC=84=9C?= =?UTF-8?q?=C2=B7=EC=BD=94=EB=93=9C=20=EC=96=B4=EA=B8=8B=EB=82=A8=EC=9D=84?= =?UTF-8?q?=20=EB=A7=A4=EC=A3=BC=20=EC=B0=BE=EC=95=84=20=EC=95=8C=EB=A6=AC?= =?UTF-8?q?=EB=8A=94=20drift=20=EC=9B=8C=ED=81=AC=ED=94=8C=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DyQnQUJ2K2X8ya4UcujAYC From b5f24c5ee0636046959b2a09f66aac3e71db4381 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 01:05:39 +0000 Subject: [PATCH 2/2] ci: run the drift checks and the text lock on every pull request Web CI starts only on web/ and hardware/case/, so a pull request that edits only the BOM or a bundle never ran check:drift. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DyQnQUJ2K2X8ya4UcujAYC --- .github/workflows/drift.yml | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/drift.yml diff --git a/.github/workflows/drift.yml b/.github/workflows/drift.yml new file mode 100644 index 00000000..afff5d8d --- /dev/null +++ b/.github/workflows/drift.yml @@ -0,0 +1,70 @@ +name: Drift checks + +# The tree keeps some facts in two places by hand: the BOM and the build +# guide's parts table, a card on /editions and a folder under +# firmware/bundles/. Each check in web/scripts/drift/ compares one such pair +# and prints both sides when they part (docs/rfc-cleanup.md §2.4). check:ci +# runs them too, but Web CI starts only on web/ and hardware/case/. A pull +# request that edits only the BOM, a bundle or the changelog runs no web job, +# and that is the pull request a drift check is for. So this one runs on every +# pull request. +# +# PF_DRIFT_STRICT=1 turns a skip into a failure. At a desk a check skips a side +# it cannot read: a tag the clone lacks, no pdftotext, no gh login. Here every +# side can be read, so a skip means this file is missing something. +# fetch-depth: 0 brings the tags the absolute links point at, and the base +# commit check:human-lock compares with. +on: + pull_request: + push: + branches: [main] + +concurrency: + group: drift-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + issues: read + +jobs: + check: + runs-on: ubuntu-latest + defaults: + run: + working-directory: web + env: + PF_DRIFT_STRICT: "1" + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: web/package-lock.json + + - name: Install dependencies + id: deps + run: npm ci + + # check:bom-schematic reads the schematic's text layer with pdftotext, + # which the runner image does not carry. + - name: Install pdftotext + run: command -v pdftotext || { sudo apt-get update -q && sudo apt-get install -y -q poppler-utils; } + + # check:roadmap asks gh for the state of each issue a roadmap node names. + - name: Drift checks + run: npm run check:drift + env: + GH_TOKEN: ${{ github.token }} + + # Not a word of the maintainer's own writing changes (§2.9). It runs + # after a red drift step too, so one push shows both. + - name: Locked text + if: ${{ !cancelled() && steps.deps.outcome == 'success' && github.event_name == 'pull_request' && hashFiles('web/scripts/human-lock.ts') != '' }} + run: npm run check:human-lock + env: + PF_LOCK_BASE: ${{ github.event.pull_request.base.sha }}