fix(parser): canonical ABI for flags<N> (LS-A-20)#157
Conversation
|
Mythos delta-pass evidence Tier-5 files touched: The agent that ran The fix touches adapter/fact.rs and component_wrap.rs only to extend pattern-match coverage to the new No adjacent findings from parser.rs scan deferred — this is the only strong one. |
Mythos delta-pass requiredThis PR modifies one or more Tier-5 source files (per Before merge, run the Mythos discover protocol on the
Why this gate exists: LS-A-10 The gate check on this PR will pass once the label is |
e286b04 to
0fee7dd
Compare
parser::convert_wp_defined_type mapped Component-Model flags<N> to
ComponentValType::Record(N × Bool), so downstream canonical-ABI
helpers computed flat=N, size=N bytes, align=1.
Spec for flags<N>:
- flat_count = ceil(N/32) i32 storage words
- size = ceil(N/8) padded to power-of-2 storage class
- align ∈ {1, 2, 4} from the storage class
Concrete impact: flags<17> as a parameter had flat=17 in meld but
flat=1 per spec. Resolver's params-ptr threshold fires at >16, so meld
flipped into params-ptr calling convention while producer kept the
flat path. Smaller N (flags<9>) produced wrong size (9 vs 2) and wrong
alignment.
Bug existed since the Flags arm was added (~2026-03-09), ~2 months
multiple releases. Wasm validator doesn't catch it because the
truncated layout is internally consistent within meld's pipeline.
Fix:
- New ComponentValType::Flags(Vec<String>) variant
- Parser's Flags arm produces it directly
- Explicit Flags arms in flat_count / canonical_abi_align /
canonical_abi_size_unpadded / flat_byte_size /
collect_return_area_type_slots / cabi_size_align /
flat_component_val_type_resolved / resolve_component_val_type
- u32::div_ceil(32) for word count (overflow-safe, Rust 1.73+ stable
API; replaces (n + 31) / 32 which clippy now flags)
Tests (2 new):
- ls_a_20_flags_canonical_abi_matches_spec (N=1/8/9/17/32/33)
- ls_a_20_flags_parser_produces_flags_variant (wat round-trip)
LS-A-20 added to safety/stpa/loss-scenarios.yaml under UCA-P-10 with
approved status. Discovered by the post-v0.8.0 Mythos delta-pass on
parser.rs.
Refs: LS-A-20 (UCA-P-10, H-4, H-4.1)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
0fee7dd to
da6900f
Compare
Cuts v0.8.1 carrying the post-v0.8.0 Mythos delta-pass sweep on the 8 Tier-5 files unscanned at v0.8.0 cut time (per #151 gate scope). Ten loss scenarios closed across 6 fix PRs, all of them silent (no host trap, no validator rejection — wrong-by-construction outputs): - LS-A-11 (#152) — extended-const init/offset truncation in segments and global initializers. Folds (i32.const x)(i32.const y) i32.add instead of dropping operands after the first. - LS-A-12/13/14 (#153) — p3-async detection bugs: mixed-mode stackful mis-classification, stream-write over-count silently classified as Complete, future<stream<...>> mis-routed to stream_types via substring match. - LS-A-15 (#154) — HashMap.iter().find non-determinism at three sites; realloc and resource-rep/-new fallbacks now sort candidate keys. - LS-A-16 (#159) — wrapper dropped source canonical options for lifts; every export silently received the first lift's string encoding. - LS-A-17/18/19 (#156) — resource_graph definer purge and terminal- exporter pass ignored the iface dimension; merger dedup used ends_with(rn) where exact match was required (float / bigfloat suffix collision). - LS-A-20 (#157) — flags<N> canonical ABI silently modeled as Record<N x Bool>; new ComponentValType::Flags variant with explicit arms in every canonical-ABI helper. Also under Added: the Mythos delta-pass CI gate workflow (#151) that made this sweep observable at PR time, and the stackful async-lift cross-memory (ptr, len) return path that v0.8.0 had errored out on. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sixth fix from the post-v0.8.0 Mythos delta-pass sweep. The parser bridge at
convert_wp_defined_typemapped Component-Modelflags<N>toComponentValType::Record(N × Bool), so the downstream canonical-ABI helpers computed wrong flat/size/align values.The bug
flat_count(flags<N>)ceil(N/32)N(one per Bool field)size(flags<N>)ceil(N/8)padded to power-of-2 storage classN(one byte per Bool)align(flags<N>)Concrete impact: a function taking
flags<17>hadflat=17in meld butflat=1per spec. The resolver's params-ptr threshold fires attotal_flat_params > 16, so meld flipped into params-ptr calling convention while the producer kept on the flat path — silent calling-convention mismatch between fused and composed paths.Smaller N (e.g.
flags<9>) produced wrong size (9 vs spec's 2) and wrong alignment, mis-aligning adjacent record fields. The bug shipped since March 2026 (~2 months, multiple releases). Wasm validator did not catch it because the truncated layout is internally consistent within meld's own pipeline.Fix
ComponentValType::Flags(Vec<String>)variant (preserves flag names for diagnostics).Record<N × Bool>.ComponentValType:flat_count,canonical_abi_align,canonical_abi_size_unpadded,flat_byte_size,collect_return_area_type_slots,resolve_component_val_type,cabi_size_align(adapter/fact.rs), andflat_component_val_type_resolved(component_wrap.rs).u32::div_ceil(32)for overflow-safe ceiling division (clippy's modern-API lint).Tests (2 new)
ls_a_20_flags_canonical_abi_matches_spec— exhaustive across N=1/8/9/17/32/33 to exercise every storage-class transition.ls_a_20_flags_parser_produces_flags_variant— wat round-trip asserting the parser emitsComponentValType::Flags(notRecord<Bool>).Tier-5 gate
Touches
parser.rs(Tier-5),adapter/fact.rs(Tier-5),component_wrap.rs(Tier-5).Test plan
cargo test -p meld-core --lib— 210 pass (208 prior + 2 new)cargo clippy --all-targets -- -D warnings— cleancargo fmt --check— cleanRefs
🤖 Generated with Claude Code