Skip to content

fix(codegen): close #556 — async CPS table-miss loud-fail fence#596

Merged
hyperpolymath merged 1 commit into
mainfrom
fix/556-async-cps-loud-fail
Jun 14, 2026
Merged

fix(codegen): close #556 — async CPS table-miss loud-fail fence#596
hyperpolymath merged 1 commit into
mainfrom
fix/556-async-cps-loud-fail

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

T0 operational-soundness fence (sibling of the just-closed #554). gen_function previously fell through to synchronous gen_expr whenever the ADR-013 async CPS transform did not fire — even for an Async fn whose async-call result is consumed by a continuation. That silently ran the continuation against an unsettled Thenable handle: a wrong runtime value, no diagnostic.

Fix

A precise loud-fail guard in lib/codegen.ml::gen_function: fail with UnsupportedFeature when an Async fn performs an async call consumed by a continuation that cannot be CPS-lowered (thenableThen not importable / unrecognised shape / effect side-table miss), while still lowering the sound shapes:

This mirrors the #555/#566 "fail loud, never silent" fence already in the same file. The narrow guard was deliberate: the broader fn_is_async-only guard would have wrongly rejected the valid tests/codegen/http_thenable_skeleton.affine pass-through (verified — all 7 existing async fixtures still compile).

Tests

New E2E Async Fence (#556) group:

  • async_sync_fallback.affine → loud UnsupportedFeature (negative)
  • async_passthrough_thenable.affine → still compiles (no over-rejection)
  • async_no_boundary.affine → still compiles (no over-rejection)

Full suite 454/454 green.

Closes #556

🤖 Generated with Claude Code

gen_function previously fell through to synchronous gen_expr whenever the
ADR-013 CPS transform did not fire — even for an `Async` fn whose async-call
result is consumed by a continuation. That silently ran the continuation
against an unsettled Thenable handle (a wrong value, no diagnostic).

Add a precise fence: fail loud (UnsupportedFeature) when an `Async` fn performs
an async call consumed by a continuation that cannot be CPS-lowered, while
still lowering the sound shapes — the `let r = <async-call>; <cont>` base case
(transformed), the bare tail-return-Thenable pass-through (#205 convergence
protocol), and an `Async` fn that performs no async call. Mirrors the
#555/#566 "fail loud, never silent" fence in the same file.

Regression tests (test/test_e2e.ml, "E2E Async Fence (#556)"):
- async_sync_fallback.affine        → loud UnsupportedFeature (negative)
- async_passthrough_thenable.affine → still compiles (no over-rejection)
- async_no_boundary.affine          → still compiles (no over-rejection)

Full suite 454/454 green.

Closes #556

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

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 40 issues detected

Severity Count
🔴 Critical 2
🟠 High 22
🟡 Medium 16

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "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": "Issue in scorecard-enforcer.yml",
    "type": "scorecard_publish_with_run_step",
    "file": "scorecard-enforcer.yml",
    "action": "split_scorecard_publish_job",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in instant-sync.yml",
    "type": "secret_action_without_presence_gate",
    "file": "instant-sync.yml",
    "action": "peter-evans/repository-dispatch",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Shell execution -- validate input before passing to shell (1 occurrences, CWE-78)",
    "type": "js_exec_sync",
    "file": "/home/runner/work/affinescript/affinescript/packages/affinescript-cli/mod.js",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  },
  {
    "reason": "Shell execution -- validate input before passing to shell (2 occurrences, CWE-78)",
    "type": "js_exec_sync",
    "file": "/home/runner/work/affinescript/affinescript/packages/affine-vscode/mod.js",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  },
  {
    "reason": "Shell execution -- validate input before passing to shell (1 occurrences, CWE-78)",
    "type": "js_exec_sync",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-vite/src/affine-plugin-improved.js",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  },
  {
    "reason": "expect() in hot path (32 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/affinescript/affinescript/affinescriptiser/src/codegen/wasm_gen.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (29 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/affinescript/affinescript/affinescriptiser/src/codegen/affine_gen.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "unsafe block -- requires SAFETY comment (2 occurrences, CWE-676)",
    "type": "unsafe_block",
    "file": "/home/runner/work/affinescript/affinescript/runtime/src/panic.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "unsafe block -- requires SAFETY comment (1 occurrences, CWE-676)",
    "type": "unsafe_block",
    "file": "/home/runner/work/affinescript/affinescript/runtime/src/alloc.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath merged commit 187f21a into main Jun 14, 2026
27 checks passed
@hyperpolymath hyperpolymath deleted the fix/556-async-cps-loud-fail branch June 14, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant