Skip to content

fix(parser): canonical ABI for flags<N> (LS-A-20)#157

Merged
avrabe merged 1 commit into
mainfrom
fix/parser-flags-canonical-abi
May 16, 2026
Merged

fix(parser): canonical ABI for flags<N> (LS-A-20)#157
avrabe merged 1 commit into
mainfrom
fix/parser-flags-canonical-abi

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 15, 2026

Sixth fix from the post-v0.8.0 Mythos delta-pass sweep. The parser bridge at convert_wp_defined_type mapped Component-Model flags<N> to ComponentValType::Record(N × Bool), so the downstream canonical-ABI helpers computed wrong flat/size/align values.

The bug

Aspect Spec (per Component Model) meld (pre-fix)
flat_count(flags<N>) ceil(N/32) N (one per Bool field)
size(flags<N>) ceil(N/8) padded to power-of-2 storage class N (one byte per Bool)
align(flags<N>) 1 (N≤8) / 2 (N≤16) / 4 (else) 1 (Bool align)

Concrete impact: a function taking flags<17> had flat=17 in meld but flat=1 per spec. The resolver's params-ptr threshold fires at total_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

  • New ComponentValType::Flags(Vec<String>) variant (preserves flag names for diagnostics).
  • Parser's Flags arm produces it directly instead of Record<N × Bool>.
  • Explicit Flags arms added to every canonical-ABI function that walks 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), and flat_component_val_type_resolved (component_wrap.rs).
  • All storage-word counts use 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 emits ComponentValType::Flags (not Record<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 — clean
  • cargo fmt --check — clean
  • YAML lint
  • CI green on smithy
  • mythos-pass-done label

Refs

  • LS-A-20 (UCA-P-10, H-4, H-4.1)
  • Discovered by post-v0.8.0 Mythos delta-pass on parser.rs

🤖 Generated with Claude Code

@avrabe avrabe added the mythos-pass-done Mythos delta-pass completed on Tier-5 file changes; findings (or NO FINDINGS) attached to PR label May 15, 2026
@avrabe
Copy link
Copy Markdown
Contributor Author

avrabe commented May 15, 2026

Mythos delta-pass evidence

Tier-5 files touched: meld-core/src/parser.rs, meld-core/src/adapter/fact.rs, meld-core/src/component_wrap.rs.

The agent that ran discover.md on parser.rs empirically reproduced this finding via a probe test in its session (printed 9-bit flags: flat=9 size=9 align=1 vs spec flat=1 size=2 align=2). The PoC in this PR (the new ls_a_20_* tests) is a direct lift of that probe shape, exhaustively covering all storage-class transitions.

The fix touches adapter/fact.rs and component_wrap.rs only to extend pattern-match coverage to the new Flags variant — these are pattern-completeness changes, not semantic changes, and were caught by the compiler when the new variant was added. The adapter/wrap arms produce the spec-correct layout for any downstream emission that walks ComponentValType.

No adjacent findings from parser.rs scan deferred — this is the only strong one.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 2026

Mythos delta-pass required

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

meld-core/src/adapter/fact.rs
meld-core/src/component_wrap.rs
meld-core/src/parser.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.

@avrabe avrabe force-pushed the fix/parser-flags-canonical-abi branch 2 times, most recently from e286b04 to 0fee7dd Compare May 16, 2026 04:38
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>
@avrabe avrabe force-pushed the fix/parser-flags-canonical-abi branch from 0fee7dd to da6900f Compare May 16, 2026 07:58
@avrabe avrabe merged commit b313dda into main May 16, 2026
10 checks passed
@avrabe avrabe deleted the fix/parser-flags-canonical-abi branch May 16, 2026 09:37
@avrabe avrabe mentioned this pull request May 16, 2026
3 tasks
avrabe added a commit that referenced this pull request May 16, 2026
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>
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