fix(scripts): make check-ts-allowlist.affine compile cleanly (follow-up to #283)#310
Merged
Merged
Conversation
…-broken seed from #283) The seed `.affine` port shipped in #283 never compiled — it used JS-style catch (`catch e { ... }`), bare-brace record literals (`{ raw: ..., ... }`), the private `collections::any` / `string::substring`, and a `string::substring` end-relative semantics call (start, end) where AS expects (start, length). None of these were caught at PR time because nothing in CI runs the AS compiler against the file (`governance-reusable.yml` still invokes the .ts). Refactor to compile cleanly: - `catch e { x }` → `catch { _ => x }` (x3) — AS catch is pattern-match arms. - `{ raw, rx }` → `#{ raw, rx }` (x2) — AS record literals need `#{}`. - Drop `use collections::{ any }` (private); inline the membership loop. - Drop `use string::{ trim, int_to_string, substring }` — `trim` and `int_to_string` are interpreter builtins; `substring` is private. Rewrite call sites to use the `string_sub(s, start, length)` builtin directly, adjusting the two end-relative calls (`len(g2)` -> `len(g2) - 1`). - License: MPL-2.0 -> PMPL-1.0-or-later, matching the .ts source and the per-repo policy in `.machine_readable/licensing-policy.toml`. Verification (from affinescript build oracle): - affinescript check -> Type checking passed - affinescript compile --deno-esm -> out.wasm (Deno-ESM) Workflow remains unchanged — `governance-reusable.yml` still invokes the `.ts` source of truth. This PR only unblocks the planned follow-up of swapping the workflow to the AS-compiled `.deno.js` entry point. Refs #239 (umbrella TS->AffineScript), #241 (STEP 2 tail-batch-1). Follow-up to #283 (seed PR). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…310) Compile-clean wasn't enough — `deno run scripts/check-ts-allowlist.deno.js` crashed on first invocation with two bugs: 1. `Identifier '_' has already been declared` The 12 `let _ = consoleError(...)` / `let _ = println(...)` calls all lower to `const _ = (console.error(...), 0);` in the same block scope — ESM strict-mode rejects the redeclaration. Drop the `let _ =` wrappers; bare expression statements (`consoleError("...");`) lower cleanly and match the merged seed's pattern. 2. `ReferenceError: endsWith is not defined` `Deno.endsWith` is declared as `pub extern fn` in `Deno.affine` but has no entry in the Deno-ESM codegen lookup table — the compiler emits the call site but never the definition (other stdlib `extern fn`s like `walkRecursive`, `regexMatch`, `readTextFile` are codegen-known and get inline `__as_*` shims; `endsWith` isn't on that list). Restore the merged seed's defensive inline helper backed by the `string_sub` builtin and switch all call sites from `endsWith` → `ends_with`. End-to-end runtime verification on local fixtures: empty dir -> exit 0, success line src/Foo.ts violation -> exit 1, error block + file list mod.ts (filename ok) -> exit 0 scripts/x.ts (dir ok) -> exit 0 Behaviour matches the .ts source the regression suite asserts against. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 30, 2026
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…o.js runtime Mirrors the workflow swap in this PR. Three updates to `docs/EXEMPTION-MECHANISMS.adoc`: 1. Layer 4a description — point at `scripts/check-ts-allowlist.affine` as the source of truth, note the compiled `.deno.js` is what the workflow actually runs. 2. History — add a fourth bullet covering standards#283 / #310 / #311: the TS→AffineScript port arc, with the dual-target rationale spelled out (`.ts` kept for regression suite + parallel-validation; `.deno.js` is the workflow target). 3. Cross-references — replace the single `.ts` line with three lines covering all three files (.affine source / .deno.js runtime / .ts archetype) and what each is for. Reduces "which file should I edit?" ambiguity for the next contributor. No behavioural change; pure doc alignment so the prose matches the workflow + source layout after #311 lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…compiled .deno.js (#311) **Depends on: #310** Second half of the seed-PR plan from #283: once the `.affine` source actually compiles + runs (#310), wire the workflow at the AffineScript-compiled output. ## Changes 1. **`scripts/check-ts-allowlist.deno.js`** (NEW, 344 lines) - Generated by `affinescript compile --deno-esm` from the post-#310 `.affine` source. Self-contained Deno-ESM bundle: inlined runtime shims for codegen-known externs (walkRecursive, regexMatch, readTextFile, exit, consoleError) + the `split` / `ends_with` helpers. Auto-invokes `await main()` at module load — same shape Deno runs the existing .ts with. 2. **`.github/workflows/governance-reusable.yml:193`** - `deno run ... check-ts-allowlist.ts` → `... check-ts-allowlist.deno.js` - Comment block explains the dual-target window: .ts kept for the regression suite (`scripts/tests/check-ts-allowlist-test.sh`) and for parallel-validation; retirement is a separate follow-up after the validation window. ## Why ship the compiled artifact (vs compile-in-CI) Compile-in-CI would require an AffineScript toolchain in the workflow (OCaml + dune + affinescript repo as a dep). The compiler is deterministic for this surface; committing the output keeps CI provider-free and matches the precedent in `affinescript/tests/codegen-deno/*.deno.js` (committed golden files). Drift between source and committed output is the obvious risk. Follow-up will add a `just check-ts-allowlist-drift` recipe (recompile + diff) wired into a non-blocking CI lint. ## Verification End-to-end runtime test of the compiled output (matches the runtime fix in PR #310 commit b046787): | fixture | exit | output | |---|---|---| | empty dir | 0 | success line | | `src/Foo.ts` violation | 1 | error block + file list | | `mod.ts` (filename ok) | 0 | success line | | `scripts/x.ts` (dir ok) | 0 | success line | ## Test plan - [ ] CI green on this branch — note AS scanner / Hypatia / SPARK Theatre Gate may need to acknowledge the new committed `.deno.js` as a generated artifact (ignore findings tagged as generated) - [ ] `scripts/tests/check-ts-allowlist-test.sh` still passes against the unchanged .ts archetype (no behavioural change to .ts) - [ ] Caller repos using `governance-reusable.yml` show green "Check for TypeScript" steps after merge Refs #239 (umbrella TS→AffineScript), #241 (STEP 2 tail-batch-1). Follow-up plan: add drift-detection lint, then a separate PR retires the .ts archetype after the parallel-validation window. Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The seed AffineScript port of
check-ts-allowlist.tsshipped via #283 (STEP 2 seed, Refs #239) never actually compiled — nothing in CI runs the AS compiler against it (governance-reusable.ymlinvokes the.ts), so the compile-broken state went unnoticed. This PR makes it parse + type-check + compile cleanly so the planned workflow swap can proceed.What was wrong
catch e { x }(AS catch is pattern-match arms, x3 occurrences){ raw, rx }(AS needs#{}, x2)use collections::{ any }—collections::anyis private (onlyprelude::any([Bool])ispub, wrong signature)use string::{ trim, int_to_string, substring }—trimandint_to_stringare interpreter builtins (nouseneeded);string::substringis private. Existingsubstring(s, start, end)calls also assumed end-relative semantics, but the public alternativestring_sub(s, start, length)is length-relative.What this changes
catch e { "" }catch { _ => "" }[{ raw, rx }][#{ raw, rx }]use collections::{ any }; if (any(fn(a) => s == a, list)) ...while j < len(list) { if s == list[j] ... }use string::{ trim, int_to_string, substring }string_subdirectlysubstring(g2, 1, len(g2))string_sub(g2, 1, len(g2) - 1)(length, not end)// SPDX-License-Identifier: MPL-2.0// SPDX-License-Identifier: PMPL-1.0-or-laterThe license change brings the
.affineinto line with the.tssource it ports and with.machine_readable/licensing-policy.toml(PMPL-1.0-or-later is the preferred SPDX in this repo).Verification
Local AS build oracle (affinescript repo, current
_build/default/bin/main.exe):affinescript check ../standards/scripts/check-ts-allowlist.affine-> Type checking passedaffinescript compile --deno-esm ../standards/scripts/check-ts-allowlist.affine-> Compiled -> out.wasm (Deno-ESM)Scope
governance-reusable.ymlstill invokes the.tssource of truth..affine->.deno.js+ tiny.mjswrapper -> repoint workflow -> retire.ts) is unblocked.Test plan
mainafter merge (re-runaffinescript checkfrom a fresh clone)governance-reusable.ymlRefs #239 (umbrella TS->AffineScript), #241 (STEP 2 tail-batch-1). Follow-up to #283 (seed PR).
Provenance: this work was resumed from a Gemini-CLI session that crashed with
ioctl(2) failed, EBADFinnode-pty/unixTerminal.js:243mid-edit — the parse-error squashing fixes above are what Gemini was attempting when its pty died.Generated with Claude Code