Skip to content

feat(stdlib): close 6 STEP-3 Deno-ESM gaps surfaced by TS→AS ports (Refs #239, #242) - #504

Merged
hyperpolymath merged 5 commits into
mainfrom
claude/step3-stdlib-gap-closures-v2
Jun 1, 2026
Merged

feat(stdlib): close 6 STEP-3 Deno-ESM gaps surfaced by TS→AS ports (Refs #239, #242)#504
hyperpolymath merged 5 commits into
mainfrom
claude/step3-stdlib-gap-closures-v2

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

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_withpub 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).

// 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 1Deno.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

…efs #239, #242)

Closes the smallest, safest tractable gaps that the four merged STEP-2
ports (phronesis#19, session-sentinel#25, tropical-resource-typing#15,
nafa-app#23) flagged for STEP 3 (campaign #239):

Stdlib (`stdlib/Deno.affine`):
  + `statIsFile`        — `Deno.statSync(p).isFile`  (gap 3)
  + `statIsDirectory`   — `Deno.statSync(p).isDirectory`  (gap 3)
  + `bytesLength`       — `(b).length`               (gap 4)
  + `bytesByteAt`       — `(b)[i]`                   (gap 4)
  + `bytesAsciiSlice`   — `String.fromCharCode(...(b).slice(start, end))`  (gap 4)
  + `importMetaUrl`     — `import.meta.url`          (gap 5)

Stdlib (`stdlib/string.affine`):
  ! `ends_with` is now `pub` so consumers can `use string::{ends_with};`
    instead of inlining a `string_sub`-backed helper.   (gap 2)

Codegen (`lib/codegen_deno.ml`):
  ! `StmtLet { sl_pat = PatWildcard _; … }` lowers to a bare expression
    statement instead of `const _ = X;`. Three back-to-back `let _ = …`
    discards in the same scope used to trip JS
    `SyntaxError: Identifier '_' has already been declared`.  (gap 7)

Tests:
  + tests/codegen-deno/deno_scripting_part2.{affine,deno.js,harness.mjs}
    exercises every new lowering plus the wildcard fix (11 assertions).
  ✓ All 353 dune-runtest tests pass.
  ✓ All codegen-Deno-ESM harnesses pass (`tools/run_codegen_deno_tests.sh`).

Two further gaps from the STEP-2 set remain open, deliberately deferred:
  - gap 1 `Deno.test` extern lowering — panic-on-fail `main()` driver in
    the four merged STEP-2 ports works; not unblocking STEP 4.
  - gap 6 native TOML parser — heavier work; STEP-2 ports used regex
    field-presence checks where TOML was relevant.

Gaps 9 (`AFFINESCRIPT_STDLIB` env discovery ladder, shipped #433) and 10
(negative integer literals, working today) were audited and confirmed
already-resolved.

Refs: hyperpolymath/standards#239, hyperpolymath/standards#242

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

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 83 issues detected

Severity Count
🔴 Critical 2
🟠 High 13
🟡 Medium 68

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action ons/checkout@v6\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action land/setup-deno@v2\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "missing_timeout_minutes",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 87 issues detected

Severity Count
🔴 Critical 2
🟠 High 16
🟡 Medium 69

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action ons/checkout@v6\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action land/setup-deno@v2\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "missing_timeout_minutes",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 87 issues detected

Severity Count
🔴 Critical 2
🟠 High 16
🟡 Medium 69

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action ons/checkout@v6\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action land/setup-deno@v2\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "missing_timeout_minutes",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

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>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
@hyperpolymath
hyperpolymath disabled auto-merge June 1, 2026 01:41
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 87 issues detected

Severity Count
🔴 Critical 2
🟠 High 16
🟡 Medium 69

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action ons/checkout@v6\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action land/setup-deno@v2\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "missing_timeout_minutes",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 87 issues detected

Severity Count
🔴 Critical 2
🟠 High 16
🟡 Medium 69

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action ons/checkout@v6\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action land/setup-deno@v2\n    needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "missing_timeout_minutes",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "missing_timeout_minutes",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath
hyperpolymath merged commit a4dd22a into main Jun 1, 2026
25 of 27 checks passed
@hyperpolymath
hyperpolymath deleted the claude/step3-stdlib-gap-closures-v2 branch June 1, 2026 01:43
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>
hyperpolymath added a commit that referenced this pull request Jun 1, 2026
…ls + governance allowlist + Pages precheck + Scorecard caller perms (#511)

## Summary

Foundational CI/CD audit of `main` (HEAD `319bc84`). Four red lanes had
four distinct root causes; this PR closes all four + adds a regression
test that catches the most pernicious one before merge.

| Workflow | Status before | Root cause | Fix |
|---|---|---|---|
| `CI / build` | red, every push | `bytesLength` / `math_random` etc.
wired in codegen + fixture but missing `pub extern fn` in
`stdlib/Deno.affine` (PR #504 + #509 partial landings) | 7 decls added;
regression test `test/test_deno_builtins_consistency.ml` enforces subset
across all `stdlib/*.affine` |
| `Governance / Language anti-pattern` | red, every push |
`check-ts-allowlist` scanner's glob⇒regex doesn't anchor against the
`./`-prefixed paths from `walkRecursive(".")` — all 3 CLAUDE.md
exemptions matched zero files in practice | added
`.governance-allowlist` (Layer 2.5) with a leading-wildcard pattern that
works against the prefixed paths; underlying scanner bug deferred to
upstream |
| `GitHub Pages` | red, every push | Pages not enabled on the repo;
`configure-pages@v6 enablement: true` can't escalate to admin via
`GITHUB_TOKEN` | precheck job probes `gh api .../pages` and
short-circuits build/deploy when disabled; emits a clear unblock notice
|
| `Scorecards` | startup_failure since adoption | `permissions:
read-all` at workflow level diverged from the canonical caller block
(`contents: read`); SHA pin was the first cut of the reusable | aligned
to canonical form + bumped reusable SHA to standards/main HEAD |

## Verification

- `dune build bin/main.exe`: clean.
- `dune runtest`: **357/357** tests green (including the new consistency
test).
- `tools/run_codegen_deno_tests.sh`: **all 30** harnesses pass.
- `check-ts-allowlist` locally: ✅ "No TypeScript files outside allowlist
(4 per-repo exemption(s) parsed across CLAUDE.md +
.governance-allowlist)."

## Owner action (one-time, optional, separate)

To unblock the Pages workflow's deploy lane: enable Pages once via
*Settings → Pages* (source: GitHub Actions). The new precheck job's
notice will flip from "Pages not enabled" to "Pages enabled — proceeding
with build + deploy" on the next push.

## What was NOT changed

- Other repos in the estate (owner directive: don't go estate-wide; the
scanner bug is filed-as-comment as belonging upstream at standards).
- `.hypatia-ignore` — governs a different rule.
- `.claude/CLAUDE.md` TypeScript Exemptions table — left as Layer-2
reference; `.governance-allowlist` is the working Layer-2.5 backstop.
- `claude/websocket-binding` branch — left alone (parallel-session WIP).
- `tests/codegen-deno/*.deno.js` regenerated outputs — left at their
pre-existing committed state; the test runner regenerates them on every
run.

## Test plan

- [x] `dune build bin/main.exe` clean
- [x] `dune runtest` 357/357 green
- [x] `tools/run_codegen_deno_tests.sh` all 30 harnesses pass
- [x] check-ts-allowlist clean against local checkout
- [ ] Post-merge: next push run is green on CI / Governance / Scorecards
- [ ] Pages stays guard-skipped until owner enables Pages (then green)

🤖 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