Skip to content

feat(codegen): #234 S4 — retire hardcoded async_primitives (ADR-016 complete) - #278

Merged
hyperpolymath merged 1 commit into
mainfrom
s234-s4-retire
May 19, 2026
Merged

feat(codegen): #234 S4 — retire hardcoded async_primitives (ADR-016 complete)#278
hyperpolymath merged 1 commit into
mainfrom
s234-s4-retire

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

#234 S4 — retire the hardcoded async_primitives (ADR-016 complete)

Final ADR-016 slice: async-boundary detection is now decided purely from the effect side-table; the structural name list is gone.

  • codegen.ml: deleted async_primitives=["http_request_thenable"]. is_async_prim_call e = Effect_sites.is_async_call e. mentions_async_primEffect_sites.exists_call Effect_sites.is_async_call e (effect-driven, same shared traversal as the numbering — can't miss a shape the detector counts). The ADR "table-miss fallback" is the oracle being empty/count-mismatched (⇒ pre-Effect-threaded async-boundary detection for the WasmGC CPS transform (generalise the structural-conservative recogniser) #234 behaviour), not a name list.
  • effect_sites.ml: factored the traversal into shared visit_expr/visit_block/visit_program; fold_calls + new exists_call both use it (single source, no drift). Dead legacy body removed.
  • typecheck.ml — root-cause fix for the cross-module gap S4 exposed: populate_call_effects only scanned the local prog_decls; imported async primitives (http_request_thenable, resolved as a wasm import, not in prog_decls) got EPure → once the structural mask was removed the transform stopped firing for them. Now falls back to the callee's resolved scheme in ctx.name_types (incl. imports), unioning the arrow-spine effect components (declared row ⊆ that; superset is sound for "row ⊇ Async").

Verification

Full tools/run_codegen_wasm_tests.sh green — http_cps_base/capture/chain + http_response_reader (imported http_request_thenable, now via scheme-eff) and effect_async_boundary (user /{Async} fn) all pass with no structural list. dune test --force 290/290. Zero regression.

#234 fully delivered: S1 ADR-016 (#270) · S2a numbering (#275) · S2b table (#276) · S3 codegen switch (#277) · S4 (this).

Closes #234.

🤖 Generated with Claude Code

…DR-016 complete)

Final ADR-016 slice. The async boundary is now decided *purely* from
the effect side-table; the structural name list is gone.

- codegen.ml: deleted `async_primitives = ["http_request_thenable"]`.
  `is_async_prim_call e = Effect_sites.is_async_call e` (no name
  disjunct). `mentions_async_prim` (PR3a single-boundary guard) is now
  `Effect_sites.exists_call Effect_sites.is_async_call e` — effect-
  driven over the SAME shared traversal the numbering uses, so it
  cannot miss a call shape the detector counts. The ADR's "table-miss
  fallback" is the oracle being empty / count-mismatched (⇒ no
  transform = exact pre-#234 behaviour), NOT a name list.
- effect_sites.ml: factored the call traversal into shared
  `visit_expr`/`visit_block`/`visit_program`; `fold_calls` (program)
  and the new `exists_call` (expr) both use it — single source, no
  drift between numbering and sub-expression scans. (Dead legacy body
  removed.)
- typecheck.ml: **root-cause fix for the cross-module gap S4 exposed.**
  `populate_call_effects` only scanned the local unit's `prog_decls`;
  imported async primitives (`http_request_thenable` — declared
  `/{Net,Async}` in stdlib Http, resolved as a wasm import, NOT in
  `prog_decls`) got EPure ⇒ once the structural mask was removed the
  CPS transform stopped firing for them. Now falls back to the
  callee's resolved scheme in `ctx.name_types` (populated by resolve,
  incl. imports), unioning the arrow-spine effect components (declared
  row ⊆ that; superset is sound for "row ⊇ Async").

