Skip to content

docs: authoritative ledger — CAPABILITY-MATRIX/ECOSYSTEM/TECH-DEBT (Refs #175 #176) - #239

Merged
hyperpolymath merged 3 commits into
mainfrom
docs/ecosystem-truthing-v2
May 19, 2026
Merged

docs: authoritative ledger — CAPABILITY-MATRIX/ECOSYSTEM/TECH-DEBT (Refs #175 #176)#239
hyperpolymath merged 3 commits into
mainfrom
docs/ecosystem-truthing-v2

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Authoritative ledger — the never-landed "first PR" of #175

Issue #175 states docs/CAPABILITY-MATRIX.adoc, docs/ECOSYSTEM.adoc, and
docs/TECH-DEBT.adoc "landed in the first PR (docs/ecosystem-truthing)".
They exist nowhere in git history — the docs/ecosystem-truthing branch
has zero diff vs main. Yet every sub-issue (#176–183, #228, #177) cites
docs/TECH-DEBT.adoc as its coordination index and as where Stages D/E are
defined. This PR materialises that ledger authoritatively, reconstructed
2026-05-19 from the issues, the compiler-as-oracle audit, and the
hyperpolymath/typed-wasm LEVEL-STATUS.md (v1.5).

What's in it

  • docs/CAPABILITY-MATRIX.adoc — single authoritative readiness source;
    overrides README / BACKEND-IMPLEMENTATION / COMPILER-CAPABILITIES /
    ALPHA-1-RELEASE-NOTES / STATE.a2ml. Truthed: alpha; the CORE-01 borrow
    soundness gap (CORE-01: complete borrow checker Phase-3 (borrow-graph validation) #177) named explicitly; backend breadth real but uneven
    (one reference target, not "N production backends"); typed-wasm is a
    separate language-agnostic target and AffineScript is one producer

    (ephapax is another).
  • docs/ECOSYSTEM.adoc — the implementation spine and the macro-stage
    spine: Stage A–E definitions established here (they were cited but
    never committed); the actual AS↔typed-wasm contract (narrow — L7+L10 on
    emitted wasm via the affinescript.ownership section, multi-producer);
    the truthed satellite registry; the INT-01..12 roadmap with
    blocked-by/critical-path.
  • docs/TECH-DEBT.adoc — the coordination ledger
    (DOC/CORE/STDLIB/INT/SAT), critical path diagram, update protocol.
  • Authoritative banners on the four over-claiming docs (DOC-04);
    STATE.a2ml drift-flagged (DOC-05); ROADMAP.adoc cross-links (DOC-06).
    DOC-01/02/03/07 done here.

Safety / scope

Docs-only. Gate unaffected: opam exec --switch=. -- dune runtest --force
= 260/260 (2026-05-19). The pre-existing local affinescript.opam
build-env drift was deliberately not staged.

Refs #175 #176 — not Closes (the epic is owner-closed only). Front-loaded
ahead of CORE-01 (#177) so that work unit can cite a real TECH-DEBT line.

🤖 Generated with Claude Code

…efs #175 #176)

The "first PR" #175 claims landed (docs/CAPABILITY-MATRIX.adoc,
docs/ECOSYSTEM.adoc, docs/TECH-DEBT.adoc) never existed in git history;
every sub-issue (#176-183, #228, #177) cites docs/TECH-DEBT.adoc as its
coordination index. This materialises that ledger authoritatively,
reconstructed 2026-05-19 from the issues + the compiler-as-oracle audit +
the hyperpolymath/typed-wasm LEVEL-STATUS (v1.5).

- docs/CAPABILITY-MATRIX.adoc: single authoritative readiness source
  (overrides README/BACKEND-IMPLEMENTATION/COMPILER-CAPABILITIES/
  ALPHA-1-RELEASE-NOTES/STATE.a2ml). Truthed: alpha; CORE-01 borrow
  soundness gap named; backend breadth real but uneven; typed-wasm is a
  separate language-agnostic target, AffineScript is one producer.
- docs/ECOSYSTEM.adoc: the implementation spine + the macro-stage spine
  (Stage A–E definitions, established here — never committed before),
  the actual AS↔typed-wasm contract (narrow: L7+L10 on emitted wasm;
  affinescript.ownership section; multi-producer w/ ephapax), the truthed
  satellite registry, and the INT-01..12 integration roadmap.
- docs/TECH-DEBT.adoc: the coordination ledger (DOC/CORE/STDLIB/INT/SAT),
  critical path, update protocol. DOC-01/02/03/07 done here.
- Authoritative banners: README.adoc, BACKEND-IMPLEMENTATION.md,
  COMPILER-CAPABILITIES.md, ALPHA-1-RELEASE-NOTES.md (DOC-04).
- STATE.a2ml drift-flagged (DOC-05); ROADMAP.adoc cross-links (DOC-06).

Docs-only; gate unaffected (dune runtest --force = 260/260, 2026-05-19).
Front-loaded ahead of CORE-01 (#177) so that work unit cites a real ledger.

Refs #175 #176

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CORE-01 borrow-graph validation part 1 landed via PR #240. Keep the
authoritative docs in lockstep (DOC-01..09 / #176 — "docs current as you
go"):
- CAPABILITY-MATRIX.adoc borrow row: graph validation landed; remaining
  NLL/flow-sensitive deferred to part 2+.
- TECH-DEBT.adoc CORE-01: part 1 LANDED (PR #240); part 2+ scoped.
- STATE.a2ml borrow-checker feature line updated (it mirrors).

Each file stays single-owner: the compiler change is PR #240 off main;
these doc/ledger files are owned by this branch (#239).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 44 issues detected

Severity Count
🔴 Critical 12
🟠 High 21
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Stray AI.a2ml in root -- use 0-AI-MANIFEST.a2ml only",
    "type": "banned",
    "file": "AI.a2ml",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Superseded by 0-AI-MANIFEST.a2ml",
    "type": "banned",
    "file": "AI.djot",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

…#228)

Module-qualified type/effect paths landed via PR #241 (zero Menhir
conflict delta, gate 267/267). Keep the authoritative docs in lockstep:
- TECH-DEBT.adoc CORE-03: grammar LANDED (PR #241), supersedes #231;
  estate re-audit + #229 follow.
- CAPABILITY-MATRIX.adoc parser row: qualified paths now parse;
  dominant estate parse blocker cleared.
- STATE.a2ml parser feature line updated (it mirrors).

ADR-014 itself is recorded in META.a2ml + SETTLED-DECISIONS.adoc on the
#241 branch (those ADR registries are owned by the implementation PR;
these ledger/status docs are owned by #239 — single-owner discipline).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 44 issues detected

Severity Count
🔴 Critical 12
🟠 High 21
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Stray AI.a2ml in root -- use 0-AI-MANIFEST.a2ml only",
    "type": "banned",
    "file": "AI.a2ml",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Superseded by 0-AI-MANIFEST.a2ml",
    "type": "banned",
    "file": "AI.djot",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath
hyperpolymath merged commit 78d7ec7 into main May 19, 2026
13 of 14 checks passed
@hyperpolymath
hyperpolymath deleted the docs/ecosystem-truthing-v2 branch May 19, 2026 15:18
hyperpolymath added a commit that referenced this pull request May 19, 2026
…onical map (Refs #229)

#228/ADR-014 landed on main (#241), unblocking #229 step 2. This is the
front-loaded #229 foundation (the #239-analogue for the estate-port arm):
authoritative re-audit + true scope + language-grounded canonical map +
escalations + the campaign reproducer.

Re-audit (oracle = main w/ #241; same cached corpus = controlled):
552 PASS / 491 DRIFT-SYNTAX / 133 TYPE-ONLY over 1176 .affine. Zero
class-delta vs the superseded #231 postfix (#241 reproduces ADR-014 parse
behaviour exactly).

Honest scope correction: DRIFT-SYNTAX (491) is NOT the workload. Most
estate DRIFT is non-RS syntax drift, out of #229's contract. True RS
scope = ~84 files / 12 repos (burble 32 + idaptik-dlc-vm 28 = 71%).

Canonical RS->AffineScript map, derived language-side (grammar/spec/stdlib,
each form cited), in four tiers:
- Tier 1 mechanical: array<T>->[T], option/result-><Option|Result>[..],
  List(X)->[X], open Mod->use Mod::*;, type rec->type (parser.mly:486/394/172,
  prelude.affine:19-21, traits.affine:89).
- Tier 2 semantic redesign: mutable-field, labelled (~x), Belt/Js stdlib.
- Tier 3 escalated language-side (the #228 bidirectional-evidence
  discipline): %%raw -> #245, JSON.t -> #246, Dict.t -> #247.
- Tier 4 cross-unit gate: import X as Y parses + alias registers
  (resolve.ml:787-797) but qualified-value calls hit the INT-01 #178 gap
  (resolve.ml:719/797) => idaptik-dlc-vm's 28-file port is gated on
  INT-01 #178; burble + the List(X) quick wins are not.

Adds:
- tools/estate-rs-audit/ — audit.sh + rs-inventory.sh + repo list +
  captured data (results.post228.tsv, rs-inventory.tsv) + README. The
  durable in-repo home the prior /tmp harness lacked.
- docs/RESCRIPT-ELIMINATION.adoc — authoritative #229 ledger.
- TECH-DEBT CORE-03 truthed (#241 merged; re-audit done; ledger ptr).
- ECOSYSTEM see-also cross-link.

No compiler/build input changed (docs + tools + data only); dune build
clean; 270 gate unaffected by construction. Refs #229 (not Closes —
multi-repo, sequenced, human-gated; per-repo port PRs follow).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request May 19, 2026
…onical map (#248)

* docs(estate): #229 foundation — post-#228 re-audit, RS inventory, canonical map (Refs #229)

#228/ADR-014 landed on main (#241), unblocking #229 step 2. This is the
front-loaded #229 foundation (the #239-analogue for the estate-port arm):
authoritative re-audit + true scope + language-grounded canonical map +
escalations + the campaign reproducer.

Re-audit (oracle = main w/ #241; same cached corpus = controlled):
552 PASS / 491 DRIFT-SYNTAX / 133 TYPE-ONLY over 1176 .affine. Zero
class-delta vs the superseded #231 postfix (#241 reproduces ADR-014 parse
behaviour exactly).

Honest scope correction: DRIFT-SYNTAX (491) is NOT the workload. Most
estate DRIFT is non-RS syntax drift, out of #229's contract. True RS
scope = ~84 files / 12 repos (burble 32 + idaptik-dlc-vm 28 = 71%).

Canonical RS->AffineScript map, derived language-side (grammar/spec/stdlib,
each form cited), in four tiers:
- Tier 1 mechanical: array<T>->[T], option/result-><Option|Result>[..],
  List(X)->[X], open Mod->use Mod::*;, type rec->type (parser.mly:486/394/172,
  prelude.affine:19-21, traits.affine:89).
- Tier 2 semantic redesign: mutable-field, labelled (~x), Belt/Js stdlib.
- Tier 3 escalated language-side (the #228 bidirectional-evidence
  discipline): %%raw -> #245, JSON.t -> #246, Dict.t -> #247.
- Tier 4 cross-unit gate: import X as Y parses + alias registers
  (resolve.ml:787-797) but qualified-value calls hit the INT-01 #178 gap
  (resolve.ml:719/797) => idaptik-dlc-vm's 28-file port is gated on
  INT-01 #178; burble + the List(X) quick wins are not.

Adds:
- tools/estate-rs-audit/ — audit.sh + rs-inventory.sh + repo list +
  captured data (results.post228.tsv, rs-inventory.tsv) + README. The
  durable in-repo home the prior /tmp harness lacked.
- docs/RESCRIPT-ELIMINATION.adoc — authoritative #229 ledger.
- TECH-DEBT CORE-03 truthed (#241 merged; re-audit done; ledger ptr).
- ECOSYSTEM see-also cross-link.

No compiler/build input changed (docs + tools + data only); dune build
clean; 270 gate unaffected by construction. Refs #229 (not Closes —
multi-repo, sequenced, human-gated; per-repo port PRs follow).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(estate): #229 ledger — oracle-grounded corrections (Refs #229)

Oracle-peeled the four allegedly "quick-win" *_gui.affine files. Findings,
all compiler-verified, folded back into RESCRIPT-ELIMINATION.adoc before
#248 merges (soundness-first; the foundation must be correct):

1. Record sigil is the DOMINANT estate blocker and was NOT in #229's named
   construct set. spec.md:414-421 prescribes the exact rewrite: expression-
   /pattern-position record literal `{`->`#{` (typed `T #{…}`); leave
   struct/type decl bodies. Oracle: bare `{x:1}` / `M{x:1}` / `M(x:1)` all
   parse-error; `Type #{…}` is the form. Added as the lead Tier-1 row.

2. Angle-brackets are NOT RS surface. Oracle: `Option<Int>` passes — both
   `<>` and `[ ]` type-application parse. The RS tell is the lowercase
   type name, not the brackets. Tier-1 row corrected (was an overclaim).

3. The text-scan inventory is a lower-bound triage signal, not the true
   per-file inventory: the oracle stops at the first parse error, so deeper
   RS layers are invisible until earlier ones go (the *_gui files scan as
   "List(X) only" but also need `#{` beneath). Added an explicit WARNING.

4. Scanner false positive: `mutable-field` matched a comment in
   panll/.../wizard.affine. panll carries no listed RS construct; its real
   fault is an enum trailing comma (not a #229 construct). panll
   reclassified OUT of #229 (scope now ~83 files / 11 repos).

5. No trivial single-construct quick wins exist — even one-RS-flagged
   files are multi-layer; per-repo plan + Tier-4 wording corrected.

docs-only; dune build clean; 270 gate unaffected by construction.
Refs #229.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: hyperpolymath <hyperpolymath@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request May 30, 2026
…r (step #242) (#445)

## Summary

Adds six externs to `stdlib/Deno.affine` to unblock the TS→AffineScript
estate migration:

- `walkRecursive(root) -> [String]` — depth-first file walk
- `args() -> [String]` — `Deno.args`
- `exit(code) -> Int` — `Deno.exit` (never returns)
- `dateNowIso() -> String` — `new Date().toISOString()`
- `consoleError(s) -> Int` — stderr; returns 0
- `regexMatch(s, pat) -> Bool` — `new RegExp(pat).test(s)`

These were surfaced by surveying the campaign #239 step 2 tail-batch-1
candidates: two pure-logic Deno CLI scripts (`panic-attack
docs/campaigns/2026-05-26/01-triage.ts` and
`standards/scripts/check-ts-allowlist.ts`) become portable using only
the existing `Deno.affine` surface plus these six additions.

## Lowering

- `walkRecursive`, `regexMatch` get tiny prelude shims
(`__as_walkRecursive` recurses through `Deno.readDirSync`;
`__as_regexMatch` wraps `RegExp.test`).
- `args`, `exit`, `dateNowIso`, `consoleError` lower directly to host
expressions.

## Test plan

- [x] `dune build` — green
- [x] New fixture
`tests/codegen-deno/deno_scripting.{affine,harness.mjs}` — in-memory FS
for walk, captured stderr, intercepted exit. New harness passes.
- [x] All 12 codegen-deno harnesses pass
- [x] `dune runtest` — 346 tests green

## Refs

- Refs hyperpolymath/standards#242 (STEP 3 — STDLIB FILL)
- Refs hyperpolymath/standards#239 (campaign umbrella)

## Notes

This is the first-cut for step 3. Other gaps not addressed here (HTTP
server, `fetch`, `crypto.subtle`, `Deno.Command`, recursive-stat with
`isFile`/`isDirectory` flags) remain on the step-3 docket — they block
heavier ports (mock-echidna, civic-connect services, dotfiles health
host) which are out of scope for tail-batch-1.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
hyperpolymath added a commit that referenced this pull request Jun 1, 2026
…tters (Refs #239, closes standards#326) (#507)

Adds the raw binary I/O surface that estate ABI-test ports need
(`raze-tui`'s 16-byte `RazeEvent` record, future tree-sitter-k9 /
tree-sitter-a2ml grammar fixtures, half of bofig's contract tests).

Companion to the read-only `bytesLength` / `bytesByteAt` /
`bytesAsciiSlice` accessors shipped in affinescript#504 (STEP 3 /
standards#242). Together the two PRs give AffineScript first-class
binary-buffer support.

## What lands

### `stdlib/Deno.affine` (+10 externs)

| extern | lowers to | notes |
|---|---|---|
| `bytes_new(n) -> Bytes` | `new Uint8Array(n)` | zeroed |
| `bytes_fill(n, byte) -> Bytes` | `(new Uint8Array(n)).fill(byte &
0xFF)` | all-byte buffer |
| `bytes_set_u8(b, off, v) -> Int` | `… .setUint8(off, v & 0xFF), 0` |
returns 0 |
| `bytes_set_u16_le(b, off, v) -> Int` | `… .setUint16(off, v & 0xFFFF,
true), 0` | LE |
| `bytes_set_u32_le(b, off, v) -> Int` | `… .setUint32(off, v >>> 0,
true), 0` | LE |
| `bytes_set_i32_le(b, off, v) -> Int` | `… .setInt32(off, v \| 0,
true), 0` | LE |
| `bytes_get_u8(b, off) -> Int` | `… .getUint8(off)` | |
| `bytes_get_u16_le(b, off) -> Int` | `… .getUint16(off, true)` | LE |
| `bytes_get_u32_le(b, off) -> Int` | `… .getUint32(off, true)` | LE |
| `bytes_get_i32_le(b, off) -> Int` | `… .getInt32(off, true)` | LE |

All multi-byte integer variants are little-endian — the estate's C ABI
contracts (raze-tui `raze-events.ads`, Idris2 `Events.idr`) are
LE-pinned. Setters return `Int = 0` so they compose in an
expression-statement position; the caller is responsible for the
buffer-bounds invariant (an out-of-range offset throws `RangeError` at
the host boundary). Bounds-check via `bytesLength` from #504.

### Tests

`tests/codegen-deno/bytes_binary_io.{affine,deno.js,harness.mjs}` —
round-trips a raze-tui-shaped RazeEvent record (LE i32 + u32 + u8 + u16
× 2) with field-level equality, plus boundary cases:
- u32 max (`0xFFFFFFFF`) round-trips
- i32 -1 preserves sign
- LE byte order verified byte-by-byte via `DataView` (`0x12345678`
writes low byte at offset 4, high byte at offset 7)
- `bytes_fill` masks `256 → 0`, `-1 → 0xFF`, `0xFF → 0xFF`
- `bytes_new` produces a zero-initialised buffer

## Verification

| step | result |
|---|---|
| `dune build bin/main.exe` | ✅ |
| `dune runtest` | ✅ 353/353 |
| `./tools/run_codegen_deno_tests.sh` | ✅ all harnesses (incl. the new
one) |

## Out of scope

- **Big-endian variants** — not needed by any current estate ABI;
revisit if/when an external API forces BE.
- **64-bit getters/setters** (`*_i64_le`) — defer; current STEP 4
candidates max out at 32-bit.

## Relation to #504 (STEP 3)

Both this PR and #504 add externs to `stdlib/Deno.affine` and lowerings
to `lib/codegen_deno.ml`. The two sets are disjoint at the symbol level:
- #504: `statIsFile`, `statIsDirectory`, `bytesLength`, `bytesByteAt`,
`bytesAsciiSlice`, `importMetaUrl`, `pub fn ends_with`, wildcard-let
codegen fix.
- this PR: 10 binary I/O externs in a separate section.

The bytes test fixture uses uniquely-named `let _r0 = …`, `let _r4 = …`,
etc. instead of the `let _ = …` form so this PR is independently
mergeable from #504; once #504 lands, the fixture could be simplified to
use the wildcard pattern.

## Refs

- Closes standards#326
- Refs: standards#239 (umbrella), standards#242 / #504 (STEP 3
predecessor), standards#243 (STEP 4 per-repo unblock target)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request Jun 1, 2026
…efs #239, #242) (#504)

Closes the smallest, safest tractable gaps that the four merged STEP-2
TS→AffineScript ports — phronesis#19, session-sentinel#25,
tropical-resource-typing#15, nafa-app#23 — flagged for STEP 3 of the
estate-wide campaign (`hyperpolymath/standards#239`, sub-issue `#242`).

## What lands

### `stdlib/Deno.affine` (+6 externs)

| extern | lowers to | gap |
|---|---|---|
| `statIsFile(path) -> Bool` | `Deno.statSync(path).isFile` | 3 |
| `statIsDirectory(path) -> Bool` | `Deno.statSync(path).isDirectory` |
3 |
| `bytesLength(b) -> Int` | `(b).length` | 4 |
| `bytesByteAt(b, i) -> Int` | `(b)[i]` | 4 |
| `bytesAsciiSlice(b, s, e) -> String` |
`String.fromCharCode(...(b).slice(s, e))` | 4 |
| `importMetaUrl() -> String` | `import.meta.url` | 5 |

The `bytes*` accessors give AffineScript first-class read access to the
opaque `Bytes` returned by `readFileBytes` so callers can peek at
file-magic / fixed-width binary headers without round-tripping through
`readTextFile` (which throws on binary). `importMetaUrl` exposes the JS
`__dirname` / `__filename` idiom for "find my own location"; only legal
at module top level, which the Deno-ESM backend's output already is.

### `stdlib/string.affine` (1 char)

`fn ends_with` → `pub fn ends_with`. The function existed but was
private, so the four STEP-2 ports each inlined a `string_sub`-backed
helper instead of importing it. Gap 2.

### `lib/codegen_deno.ml` — wildcard `let _` fix (gap 7)

`StmtLet { sl_pat = PatWildcard _; … }` now lowers to a bare expression
statement instead of `const _ = X;`. Three back-to-back `let _ = side()`
discards in the same scope tripped JS `SyntaxError: Identifier '_' has
already been declared`. The wildcard pattern doesn't bind, so dropping
the binding entirely preserves AffineScript semantics (evaluate for side
effects).

```js
// before
function discard_chain() {
  const _ = side(1);
  const _ = side(2);   // ❌ SyntaxError
  const _ = side(3);
  return 42;
}

// after
function discard_chain() {
  side(1);
  side(2);
  side(3);
  return 42;
}
```

### Tests

`tests/codegen-deno/deno_scripting_part2.{affine,deno.js,harness.mjs}` —
11 assertions across the new lowerings + the wildcard fix. The harness
reaching its discard-chain assertion is itself the test for gap 7: a
syntax-error generated module would have thrown at the dynamic `import`
line before any assert ran.

## Verification

| step | result |
|---|---|
| `dune build bin/main.exe` | ✅ |
| `dune runtest` | ✅ 353/353 |
| `./tools/run_codegen_deno_tests.sh` | ✅ all harnesses (incl. the new
one) |

## What does not land here (deferred deliberately)

- **gap 1** — `Deno.test` extern lowering. The four merged STEP-2 ports
use a panic-on-fail `main()` driver and it works; not unblocking STEP 4.
- **gap 6** — native TOML parser. Heavier work; STEP-2 ports used regex
field-presence checks where TOML mattered.

Gaps 9 (`AFFINESCRIPT_STDLIB` env discovery ladder, shipped #433) and 10
(negative integer literals, verified working in all contexts — match
arms, array literals, equality, ternaries) were audited as
already-resolved.

## Refs

- Closes 6 of the 10 gaps blocking `hyperpolymath/standards#242` (STEP 3
of `#239`).
- Unblocks STEP 4 (`#243`, mid-tier 4-9 file ports) and STEP 5 (`#244`,
idaptik DLC) for any consumer that needs stat predicates, byte
accessors, module-URL inspection, the public `ends_with`, or multiple
`let _` discards in a single scope.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request Jun 1, 2026
…ses standards#327) (#509)

Adds the randomness + high-res-timer surface that estate property tests
and benchmark fixtures need:
- `bofig/tests/property/graph_properties_test.ts` (377L) substitutes
`\`\${prefix}_\${Math.floor(Math.random() * 1000000)}\`` for ID
generation.
- Bench tests want sub-millisecond timings (`performance.now()`).

## What lands

### `stdlib/Deno.affine` (+4 externs)

| extern | lowers to | notes |
|---|---|---|
| `math_random() -> Float` | `Math.random()` | `[0, 1)`. JS PRNG,
non-crypto. |
| `random_u32() -> Int` | `((Math.random() * 4294967296) >>> 0)` |
uniform u32 |
| `random_in_range(lo, hi) -> Int` | `Math.floor(Math.random() * (hi -
lo)) + lo` | uniform `[lo, hi)` |
| `performance_now() -> Float` | `performance.now()` | high-res sub-ms
timer |

`math_random` is the JS PRNG — **not cryptographically secure**.
Sufficient for property-test input generation, sampling, and
simulations. For cryptographic random bytes a separate
`crypto_random_bytes` binding routing to `crypto.getRandomValues()`
belongs in a different sub-issue (different host call, different threat
model).

### Tests

`tests/codegen-deno/random_smoke.{affine,deno.js,harness.mjs}` covers:
- 1000 `math_random` draws all in `[0, 1)`
- 10000 `random_u32` draws all in `[0, 2^32)` with ≥ 1000 distinct
values (catches degenerate-PRNG regression)
- 1000 `random_in_range(0, 100)` draws all in `[0, 100)`
- 500 `random_in_range(50, 60)` draws cover most of the window
- `performance_now` monotone non-decreasing across three consecutive
calls (catches clock-resolution regression)

## Verification

| step | result |
|---|---|
| `dune build bin/main.exe` | ✅ |
| `dune runtest` | ✅ 353/353 |
| `./tools/run_codegen_deno_tests.sh` | ✅ all harnesses (incl. the new
one) |

## Out of scope

- **Seeded RNG** (`@std/random`) — defer until a determinism-needing
property test surfaces.
- **`sleep` / `setTimeout`** — separate effect surface; not blocking
STEP 4.

## Relation to #504 + #507

The three STEP 3 / STEP 4-A / STEP 4-B PRs all add disjoint externs to
`stdlib/Deno.affine` and `lib/codegen_deno.ml`. Each is independently
mergeable from origin/main; expected merge order is #504#507 → this
PR but the file sections are separate enough that the rebases are
mechanical.

## Refs

- Closes standards#327
- Refs: standards#239 (umbrella), standards#243 (STEP 4 per-repo unblock
target), affinescript#504 (STEP 3 sibling), affinescript#507 (STEP 4-A
sibling)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant