Skip to content

feat(vscode): AffineScript port of extension (TS→AS campaign step 1)#19

Merged
hyperpolymath merged 1 commit into
mainfrom
chore/ts-to-as-step-1-seed-port
May 28, 2026
Merged

feat(vscode): AffineScript port of extension (TS→AS campaign step 1)#19
hyperpolymath merged 1 commit into
mainfrom
chore/ts-to-as-step-1-seed-port

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Adds `editors/vscode/src/extension.affine` — AffineScript port of `extension.ts`, as a parallel artifact alongside the TS source.

Step 1 of the estate-wide TS→AffineScript migration campaign:

Why phronesis first

  • Smallest VSCode extension in the campaign backlog (54 lines).
  • All required surface confirmed bound in AS stdlib: `Vscode::getConfiguration`, `workspaceConfigGetString`, `VscodeLanguageClient::newLanguageClient/Start`.
  • Pattern mirrors the affinescript dogfood at `affinescript/editors/vscode/src/extension.affine`.

What's NOT in this PR

Build pipeline integration is the follow-up:

  • compile `extension.affine` → `out/extension.cjs`
  • swap `package.json` `main` to point at `out/extension.cjs`
  • drop `tsconfig.json` + `typescript` devDep
  • delete `extension.ts`

Until that follow-up lands, `extension.ts` remains the live source. This PR is a low-risk additive step that validates the AS source + binding coverage.

Behavioural notes (documented inline)

  • Unused `path` import omitted.
  • `process.env` preserved by Node child_process default behaviour (`newLanguageClient` binding doesn't take env explicitly).
  • `synchronize.fileEvents` collapsed in the AS binding (host shim derives it from primitives per Vscode.affine + VscodeLanguageClient.affine conventions).
  • Top-level held-client pattern dropped (process-exit closes the server pipe).

Pre-PR ownership gate

```
gh repo view hyperpolymath/phronesis --json owner,isFork,parent
→ owner=hyperpolymath isFork=false parent=null
```

✓ within scope of the campaign (owner-only repo, not a fork).

Test plan

  • AS source compiles to syntactically valid AffineScript (pattern-mirror of dogfood)
  • Follow-up PR: build pipeline integration (compile + swap main)
  • Follow-up PR: smoke test in VSCode dev host

🤖 Generated with Claude Code

… #240)

Adds editors/vscode/src/extension.affine — AffineScript port of
extension.ts, parallel artifact alongside the TS source.

Step 1 of the estate-wide TS→AffineScript migration umbrella
(hyperpolymath/standards#239); seed-port issue #240.

Build pipeline integration (compile extension.affine → out/extension.cjs,
swap package.json `main`, drop tsconfig/typescript devDeps) lands in a
follow-up PR. extension.ts remains live until that swap.

Binding coverage confirmed at this session: Vscode.affine (55 fns) +
VscodeLanguageClient.affine cover all surface the TS used
(getConfiguration, workspaceConfigGetString, newLanguageClient,
languageClientStart). Pattern mirrors affinescript dogfood at
affinescript/editors/vscode/src/extension.affine.

Behavioural notes documented inline:
  - unused `path` import omitted
  - process.env preserved by Node child_process default behaviour
    (host shim handles it)
  - synchronize.fileEvents collapsed in newLanguageClient ABI
  - top-level held-client pattern replaced by activate-only start
    (process-exit closes the server pipe)

Pre-PR ownership gate: owner=hyperpolymath, isFork=false, parent=null
(verified inline).
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 86 issues detected

Severity Count
🔴 Critical 2
🟠 High 11
🟡 Medium 73

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Backup file in root",
    "type": "stale",
    "file": "META.scm.bak",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "medium"
  },
  {
    "reason": "Backup file in root",
    "type": "stale",
    "file": "ECOSYSTEM.scm.bak",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "medium"
  },
  {
    "reason": "Merge artifact in root",
    "type": "stale",
    "file": "SPEC.core.scm.orig",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in codeql.yml",
    "type": "unknown",
    "file": "codeql.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dependabot-automerge.yml",
    "type": "unknown",
    "file": "dependabot-automerge.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "unknown",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "unknown",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "unknown",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath disabled auto-merge May 28, 2026 18:32
@hyperpolymath hyperpolymath enabled auto-merge (squash) May 28, 2026 18:32
@hyperpolymath hyperpolymath disabled auto-merge May 28, 2026 20:04
@hyperpolymath hyperpolymath enabled auto-merge (squash) May 28, 2026 20:04
@hyperpolymath hyperpolymath disabled auto-merge May 28, 2026 20:20
@hyperpolymath hyperpolymath merged commit 7587b9f into main May 28, 2026
19 checks passed
@hyperpolymath hyperpolymath deleted the chore/ts-to-as-step-1-seed-port branch May 28, 2026 23:59
hyperpolymath added a commit to hyperpolymath/standards that referenced this pull request May 30, 2026
…gn 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)
hyperpolymath added a commit that referenced this pull request May 30, 2026
- Swap extension.ts for extension.affine (landed in #19)
- Update package.json main to .out/extension.cjs
- Update compile script to use affinescript compiler
- Remove tsc-specific configuration and devDependencies

Step 1 (follow-up) of the TS->AS migration campaign (#240).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant