fix(stdlib): wire env_at / arg_at surface — codegen lowers via gen_str_at_via_get (ADR-015 S5, #180)#364
Merged
Merged
Conversation
…r_at_via_get (ADR-015 S5, #180) The codegen-test fixtures tests/codegen/{env_at,arg_at,env_count_and_at}.affine all reference env_at / arg_at, but those surface names were never wired in resolve.ml or typecheck.ml — `dune runtest` hits Resolve.UndefinedVariable before codegen even fires. Latent baseline-rot since commit 58f08b9 (ADR-015 S5) added the wasm IR + helper without completing the surface. Same shape of fix as #362 (string_length), but a full layer-by-layer wiring because env_at/arg_at need TWO WASI imports each. ## Changes * lib/resolve.ml: add `def "env_at"; def "arg_at"`. * lib/typecheck.ml: bind both as `Int -> String / Time`, matching the effect row of their count siblings (env_count / arg_count). * lib/codegen.ml: new ExprApp dispatch right after the env_count/arg_count handler — allocates 8 locals (n, scratch, count, bufsize, ptrvec, src, dst, result), looks up the matching sizes_get + get WASI func indices, and calls Wasi_runtime.gen_str_at_via_get (already present, was just unreferenced). * lib/codegen.ml: extend the optional_wasi table with four new rows — ("env_at", "environ_sizes_get"), ("env_at", "environ_get"), ("arg_at", "args_sizes_get"), ("arg_at", "args_get"). Each row's factory is the existing create_*_import in wasi_runtime.ml. * lib/codegen.ml: add a dedup pass over optional_wasi keyed by WASI import name (keep first occurrence). Necessary because env_count + env_at both want environ_sizes_get; without dedup the wasm would carry two imports under the same name and instantiation would fail. The env_count_and_at.affine fixture is the regression test for this case — its docstring already documented the requirement. ## What this does NOT cover * Interp.eval_program does not gain env_at / arg_at. Same posture as env_count / arg_count (also absent from interp). These are WASI-only surfaces; interp would need a synthetic environ table to simulate them. Out of scope. Closes-Refs ADR-015 S5 surface completion; Refs #180 (parent epic), Refs #339 (the IR-only commit), Refs #361 (originating queue-clearance incident — this is the 4th baseline-rot iteration after #361 / #362 / the .hypatia-ignore-format fix). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 108 issues detected
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": "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": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"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 |
…binding The interp binding for string_length landed in #362 (already on main), but the wasm-backend codegen still does not know it — `codegen.ml`'s `ExprApp` dispatch fell through to the "Function or variable not found" error path. The codegen-test fixtures env_at.affine / arg_at.affine / env_count_and_at.affine all call `string_length(env_at(0))` etc., so the dune-runtest codegen-fixture loop fails at code-generation time even after the resolver / typechecker (#332) and interp (#362) layers were wired. AS string layout is `[len: i32][bytes...]` at the pointer the arg evaluates to — reading the length is one `i32.load` at offset 0. Same shape as the existing tuple-index / record-field load patterns. Three lines of effective code in the handler. Closes the gap for ADR-015 S5 (env_at/arg_at) too: their codegen emits a length-prefixed AS string, and the fixture tests then need string_length to read that length back. Both pieces (env_at/arg_at wiring + string_length codegen lowering) are required for the fixtures to compile end-to-end. Refs #332 (STDLIB-04e originating ticket), Refs #361 (queue-clearance incident), follow-on to #362 (interp side) and #364's env_at/arg_at wiring earlier in this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 108 issues detected
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": "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": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"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 |
`dune build @fmt` rejects the one-line forms my #361 commit landed on main — dune's formatter wants `(modules ...)` with each module on its own line, and `(action ...)` with the body on its own line. This is a follow-up to PR #361 (already merged); the @fmt check has been failing on every build since #361 because of that one-liner. The `dune runtest` / `just bench` semantics are unchanged. Combined with the env_at/arg_at wiring and string_length codegen lowering earlier in this PR, this should clear the build red on the 4-PR queue (#357-#360) and on this branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 108 issues detected
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": "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": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"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 |
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
4th baseline-rot iteration after #361 / #362 / the
.hypatia-ignoreformat fix. The codegen-test fixturestests/codegen/{env_at,arg_at,env_count_and_at}.affineall referenceenv_at/arg_at, but those surface names were never wired inresolve.mlortypecheck.ml—dune runtesthitsResolve.UndefinedVariablebefore codegen even fires.The wasm IR + helper was added in commit
58f08b9(ADR-015 S5) but the surface plumbing was left out. This PR completes the surface.What's wired
lib/resolve.mldef "env_at"; def "arg_at"lib/typecheck.mlInt -> String / Timefor both (matches the effect row ofenv_count/arg_count)lib/codegen.mlExprApphandler right afterenv_count/arg_count. Allocates 8 fresh locals (n / scratch / count / bufsize / ptrvec / src / dst / result), looks up matching sizes_get + get WASI func indices, callsWasi_runtime.gen_str_at_via_get(already present, just unreferenced).lib/codegen.mloptional_wasitable("env_at", "environ_sizes_get"),("env_at", "environ_get"),("arg_at", "args_sizes_get"),("arg_at", "args_get").lib/codegen.mloptional_wasitableenv_count + env_atboth wantenviron_sizes_get; without dedup the wasm carries two imports under the same name and instantiation fails.Regression coverage
tests/codegen/env_count_and_at.affineis the dedup regression — its docstring already documented the invariant. Thedune runtestinvocation in CI compiles all three fixtures end-to-end.What this does NOT cover
Interp.eval_programdoes not gainenv_at/arg_at. Same posture asenv_count/arg_count(also absent from interp). These are WASI-only surfaces; interp would need a synthetic environ table to simulate them. Out of scope for the baseline-rot fix.How this was found
#361'sbuildjob remained red after the bench/dune +.hypatia-ignore+string_lengthfixes cleared the other reds. The failure wasResolution error: UndefinedVariable arg_atattests/codegen/arg_at.affine:7. Same root-cause class asstring_length(#362): a stdlib surface declared in test fixtures but never wired in resolve+typecheck.Test plan
dune buildsucceeds (no OCaml compile error from the codegen dispatch or dedup pass).dune runtestclears the codegen-test compile loop (env_at, arg_at, env_count_and_at all produce valid wasm).string_lengthdoes — make sure the existing fix(interp): wire missing string_length builtin (Refs #332, #329) #362 wiring still works).Refs #180 (ADR-015 parent), Refs #339 (the IR-only commit), Closes-Refs #361 (originating queue-clearance incident).
🤖 Generated with Claude Code