Commit bfef9ad
authored
feat(scripts): AffineScript port of check-ts-allowlist (TS->AS campaign STEP 2 seed) (#284)
## Summary
Adds `scripts/check-ts-allowlist.affine` as the AffineScript port of the
existing `scripts/check-ts-allowlist.ts`, filed under the estate
TS->AffineScript migration campaign (#239
umbrella, STEP 2 — tail-batch-1 per standards#241).
**Self-referential**: the script that enforces the no-new-TypeScript
policy is itself one of the TS files that policy applies to. Landing the
AffineScript version is a symbolic milestone for the meta-tool.
**Pattern**: phronesis#19 seed style. Add `.affine` alongside the live
`.ts`. No workflow change in this PR; CI keeps invoking the `.ts` via
`deno run --allow-read
.standards-checkout/scripts/check-ts-allowlist.ts`. Workflow cutover
(compile `.affine` to `.deno.js`, wire wrapper, retire `.ts`) is a
follow-up issue.
## Behaviour equivalence
The regression suite at `scripts/tests/check-ts-allowlist-test.sh`
exercises 13 cases (builtin allowlist classes + Layer-2 CLAUDE.md
exemptions + Layer-2.5 governance-allowlist + dotted-dir skip +
multi-heading-table parsing).
- **All 13 PASS** against the AffineScript-emitted `.deno.js` (verified
locally with a sibling harness using the same fixtures)
- **All 13 PASS** against the original `.ts` (no regression)
Both implementations are behaviour-equivalent on the substring
assertions the suite makes. Cosmetic difference: the `.affine` port uses
ASCII `[FAIL]` / `[OK]` sentinels instead of the original emoji (see
"Seam findings" below).
## Stdlib surface used
All externs already shipped in `stdlib/Deno.affine` via
affinescript#445:
- `walkRecursive` (recursive file enumeration)
- `regexMatch` (JS RegExp.test wrapper)
- `readTextFile` (synchronous file read; throws on missing — wrapped in
`try`/`catch`)
- `args`, `exit`, `consoleError`
Plus AffineScript builtins: `string_get`, `string_sub`, `string_find`,
`char_to_int`, `int_to_string`, `len`.
## AffineScript seam findings surfaced by this port
(Each would be a separate affinescript-repo PR — out of scope for this
per-standards-repo PR per the campaign's ownership gate.)
- **String less-than lex-compare**: not built-in. Implemented inline via
byte-wise `str_lt` (calls `char_to_int(string_get(...))`). Bare `a < b`
on `String` produces `TypeMismatch (String, Int)`.
- **`break`/`continue` in `while`**: `BREAK`/`CONTINUE` tokens are
reserved in `lib/parser.mly` but no production rule uses them yet.
Refactored two natural occurrences (`s_trim` inner loops +
`strip_leading_dot_slash`) to combined-guard / sentinel-boolean forms.
- **Non-ASCII string literals**: lower to octal escape sequences (e.g.
`"\\226\\157\\140"`) in `--deno-esm` output. Strict-mode ESM rejects
octal escapes with `SyntaxError: Octal escape sequences are not allowed
in strict mode.` Worked around with ASCII `[FAIL]` / `[OK]` sentinels.
- **Stale installed binary**: the `affinescript` at `~/.local/bin/`
predated PR #445 and silently emitted bare `walkRecursive(".")` calls
(no `__as_walkRecursive` shim in the prelude). A trunk rebuild surfaces
the new shims correctly.
## Sequencing follow-ups (NOT part of this PR)
- [ ] Compile-time wiring: build `.affine` -> `.deno.js` in CI; commit
`.deno.js` as a generated artefact OR add a precompile step.
- [ ] Workflow cutover: update
`.github/workflows/governance-reusable.yml` to invoke the `.deno.js`
(with the existing `--allow-read` scope).
- [ ] Retire `.ts`: delete `scripts/check-ts-allowlist.ts` and update
`docs/EXEMPTION-MECHANISMS.adoc` references.
- [ ] Upstream affinescript fixes for the 3 seam findings above (file as
separate affinescript-repo issues).
## Test plan
- [x] `affinescript check` type-checks the `.affine`
- [x] `affinescript compile --deno-esm` emits `.deno.js` with no
octal-escape errors
- [x] 13/13 regression tests pass against the AffineScript-emitted
`.deno.js`
- [x] 13/13 regression tests pass against the original `.ts` (no
regression)
- [x] GPG-signed commits
## Refs
- Refs #239 (campaign umbrella)
- Refs #241 (STEP 2 — TAIL BATCH 1)
- Pattern: hyperpolymath/phronesis#19 (STEP 1 seed)
- Unblocked by: hyperpolymath/affinescript#445 (STEP 3 first-cut)
🤖 Generated with [Claude Code](https://claude.com/claude-code)1 parent 9c33dec commit bfef9ad
0 file changed
0 commit comments