Skip to content

fix: Mythos v0.4 follow-up — items 4, 5, 6 (closes #112 partially)#117

Merged
avrabe merged 1 commit into
mainfrom
fix/issue-112-mythos-v04-followup
Apr 28, 2026
Merged

fix: Mythos v0.4 follow-up — items 4, 5, 6 (closes #112 partially)#117
avrabe merged 1 commit into
mainfrom
fix/issue-112-mythos-v04-followup

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented Apr 28, 2026

Summary

  • Item 4 (LS-CP-3): graph.adapter_sites was populated by iterating graph.resolved_imports (a HashMap) and never sorted. Fixed by extracting sort_adapter_sites_for_determinism and calling it after the cross- and intra-component promotion passes.
  • Item 5 (LS-R-10 / UCA-R-3): identify_intra_component_adapter_sites was setting import_module = res.import_name, dropping the from_import_module disambiguator and causing merger.rs:1500's disjunctive match to route same-name-different-module imports to the wrong upstream export. Fixed by preserving from_import_module when non-empty.
  • Item 6 (LS-CP-3, second class): three caller_lower_map.iter().next() / lower_map.iter().next() encoding fallbacks picked an arbitrary string_encoding from a HashMap, silently flipping UTF-8/UTF-16 across builds. Fixed by switching to min_by_key(|(k, _)| **k).

Items 1–3 (HT_CAPACITY enforcement, u32 truncation in table_base_addr, silent memory.maximum raise) are deferred — they need adversarial fixtures meld doesn't currently accept and the oracle bar can't be met within the v0.4 follow-up window. Disposition will be posted as a comment on #112.

Closes #112 partially. Links #112.

Oracle pairs

Each fixed item ships the v0.3.0 oracle pattern (Kani harness + PoC test):

  • meld-core::resolver::tests::test_issue112_item4_sort_adapter_sites_is_canonical — asserts sort_adapter_sites_for_determinism is a canonical permutation invariant and idempotent.
  • meld-core::resolver::tests::test_issue112_item5_intra_adapter_preserves_from_import_module — hand-builds a ParsedComponent with two ModuleResolutions sharing import_name = "f" but different from_import_modules, calls identify_intra_component_adapter_sites directly, asserts each promoted site's import_module equals its from_import_module. Verified to fail pre-fix.
  • tests/issue_112_mythos_v04.rs::issue112_item5_intra_component_same_name_different_module — full-pipeline integration test: two-provider component, asserts run() returns 21 (= 1 + 2 * 10) rather than 11 / 22 (the wrong-routing values).
  • tests/issue_112_mythos_v04.rs::issue112_item4_adapter_sites_determinism — fuses the same input five times in fresh Fusers and asserts byte-equal output.
  • Kani harnesses kani_proofs::check_item4_sort_is_canonical_under_swap and check_item5_promotion_preserves_from_import_module model the sort and promotion logic and prove the determinism and field-preservation properties under bounded inputs.

STPA loss scenarios

Two new approved entries in safety/stpa/loss-scenarios.yaml:

  • LS-R-10 (UCA-R-3, hazards H-1 / H-3.1): intra-component adapter promotion drops from_import_module disambiguator.
  • LS-CP-3 (hazard H-7): HashMap iteration leaks into adapter_sites order and caller_encoding fallback.

Both modeled on LS-P-4 / LS-A-8 from commit dc50c28.

Test plan

  • cargo test --package meld-core — full meld-core suite (179 lib tests + 73 wit_bindgen_runtime + integration tests) green
  • cargo test --workspace — all crates green
  • cargo fmt --all --check — clean
  • cargo clippy --package meld-core --all-targets -- -D warnings — clean
  • Pre-commit hooks (cargo-fmt + cargo-clippy + cargo-test) — passed
  • Item 5 unit test verified to fail pre-fix and pass post-fix
  • CI green (waiting on draft PR)
  • Maintainer review

🤖 Generated with Claude Code

@avrabe avrabe marked this pull request as ready for review April 28, 2026 17:48
#112)

Items 4, 5, and 6 from the v0.4 Mythos pre-release pass: three
HashMap-iteration leaks in meld-core/src/resolver.rs that all silently
corrupted fusion output by changing across builds.

1. Item 4 (LS-CP-3): graph.adapter_sites was populated by iterating
   graph.resolved_imports (a HashMap) and never sorted. Rust's default
   hasher randomises per-process, so the push order of cross-component
   sites varied across builds. Downstream:
   * lib.rs:413-414 allocates merged function indices as
     adapter_base + adapter_offset, so a different push order yields
     different merged indices for the same logical adapters.
   * merger.rs:1500 walks adapter_sites and takes the first match for
     an (import_name, import_module) pair, so when two sites share that
     pair the merged module routes calls to whichever was pushed first.
   The 0.3.0 fix sorted reexporter_components / reexporter_resources
   but missed adapter_sites itself.

   Fix: extract sort_adapter_sites_for_determinism, call it after both
   identify_adapter_sites and identify_intra_component_adapter_sites
   complete. Sort key is the totally-ordered tuple
   (from_component, from_module, import_module, import_name,
    to_component, to_module, export_name, export_func_idx).

2. Item 5 (LS-R-10 / UCA-R-3): identify_intra_component_adapter_sites
   set import_module = res.import_name (the field name) when promoting
   a ModuleResolution to an AdapterSite. This dropped the
   from_import_module disambiguator, which ModuleResolution carries
   precisely so the resolver and merger can tell apart same-name
   imports from different modules (e.g. env.alloc vs mylib.alloc, or
   wasi:clocks/wall-clock@0.2.0::now vs
   wasi:clocks/monotonic-clock@0.2.0::now).

   merger.rs:1500's disjunctive match
   (imp.module == site.import_module || imp.name == site.import_module)
   then accepts EITHER core import for EITHER promoted adapter site
   when the disambiguator is wrongly set to the field name, collapsing
   two distinct calls onto whichever site sat first in adapter_sites.

   Fix: use res.from_import_module when non-empty; fall back to
   res.import_name only for legacy synthesised resolutions where
   from_import_module is empty.

3. Item 6 (LS-CP-3, second class): three caller_lower_map.iter().next()
   / lower_map.iter().next() encoding fallbacks selected an arbitrary
   string_encoding (UTF-8 vs UTF-16) when name-based matching missed.
   Same root cause as item 4 — HashMap iteration randomises across
   builds, so the chosen encoding and the string_transcoding flag
   could flip silently from build to build.

   Fix: replace each iter().next() with iter().min_by_key(|(k, _)| **k)
   so the smallest-keyed entry is picked deterministically.

Oracle pairs:

  * Unit test resolver::tests::test_issue112_item5_intra_adapter_preserves_from_import_module:
    constructs a hand-built ParsedComponent with two ModuleResolutions
    sharing import_name = "f" but different from_import_module's
    ("providerA"/"providerB"), populates core_entity_order so
    build_entity_provenance produces the func_source entries needed for
    promotion to fire, calls identify_intra_component_adapter_sites
    directly, asserts each promoted site's import_module equals its
    from_import_module rather than "f". Verified to fail pre-fix.

  * Unit test resolver::tests::test_issue112_item4_sort_adapter_sites_is_canonical:
    asserts sort_adapter_sites_for_determinism is a canonical
    permutation invariant and idempotent over three input orderings.

  * Integration test tests/issue_112_mythos_v04.rs (two tests):
    * issue112_item5_intra_component_same_name_different_module — full
      pipeline with two providers, asserts run() returns 21
      (= 1 + 2*10) rather than 11 or 22 (the wrong-routing values).
    * issue112_item4_adapter_sites_determinism — fuses the same input
      five times in fresh Fuser instances, asserts byte-equal output.

  * Kani harnesses kani_proofs::check_item4_sort_is_canonical_under_swap
    and check_item5_promotion_preserves_from_import_module: model the
    sort and promotion logic abstractly, prove the determinism and
    field-preservation properties under bounded inputs.

LS entries: LS-R-10 (UCA-R-3, intra-adapter import_module) and LS-CP-3
(SR-19 / H-7, HashMap iteration leakage in adapter_sites + encoding
fallbacks) added to safety/stpa/loss-scenarios.yaml, both approved /
high priority.

73-test wit_bindgen_runtime suite stays green; full meld-core test
suite (179 lib tests + integration tests) green.

Closes #112 (items 4, 5, 6). Items 1-3 (HT_CAPACITY enforcement, u32
truncation in table_base_addr, silent memory.maximum raise) deferred —
they need adversarial fixtures meld doesn't currently accept and the
oracle bar can't be met within the v0.4 follow-up window. Disposition
posted as a comment on #112.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@avrabe avrabe force-pushed the fix/issue-112-mythos-v04-followup branch from fc4409f to 010f6a4 Compare April 28, 2026 19:33
@avrabe avrabe merged commit 0cf0f08 into main Apr 28, 2026
5 of 8 checks passed
@avrabe avrabe deleted the fix/issue-112-mythos-v04-followup branch April 28, 2026 20:14
avrabe added a commit that referenced this pull request Apr 29, 2026
V&V-hardening minor release. Closes 5 issues:

- #98 — semver-correct compare_version (PR #113)
- #99 — resource-import fallback name-keyed, sentinel eliminated (PR #115)
- #102 — Kani + proptest harnesses for parser/merger/resolver (PR #116)
- #104 — cargo-fuzz scaffolding with 4 targets (PR #114)
- #112 — Mythos v0.4 follow-up: items 4, 5, 6 confirmed and fixed (PR #117)

New approved STPA loss scenarios: LS-R-10, LS-CP-3.

Pre-release Mythos delta pass (tier-5 + tier-4 changed since v0.3.0):
merger.rs and resolver.rs scanned; **no confirmed findings**.

The cargo-fuzz scaffolding immediately surfaced a real parser panic on
truncated component-section input — tracked as #118 for v0.4.1 / v0.5.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

v0.4 follow-up: Mythos delta-pass unverified suspicions

1 participant