feat: P3 async lowering — foundation + stream<T> e2e (partial #94)#124
Merged
Conversation
…2e (partial #94) Establishes the foundation layer for P3 async lowering: a documented `pulseengine:async` host-intrinsic ABI surface, a structured detection API on `Fuser`, and an end-to-end test covering `stream<u8>` parsing through detection. Lowering pass (rewriting `(canon stream.*)` to `pulseengine:async/*` imports), `future<T>` e2e, async-export callback alignment, and formal error/backpressure conventions are deferred to follow-up sub-issues #120 / #121 / #122 — see ADR-1 for the full breakdown. 73-test `wit_bindgen_runtime` suite stays green; 6 new unit tests + 5 new integration tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
avrabe
added a commit
that referenced
this pull request
Apr 30, 2026
closes #120) (#129) Implements the lowering pass deferred from PR #124 (the v0.5 P3 async foundation). The canonical built-ins `(canon stream.*)` and `(canon future.*)` (14 verbs total) are now rewritten into core-module imports against the documented `pulseengine:async` ABI surface (`HostIntrinsic::import()`). Mapping is one-to-one: canon stream.new → pulseengine:async/stream_new canon stream.read → pulseengine:async/stream_read canon stream.write → pulseengine:async/stream_write canon stream.cancel-read → pulseengine:async/stream_cancel_read canon stream.cancel-write → pulseengine:async/stream_cancel_write canon stream.drop-readable → pulseengine:async/stream_drop_readable canon stream.drop-writable → pulseengine:async/stream_drop_writable (same seven verbs for future) The existing `stream<u8>` fixture in tests/p3_async_lowering.rs gains an end-to-end assertion: after Fuser::fuse(), the fused module's import section contains exactly the imports under module `pulseengine:async` matching `p3_async_summary()`. New fuse-only test covers the symmetric `future<T>` case. ADR-1 updated to mark the lowering pass shipped. 73-test wit_bindgen_runtime suite stays green. Sub-#94. The remaining P3 async follow-ups (error/backpressure conventions #121, async-export callback alignment #122) ship in parallel PRs. Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
This was referenced May 12, 2026
Closed
avrabe
added a commit
that referenced
this pull request
May 13, 2026
First phase of the two-mode P3 async lifting work tracked under #94. This PR lands the host-intrinsic ABI surface a stackful lift needs; the actual trampoline emitter in adapter/fact.rs lands in the follow-up, mirroring the #124 -> #129 split that worked for the data-plane intrinsics. What lands: - 4 new HostIntrinsic variants (ThreadNew, ThreadSwitchTo, ThreadYield, ThreadExit) with pinned signatures and a thread::* name module - uses_stackful_lift() derived helper on P3AsyncFeatures (async lift without callback option => stackful mode per Component Model spec) - Two new tests: stackful_intrinsic_signatures_pinned (4 names + sigs + pulseengine:async module) and stackful_lift_is_async_without_callback (4-case truth table) - ADR-1 addendum documenting the two-mode policy side-by-side - SR-32 flipped planned -> in-progress in safety-requirements.yaml and traceability.yaml updated to point at the new code + tests - CHANGELOG [Unreleased] entry Emitter behavior is unchanged in this PR: a component requesting stackful lift still hits the existing clear error path. Phase 2 wires the trampoline. Refs: #94 (P3 async umbrella), SR-32 (stackful lifting requirement) Milestone: v0.8.0 Co-authored-by: Claude Opus 4.7 <[email protected]>
avrabe
added a commit
that referenced
this pull request
May 20, 2026
…173) * feat(p3): cross-component stream<T> pairing detection (#141, ADR-3) Foundation for the in-module cross-component stream adapter — sub-A of the P3 async umbrella #94. Today meld lowers every component's stream operations to host imports under `pulseengine:async` (ADR-1). When two fused components share a `stream<T>` end-to-end — one holds the writable end, one the readable end — both sides still route every chunk through the host even though both ends now live in the merged module. This PR ships the *detection* half (ADR-3, Path N): everything that can be proven correct with unit tests and no wasm runtime. The adapter *emitter* (ring buffer for same-memory, stream_read→copy→ stream_write chain for cross-memory) is a deliberately separate, runtime-verified follow-up — cross-component stream codegen is data-plane wasm that is only correct once executed on kiln/wasmtime, and landing unverified codegen into the merged module is the H-1/H-3 hazard class meld's Mythos and LS-N gates exist to prevent. The repo shipped P3 lowering in exactly this staged shape (#124 foundation, #129 full pass). What lands: - `safety/adr/ADR-3-cross-component-stream-adapter.md` — design doc. Design paths: N (detection-now/emitter-next, chosen), O (full emitter in one PR, rejected — unverifiable), P (keep host routing, rejected — defeats fusion). Documents the two emitter shapes the follow-up implements and the foundation's precision boundary. - `meld-core/src/p3_stream.rs` — new module, sibling to p3_async.rs. `StreamElement` (element type parsed from the `stream<...>` descriptor), `StreamRole` (Producer/Consumer from StreamWrite/ StreamRead canonical entries), `StreamPair`, `StreamPairGraph`, and a pure `build_stream_pair_graph(components, resolved_imports, mode)`. The pairing logic is a pure function unit-tested without any ParsedComponent construction. - `DependencyGraph` gains a `stream_pair_graph` field, populated by the resolver right after the resource graph (both key off `resolved_imports`). Memory mode follows `MemoryStrategy`. Detection is conservative. A `StreamPair` is a *candidate*, recorded only when two fusion-connected components have complementary roles on a stream of the **same element type**. It does not prove the two endpoints carry the same runtime handle (unknowable at build time). Pairing only on matching element type — never any producer with any consumer — keeps the foundation from manufacturing hallucinated cross-type pairs ("hallucinations are more expensive than silence"). `meld-core/src/p3_stream.rs` added to the Mythos Tier-5 path lists in mythos-gate.yml and mythos-auto.yml, per the documented drift-review process for new fusion-correctness files. Tests: 9 unit tests in p3_stream.rs including the 4 ADR-3 gating fixtures. Full meld-core lib suite 239 → 247 passing. Clippy clean. Refs: #141, #94 (umbrella), ADR-3, SR-33 (detection half). Co-Authored-By: Claude Opus 4.7 <[email protected]> * fix(ci): drop Tier-5 path-list change from this PR claude-code-action self-validates that the workflow invoking it has content identical to the version on `main` — a security measure that stops a PR from altering the workflow to exfiltrate secrets. PR #173 modified `mythos-auto.yml` (adding `p3_stream.rs` to the Tier-5 path list), so the action refused to run with: Action failed with error: Workflow validation failed. The workflow file must exist and have identical content to the version on the repository's default branch. Reverts the `mythos-gate.yml` / `mythos-auto.yml` path-list edits so `mythos-auto.yml` on this branch matches `main` and the auto-runner can actually scan the Tier-5 source this PR touches (`resolver.rs`, `merger.rs`). Registering `p3_stream.rs` in the Tier-5 lists moves to a separate follow-up PR that touches no Tier-5 *source* — its `detect` job sees no Tier-5 source change, sets `any=false`, and the scan (hence the self-validation) never runs. Co-Authored-By: Claude Opus 4.7 <[email protected]> --------- Co-authored-by: Claude Opus 4.7 <[email protected]>
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.
Foundation layer for P3 async lowering (issue #94). Establishes the stable host-intrinsic ABI contract that subsequent lowering work builds against, plus an end-to-end detection test covering
stream<u8>.Closes partial of #94 — the parent stays open until follow-up sub-issues #120 / #121 / #122 land.
Summary
meld_core::p3_asyncmodule — documentedpulseengine:asynchost-intrinsic ABI (14 intrinsics across stream + future),HostIntrinsicenum with one-to-one canonical-built-in → import mapping, and a structuredP3AsyncFeaturesdetection API.Fuser::p3_async_summary()— new public API exposing per-component P3 async usage.meld-core/tests/p3_async_lowering.rsparses a syntheticstream<u8>component (5 canonical built-ins) and asserts detection produces the expectedHostIntrinsicset.safety/adr/ADR-1-p3-async-lowering.mddocuments the decision, scope, and what's deferred.In-scope (this PR)
p3_async_features: Vec<String>; this PR makes it queryable structurally viaHostIntrinsic+P3AsyncFeatures.p3_async.rsplus stableHOST_INTRINSIC_MODULE/ per-verb constants.stream<T>e2e parse + detect.Out of scope (deferred — see ADR-1)
(canon stream.*)topulseengine:async/*imports in fused output.future<T>e2e (P3 async: lowering pass — rewrite (canon stream.*) to pulseengine:async imports (sub-#94) #120) — symmetric companion to stream lowering.Test plan
cargo test -p meld-core— 197 lib + 73 wit_bindgen_runtime + 5 new p3_async_lowering tests = green.cargo clippy -p meld-core --all-targets -- -D warnings— clean.cargo fmt -p meld-core --check— clean (pre-commit hook passed).Fuser::p3_async_summary()returns empty for all 73 existing P2 fixtures (verified viapure_p2_component_has_no_p3_features).Why "foundation"?
Issue #94 is major-version-class scope (5k+ LOC across merger, component_wrap, adapter, resolver). Landing it in one PR would couple unrelated decisions (callback trampoline shape, ring-buffer layout, error encoding) into one review and require cross-repo runtime work in kiln. This PR ships the stable API contract the rest of the work builds on — once merged, the lowering pass and runtime implementation can land independently and in parallel, sharing only the
pulseengine:asyncABI.🤖 Generated with Claude Code