Skip to content

feat(effect-sites): #234 S2a — shared call-site numbering (ADR-016)#275

Merged
hyperpolymath merged 1 commit into
mainfrom
s234-effect-sites
May 19, 2026
Merged

feat(effect-sites): #234 S2a — shared call-site numbering (ADR-016)#275
hyperpolymath merged 1 commit into
mainfrom
s234-effect-sites

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

#234 S2a — shared call-site numbering (ADR-016 foundation)

ADR-016's keying mechanism. ExprApp has no loc/id and ADR-016 rejects annotating the AST, so the effect side-table is keyed by a deterministic shared call-site numbering: lib/effect_sites.ml — a single, total, pure pre-order traversal assigning every ExprApp a 0-based ordinal. Typecheck (producer) and the WasmGC CPS detector (consumer) will both call this function on the same prog, so keys cannot drift — no AST shape change.

This slice is the keying primitive only. No typecheck/codegen change → pure, gate-neutral. (S2b: typecheck builds the table on top; S3: pipeline thread + codegen switch + user-Async e2e; S4: retire the hardcoded set.)

  • API: fold_calls / count / to_list / iter.
  • Ordering contract (documented; stable; do-not-change-without-amending-ADR-016): strict left-to-right pre-order, call node numbered before its callee/arg sub-exprs. Exhaustive over every expr/stmt/block/match/handler/unsafe/fn-body/top-level position.
  • test/test_effect_sites.ml: 5 cases — count, contiguous pre-order ordinals, determinism+purity (across runs & re-parses), zero-calls, calls nested in arg/while/for/match/lambda/block positions.

dune test --force 287/287. Zero regression.

Refs #234. Not Closes — staged campaign; owner closes per ISSUE-CLOSURE.

🤖 Generated with Claude Code

ADR-016 mechanism foundation. The AST has no loc/id on `ExprApp` and
the ADR rejects annotating it, so the effect side-table is keyed by a
*deterministic shared call-site numbering*: `lib/effect_sites.ml` is a
single, total, pure pre-order traversal that assigns every `ExprApp` a
0-based ordinal. Typecheck (producer) and the WasmGC CPS detector
(consumer) will both obtain ordinals by calling THIS function on the
same `prog`, so keys cannot drift — with no AST shape change.

This slice is `effect_sites.ml` ONLY (the keying primitive). No
typecheck/codegen change ⇒ pure, gate-neutral. S2b adds the typecheck
table on top; S3 threads + switches codegen; S4 retires the hardcoded
set (per ADR-016 staging).

API: `fold_calls` / `count` / `to_list` / `iter`. Ordering contract
(documented, stable, do-not-change-without-amending-ADR-016):
strict left-to-right pre-order; a call node is numbered before its
callee/argument sub-exprs are descended. Exhaustive over every
expr/stmt/block/match/handler/unsafe/fn-body/top-level position
(TopFn/Const/Impl/Trait-default bodies).

Tests: `test/test_effect_sites.ml` (5 cases — count, contiguous
pre-order ordinals, determinism+purity across runs/re-parses, zero
calls, calls nested in arg/while/for/match/lambda/block positions).
Registered in test_main. `dune test --force` 287/287. Zero regression.

Refs #234. Not Closes — staged campaign; owner closes per ISSUE-CLOSURE.
@hyperpolymath hyperpolymath merged commit f3c765a into main May 19, 2026
12 of 13 checks passed
@hyperpolymath hyperpolymath deleted the s234-effect-sites branch May 19, 2026 19:07
@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 19, 2026
…DR-016 complete) (#278)

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