Verification: full `tools/run_codegen_wasm_tests.sh` green —
http_cps_base/capture/chain + http_response_reader (imported
`http_request_thenable`, now via scheme-eff) AND
effect_async_boundary (user `/{Async}` fn) all pass with NO structural
list. `dune test --force` 290/290. Zero regression.

#234 fully delivered: S1 ADR-016 (#270), S2a numbering (#275), S2b
table (#276), S3 codegen switch (#277), S4 (this).

Closes #234.
@hyperpolymath
hyperpolymath merged commit 46bb174 into main May 19, 2026
12 of 13 checks passed
@hyperpolymath
hyperpolymath deleted the s234-s4-retire branch May 19, 2026 19:49
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 47 issues detected

Severity Count
🔴 Critical 12
🟠 High 21
🟡 Medium 14

⚠️ 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": "Action actions/checkout@v4 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"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath added a commit that referenced this pull request May 24, 2026
## Summary

The effect-threaded async-boundary work (issue #234, ADR-016) shipped
end-to-end on 2026-05-19 via PRs #270 / #275 / #276 / #277 / #278, but
the ledger entries and several in-source comments were still describing
intermediate states (`"S1 done"`, `"Built, not yet consumed"`, `"falls
back to the structural recogniser"`). This PR brings them into agreement
with the realised end state. **No behavioural change** — pure
documentation truthing of work already merged.

### Ledger refresh

- `docs/TECH-DEBT.adoc` — **CORE-02** and **CONV-02** marked `*CLOSED
2026-05-19*` with the full S1..S4 / PR cross-reference and the
steady-state miss path.
- `docs/specs/SETTLED-DECISIONS.adoc` +
`.machine_readable/6a2/META.a2ml` ADR-016 — staging block records
per-slice PR numbers and `DONE` status; the *Fallback / safety*
paragraph rewritten so the steady-state miss path is "no transform" (S4
retired the structural recogniser).
- `docs/ECOSYSTEM.adoc` + `docs/specs/async-on-wasm-cps.adoc` — #234
marked DELIVERED with the PR list, removing the "follow-up, still
tracked" framing.

### In-source comment refresh

- `lib/codegen.ml` — `is_async_prim_call` docstring + the
`bind_consumer` call-site comment rewritten to describe the realised
behaviour (single-sourced from `Effect_sites.is_async_call`; table-miss
= no transform).
- `lib/effect_sites.ml` — async-oracle header no longer claims "falls
back to the structural recogniser".
- `lib/typecheck.ml` — `call_effects` field doc +
`populate_call_effects` comment no longer say "Built, not yet consumed".
- `test/test_main.ml` — Alcotest suite label `"Effect-sites (#234 S2a)"`
→ `"Effect-sites (#234, ADR-016)"`.

### Why zero behaviour risk

Code-side edits touch only `(* … *)` / `(** … *)` comment blocks
(stripped by the OCaml lexer) and one Alcotest suite-label string. No
identifier, no expression, no top-level binding is changed.

## Test plan

- [ ] CI: `dune build` clean
- [ ] CI: `dune test --force` green (gate baseline holds — the S2a
`Effect_sites` test suite + the S3
`tests/codegen/effect_async_boundary.affine` e2e are the in-tree
witnesses of the delivered behaviour)
- [ ] No new lints flagged

> Local `dune test` was not run in this session because the
remote-execution env's network policy blocks the non-GitHub opam hosts
(`erratique.ch`, `gitlab.inria.fr`, `ocaml.janestreet.com`) that
`menhir`, `cmdliner`, `fmt`, `sexplib0`, … fetch from, so the switch
could not be brought up. The actual S1..S4 behaviour was CI-verified at
merge time on each of #270/#275/#276/#277/#278.

https://claude.ai/code/session_01HZ3i2wX5R5rbY8Ycmug4Ao

---
_Generated by [Claude
Code](https://claude.ai/code/session_01HZ3i2wX5R5rbY8Ycmug4Ao)_

Co-authored-by: Claude <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