Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: P3 async lowering pass — canon stream/future → pulseengine:async (closes #120)#129

Merged
avrabe merged 1 commit into
mainfrom
feat/issue-120-p3-async-lowering
Apr 30, 2026
Merged

feat: P3 async lowering pass — canon stream/future → pulseengine:async (closes #120)#129
avrabe merged 1 commit into
mainfrom
feat/issue-120-p3-async-lowering

Conversation

@avrabe

@avrabe avrabe commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the P3 async lowering pass — the actual rewrite from canonical built-ins ((canon stream.*), (canon future.*)) to core-module imports against the pulseengine:async ABI shipped in v0.5.0.

The mapping is one-to-one (per HostIntrinsic::import() from meld_core::p3_async):

Canonical built-in Lowered import
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) pulseengine:async/future_*

Test plan

  • 73-test wit_bindgen_runtime suite green (no regressions)
  • Existing stream<u8> fixture: import-section matches p3_async_summary()
  • New fuse-only test for future<T> symmetric case
  • CI green

What's left

ADR-1 updated to mark this lowering pass shipped. The remaining P3 async items (#121 error/backpressure conventions, #122 async-export callback alignment) are filed as separate PRs.

Closes #120 (sub-#94).

closes #120)

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]>
@avrabe avrabe marked this pull request as ready for review April 29, 2026 21:55
@avrabe avrabe merged commit c52eb1b into main Apr 30, 2026
9 checks passed
@avrabe avrabe deleted the feat/issue-120-p3-async-lowering branch April 30, 2026 03:50
@avrabe avrabe mentioned this pull request May 1, 2026
5 tasks
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]>
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.

P3 async: lowering pass — rewrite (canon stream.*) to pulseengine:async imports (sub-#94)

1 participant