Context
#841 (PR #842) made async(Http.get/post(...)) with call-free arguments concurrent, and W002 warns when the argument's effect row is outside the commutative whitelist — the semantic case where concurrency is impossible without observable reordering.
The gap CodeRabbit flagged (PR #842 review)
Two natural shapes are effect-eligible but never fuse, silently staying eager with no diagnostic:
async(fetch(url)) where fetch is effects(<Http>) and wraps Http.get — fusion requires a direct Http.get/Http.post call.
async(Http.get(build_url(id))) with a pure build_url — fusion requires call-free request arguments.
Both are per-design in v1 (spec §9.5.4 documents the exact fused shapes, and the MAY-evaluate-concurrently wording means silence promises nothing), and W002's semantic contract is commutativity, not fusion reporting — tests/test_checker_effects.py::test_async_over_http_via_fn_call_no_warning pins that deliberately. But a user writing these shapes plausibly expects concurrency, and an advisory would surface the miss at check time instead of at the profiler.
Proposal
A separate advisory (W003, "async argument is not a fusable shape; evaluates eagerly"), firing only when the argument's effect row intersects {Http} (so async(41 + 1) stays silent) but the shape is not the direct call-free form. Notes:
Refs #841.
Context
#841 (PR #842) made
async(Http.get/post(...))with call-free arguments concurrent, andW002warns when the argument's effect row is outside the commutative whitelist — the semantic case where concurrency is impossible without observable reordering.The gap CodeRabbit flagged (PR #842 review)
Two natural shapes are effect-eligible but never fuse, silently staying eager with no diagnostic:
async(fetch(url))wherefetchiseffects(<Http>)and wrapsHttp.get— fusion requires a directHttp.get/Http.postcall.async(Http.get(build_url(id)))with a purebuild_url— fusion requires call-free request arguments.Both are per-design in v1 (spec §9.5.4 documents the exact fused shapes, and the MAY-evaluate-concurrently wording means silence promises nothing), and
W002's semantic contract is commutativity, not fusion reporting —tests/test_checker_effects.py::test_async_over_http_via_fn_call_no_warningpins that deliberately. But a user writing these shapes plausibly expects concurrency, and an advisory would surface the miss at check time instead of at the profiler.Proposal
A separate advisory (
W003, "async argument is not a fusable shape; evaluates eagerly"), firing only when the argument's effect row intersects{Http}(soasync(41 + 1)stays silent) but the shape is not the direct call-free form. Notes:vera/wasm/async_fusion.pywithout inverting the layer direction (vera/checker→vera/wasm); the shape predicate would need a neutral home (e.g. alongside the AST helpers) consumed by both, preserving the single-source-of-truth invariant from PR feat(async): concurrent async(Http.get/post) on host worker threads — release v0.0.192 #842.Refs #841.