From a8ac18e14d6c724421af9843f01b846ab0960f0f Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Sat, 30 May 2026 23:10:02 +0100 Subject: [PATCH] ci(governance): non-blocking drift check for check-ts-allowlist .affine/.deno.js (closes #312) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After #311 swapped the workflow to executing the committed `.deno.js` artifact, the .affine source can silently drift if a maintainer edits it without recompiling. This adds: - `just check-ts-allowlist-drift` recipe — invokes the AffineScript compiler against the .affine source into a temp file and diffs against the committed .deno.js. Exit 0 = in sync. - Non-blocking `continue-on-error: true` CI step in governance-reusable.yml that runs the same diff and surfaces a `::warning::` on drift. Skipped gracefully when the AffineScript compiler isn't on the runner (notice, exit 0). - Pointer comment in check-ts-allowlist.affine header so maintainers see the drift recipe at the obvious place. Non-blocking until the compiler output is hash-pinned per compiler version — the compiler currently stamps a moving "Generated by AffineScript compiler" header. Promotion to blocking is a separate follow-up. Closes #312 Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/governance-reusable.yml | 27 +++++++++++++++++++++++ Justfile | 13 +++++++++++ scripts/check-ts-allowlist.affine | 6 +++++ 3 files changed, 46 insertions(+) diff --git a/.github/workflows/governance-reusable.yml b/.github/workflows/governance-reusable.yml index cd802085..93313ede 100644 --- a/.github/workflows/governance-reusable.yml +++ b/.github/workflows/governance-reusable.yml @@ -199,6 +199,33 @@ jobs: # the .ts is a separate follow-up after the dual-target window. run: deno run --allow-read --no-lock .standards-checkout/scripts/check-ts-allowlist.deno.js + - name: check-ts-allowlist source/compile drift (informational) + # Non-blocking — informational until the AffineScript compiler + # output is hash-pinned per compiler version. The compiler header + # currently stamps "Generated by AffineScript compiler" which is + # a moving target as the codegen evolves, so spurious diff = + # "compiler bumped" vs real diff = "someone edited .affine + # without recompiling". Promotion to blocking is gated on a + # compiler-version pin landing (see standards#312). + continue-on-error: true + run: | + if ! command -v affinescript >/dev/null 2>&1; then + echo "::notice::affinescript compiler unavailable on runner — skipping drift check" + exit 0 + fi + tmp="$(mktemp /tmp/check-ts-allowlist-drift.XXXXXX.deno.js)" + if ! affinescript compile --deno-esm -o "$tmp" .standards-checkout/scripts/check-ts-allowlist.affine; then + echo "::warning::affinescript compile failed — drift check skipped" + rm -f "$tmp" + exit 0 + fi + if diff -u .standards-checkout/scripts/check-ts-allowlist.deno.js "$tmp"; then + echo "✅ check-ts-allowlist .affine source and .deno.js compiled output are in sync" + else + echo "::warning::check-ts-allowlist.deno.js drifted from check-ts-allowlist.affine — re-run \`just check-ts-allowlist-drift\` locally and recommit the .deno.js" + fi + rm -f "$tmp" + # Shared escape hatch for the banned-language-file checks below. # Honours three exemption mechanisms (see # standards/docs/EXEMPTION-MECHANISMS.adoc): diff --git a/Justfile b/Justfile index 04878146..b08ad870 100644 --- a/Justfile +++ b/Justfile @@ -125,6 +125,19 @@ help-me: @echo "Include the output of 'just doctor' in your report." +# Verify scripts/check-ts-allowlist.deno.js matches what compiling +# scripts/check-ts-allowlist.affine produces. Run after editing the +# .affine source. Exit 0 = in sync; non-zero with diff = drifted. +# See standards#312. +check-ts-allowlist-drift: + @command -v affinescript >/dev/null 2>&1 || { echo "affinescript compiler not on PATH — skipping drift check"; exit 0; } + @tmp="$$(mktemp /tmp/check-ts-allowlist-drift.XXXXXX.deno.js)"; \ + affinescript compile --deno-esm -o "$$tmp" scripts/check-ts-allowlist.affine; \ + diff -u scripts/check-ts-allowlist.deno.js "$$tmp"; \ + rc=$$?; \ + rm -f "$$tmp"; \ + exit $$rc + # Print the current CRG grade (reads from READINESS.md '**Current Grade:** X' line) crg-grade: @grade=$$(grep -oP '(?<=\*\*Current Grade:\*\* )[A-FX]' READINESS.md 2>/dev/null | head -1); \ diff --git a/scripts/check-ts-allowlist.affine b/scripts/check-ts-allowlist.affine index 7e992a29..ccaa265b 100644 --- a/scripts/check-ts-allowlist.affine +++ b/scripts/check-ts-allowlist.affine @@ -5,6 +5,12 @@ // // Step 2 of the estate-wide TypeScript → AffineScript migration campaign // (hyperpolymath/standards#239 umbrella, #241 tail-batch-1 issue). +// +// Compiled output: scripts/check-ts-allowlist.deno.js (committed). After +// editing this file, re-run `just check-ts-allowlist-drift` to verify the +// committed .deno.js matches what compiling this source produces. The +// governance reusable runs the same check in CI as a non-blocking +// informational step (standards#312). use Deno::{ readTextFile, walkRecursive, exit, consoleError,