Skip to content

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

Open
avrabe wants to merge 1 commit into
mainfrom
fix/parser-flags-canonical-abi
Open

fix(parser): canonical ABI for flags<N> (LS-A-20)#157
avrabe wants to merge 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.

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 5680cda to e286b04 Compare May 15, 2026 14:28
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