Skip to content

feat(p3): static resource-lifetime validation for async streams (#142 iv, v0.21.0)#210

Merged
avrabe merged 3 commits into
mainfrom
feat/stream-resource-lifetime
Jun 2, 2026
Merged

feat(p3): static resource-lifetime validation for async streams (#142 iv, v0.21.0)#210
avrabe merged 3 commits into
mainfrom
feat/stream-resource-lifetime

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 30, 2026

Summary

Implements #142 (iv) — resource lifetime across async boundaries, the last open item in the static stream-validation checklist, and closes (ii) as not-applicable with rationale.

meld fuse now rejects a fusion where a component declares a stream<T> / future<T> whose element type is a resource handle:

  • borrow<R> — definite violation. A borrow is valid only within its lending call, but a stream/future is read by the consumer after that call returns across the async boundary → use-after-scope.
  • own<R> — flagged as the drop-while-referenced hazard P3 async — static stream validation at build time (#94 sub-B) #142 names: if the producer drops the handle while the consumer still holds it via the stream, the representation is freed under the consumer.

Surfaced as StreamValidationIssue::ResourceLifetimeError::StreamValidation.

How detection works (and why it's grounded)

Resource handles don't appear literally in the stream descriptor — they hide behind a type reference, so a handle stream parses as stream<Type(N)> where component type index N resolves to a Defined(Own/Borrow). The check parses the Type(N) index out and reuses ParsedComponent::resolve_to_resource — the exact Type(idx) → Own/Borrow chase meld already applies to function params — rather than trusting the Debug text for the handle kind. The wasmparser ComponentValType::Type(N) Debug form is pinned by a regression test (wasmparser_type_debug_form_is_stable), so a wasmparser upgrade that changes it fails loudly instead of silently disabling the check.

Verification

  • LS-R-14 (approved) — gated by ls_r_14_borrow_handle_in_stream_flagged, ls_r_14_own_handle_in_future_flagged_as_owned, and negative test ls_r_14_primitive_element_stream_not_flagged, plus the format pin. run_ls_verification.py: [ OK ] LS-R-14 (3 pass).
  • Full suite green; clippy + fmt clean. resolve_to_resource made pub(crate).

(ii) bounded-channel capacity — not applicable

The Component-Model canonical ABI has no bounded-channel / capacity concept: stream.new (CanonicalEntry::StreamNew { ty }) takes no capacity argument and streams are unbounded by construction. There is nothing in the component binary to validate — "declare a capacity" presupposes an annotation mechanism the ABI does not provide. Documented in p3_stream.rs + LS-R-14. This closes the #142 (i)–(iv) checklist: i/iii shipped in v0.13.0/v0.15.0, iv here, ii N/A.

Limitation (acknowledged)

A handle nested inside a composite element (stream<list<own<R>>>) is not flagged — the same boundary as stream_elements_in_valtype.

p3_stream.rs / parser.rs / resolver.rs are Tier-5, so this PR gets the Mythos delta scan.

🤖 Generated with Claude Code

…iv)

meld fuse now rejects a fusion where a component declares a
stream<T>/future<T> whose element type is a resource handle. A borrow<R>
cannot outlive its lending call across the async boundary
(use-after-scope); an own<R> is the drop-while-referenced hazard #142
(iv) names. New StreamValidationIssue::ResourceLifetime →
Error::StreamValidation.

Detection: resource handles surface in the parsed stream descriptor as
`stream<Type(N)>` (handle hidden behind a Type(idx) ref), so the check
parses the index out and reuses ParsedComponent::resolve_to_resource —
the same Type(idx)→Own/Borrow chase meld applies to function params —
rather than trusting Debug text for the handle kind. The wasmparser
ComponentValType::Type(N) Debug form is pinned by a regression test so a
wasmparser upgrade that changes it fails loudly.

New LS-R-14 (approved) + 3 tests (borrow flagged, own flagged-as-owned,
primitive not flagged) + the format pin. resolve_to_resource made
pub(crate).

#142 (ii) bounded-channel capacity documented NOT APPLICABLE: the
canonical ABI has no capacity concept (stream.new takes none; streams
are unbounded). This closes the #142 (i)-(iv) checklist (i/iii shipped
v0.13/v0.15, iv here, ii N/A).

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

github-actions Bot commented May 30, 2026

Mythos delta-pass required

This PR modifies one or more Tier-5 source files (per
scripts/mythos/rank.md):

meld-core/src/p3_stream.rs
meld-core/src/parser.rs
meld-core/src/resolver.rs

Before merge, run the Mythos discover protocol on the
modified Tier-5 files:

  1. Follow scripts/mythos/discover.md
    — one fresh agent session per touched Tier-5 file.
  2. For each finding, the agent must produce both a Kani
    harness and a failing PoC test (per the protocol's
    "if you cannot produce both, do not report" rule).
  3. Attach a comment on this PR with either the findings
    (formatted per discover.md's output schema) or
    NO FINDINGS.
  4. Add the mythos-pass-done label to this PR.

Why this gate exists: LS-A-10
(CABI alignment padding in async-lift retptr writeback) was
found by the v0.8.0 pre-release Mythos pass — but it had
lived in the callback emitter since #128, across six
releases. A PR-time gate would have caught it at review
time instead of at the release boundary.

The gate check on this PR will pass once the label is
applied.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 30, 2026

LS-N verification gate

⚠️ 37/39 verified — 2 missing regression tests

count
Passed (≥1 test, all green) 37
Failed (≥1 test failure) 0
Missing (no ls_*_NN_* test found) 2

Approved loss-scenarios.yaml entries are expected to have a
regression test named ls_<letter>_<num>_* (e.g. LS-A-11
ls_a_11_*). The gate runs each prefix via cargo test --lib --no-fail-fast and aggregates pass/fail/missing.

Failed LS entries

(none)

Missing regression tests
  • LS-R-13
  • LS-M-6

Updated automatically by tools/post_verification_comment.py.
Source of truth: safety/stpa/loss-scenarios.yaml.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 30, 2026

Mythos delta-pass (auto)

NO FINDINGS across 3 Tier-5 file(s)

File Verdict Hypothesis
`` ✅ NO FINDINGS
meld-core/src/parser.rs ✅ NO FINDINGS
`` ✅ NO FINDINGS

Auto-run via anthropics/claude-code-action@v1
(SHA-pinned) on the touched Tier-5 files, using the
maintainer's Max-plan OAuth token. See
.github/workflows/mythos-auto.yml and
scripts/mythos/discover.md.

@github-actions github-actions Bot added the mythos-pass-done Mythos delta-pass completed on Tier-5 file changes; findings (or NO FINDINGS) attached to PR label May 30, 2026
avrabe added a commit that referenced this pull request Jun 2, 2026
Brings the rivet traceability requirement statuses in line with what has
actually shipped on main. 24 draft + 2 planned (SR-33, SR-35) → implemented;
SR-34 and SR-36 deliberately held at `planned`.

Basis (status `implemented` = code exists and works, full test suite green;
NOT `verified` = per-requirement formal verification, which is a separate pass):
- SR-35 DWARF address remap → shipped v0.16–v0.20 (DwarfHandling::Remap,
  dwarf.rs); in-tree witness oracle passes. NB its stated verification is a
  cross-repo witness smoke that is NOT yet done — hence implemented, not verified.
- SR-33 cross-component stream fusion → v0.9.0 (#141).
- SR-31 multiply-instantiated detection → LS-M-5, ls_m_5_* regression test.
- SR-19 deterministic output → LS-A-15.
- SR-1..SR-25 (parser / canonical-ABI / merger / adapter / wrapping) →
  foundational subsystems shipped across v0.1–v0.20; exercised end-to-end by
  the wasmtime runtime tests (real components fused + executed).

Held at `planned` (honesty — not on main):
- SR-34 static stream validation: (i)/(iii) merged, (iv) is in the unmerged
  PR #210, (ii) bounded-capacity is N/A. Flip to implemented when #210 merges.
- SR-36 synthesised DWARF DIEs for adapters: DWARF Phase 3 (#144), not started.

`rivet validate` error count is unchanged (164 pre-existing schema-drift /
broken-link errors, none introduced by this change).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@avrabe avrabe merged commit 06133d3 into main Jun 2, 2026
19 of 20 checks passed
@avrabe avrabe deleted the feat/stream-resource-lifetime branch June 2, 2026 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mythos-pass-done Mythos delta-pass completed on Tier-5 file changes; findings (or NO FINDINGS) attached to PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant