Skip to content

feat(core): explicit DWARF policy with Strip default (#130 phase 1.5)#135

Merged
avrabe merged 3 commits into
mainfrom
chore/dwarf-strip-default
May 11, 2026
Merged

feat(core): explicit DWARF policy with Strip default (#130 phase 1.5)#135
avrabe merged 3 commits into
mainfrom
chore/dwarf-strip-default

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 10, 2026

Summary

Phase 1.5 of issue #130. Today meld passes input .debug_* sections
through verbatim while it rewrites and renumbers function bodies into
the merged code section, so every DWARF address ends up referencing
the wrong instruction. Downstream MC/DC tooling (pulseengine/witness)
trusts what gimli reads and silently produces wrong source-line
attribution for every br_if.

This PR makes the policy explicit and defaults to dropping DWARF
until Phase 2 ships an actual address-remap pass — wrong attribution
is strictly worse than no attribution because witness has a graceful
no-DWARF fallback that the lossy passthrough subverts.

Changes

  • New DwarfHandling::{Strip, PassThrough} enum on FuserConfig,
    default Strip.
  • lib.rs::encode_output filters .debug_* when Strip.
  • Recorded in attestation tool_parameters as
    dwarf_handling = "strip" | "passthrough" so consumers can detect
    lossy emissions; SR-28 sentinel test extended.
  • Three integration tests in meld-core/tests/dwarf_strip.rs pin the
    default-strip / passthrough-preserves / default-is-strip contract.
  • LS-CP-4 added to safety/stpa/loss-scenarios.yaml (approved, H-7).
  • 12 existing call sites that struct-literal-construct FuserConfig
    updated with the new field.

Why draft

Logical follow-up to #131 (Phase 1 discovery, also draft). The whole
witness-mapping epic stays draft until at least Phase 2 (address remap)
lands so the changelog story is one coherent fix instead of a "we
silently turned DWARF off" surprise.

Test plan

  • cargo test -p meld-core — 73 passed (lib + integration)
  • cargo test -p meld-core --test dwarf_strip — 3 passed
  • cargo clippy -p meld-core --all-targets -- -D warnings
  • cargo fmt --all -- --check
  • CI green on smithy

Refs

🤖 Generated with Claude Code

avrabe and others added 3 commits May 10, 2026 14:18
meld passes input `.debug_*` sections through verbatim while it
rewrites and renumbers function bodies into a new merged code section.
Every DWARF address inside those passed-through sections then references
the wrong instruction (or nothing) in the fused output. Downstream MC/DC
tooling (`pulseengine/witness`) trusts the gimli-built `(code-offset ->
file, line)` map and silently produces wrong source-line attribution
for every `br_if`. Wrong attribution is strictly worse than no
attribution because witness has a graceful no-DWARF fallback that the
lossy passthrough subverts.

Phase 2 of issue #130 will add an actual address-remap pass over
`.debug_line` / `.debug_info` / `.debug_ranges`. Until that lands the
only non-corrupting policy is to drop `.debug_*`. Phase 1.5 makes that
choice explicit:

- New `DwarfHandling::{Strip, PassThrough}` enum on `FuserConfig`,
  default `Strip`.
- `lib.rs::encode_output` filters `.debug_*` when `Strip`.
- Recorded in attestation `tool_parameters` as
  `dwarf_handling = "strip" | "passthrough"` so consumers can detect
  lossy emissions; SR-28 sentinel test extended.
- Three integration tests in `meld-core/tests/dwarf_strip.rs` pin the
  default-strip / passthrough-preserves contract.
- LS-CP-4 added to `safety/stpa/loss-scenarios.yaml` (status approved,
  H-7).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@avrabe avrabe marked this pull request as ready for review May 11, 2026 03:54
@avrabe avrabe merged commit c7a2c0b into main May 11, 2026
11 of 17 checks passed
@avrabe avrabe deleted the chore/dwarf-strip-default branch May 11, 2026 03:54
@avrabe avrabe mentioned this pull request May 11, 2026
2 tasks
avrabe added a commit that referenced this pull request May 11, 2026
DWARF Phase 1.5 (#135 / sub-#130): switch the default DWARF policy
from silent passthrough to explicit Strip. Passing input `.debug_*`
sections through verbatim produces wrong source-line attribution
against the merged code section — strictly worse than no DWARF for
downstream MC/DC tooling. `DwarfHandling::PassThrough` remains
available for callers that knowingly accept the lossy mapping.

This is a behaviour-changing default but the change is contained:
non-debug-info input is unaffected, and PassThrough preserves the
prior shape for any callers that need it. LS-CP-4 added.
avrabe added a commit that referenced this pull request May 18, 2026
Phase 1.5 shipped on main in PR #135 (commit c7a2c0b) during the 16
days this branch sat idle. The DWARF default flipped from PassThrough
(broken-but-present) to Strip (correct-but-lossy), and `FuserConfig`
gained a new `dwarf_handling` field.

Three rebase-driven updates:

1. Add the `dwarf_handling` field to both helper builders. The
   PassThrough path is the one Phase 2 (#143) will flip from broken
   to correct, so the existing tests' premise — pin the broken
   behaviour as a Phase-2 oracle — needs the explicit opt-in now
   that Strip is the default.

2. Rename `fuse_default` → `fuse_passthrough` to make its scope
   explicit. The discovery oracle was never about "whatever the
   default does" — it was about pinning passthrough behaviour for
   Phase 2 to flip — and that's clearer post-1.5.

3. Re-purpose the `current_default_is_merge_not_drop` test to
   `current_default_is_strip_post_phase_1_5`. The original was
   written to flag a future default flip; the flip has now
   happened, so the assertion inverts. Future changes (e.g.
   Phase 2 making PassThrough the new default) continue to be
   surfaced by this same test.

4. Update docstrings and inline comments referencing Phase 1.5 as
   "will ship" to "shipped in #135 / PR c7a2c0b".

All 5 discovery tests still pass against the updated helpers, and
the full meld-core lib suite (236/236) is unaffected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
avrabe added a commit that referenced this pull request May 18, 2026
…143) (#131)

* chore: DWARF / witness mapping discovery for fused output (#130)

meld currently passes DWARF custom sections through fusion byte-for-byte.
DWARF addresses encode byte offsets into the per-input code section, but
fusion rewrites function bodies into a new merged code section — so every
preserved DWARF address points at the wrong instruction (or out of
range). The pulseengine `witness` MC/DC tool reads those addresses via
gimli, so coverage attribution for fused modules is currently silently
wrong.

This change:
- Adds `meld-core/tests/dwarf_passthrough.rs` pinning the current
  lossy-but-present behaviour as five green tests so any future
  remapping work has a clear oracle to flip.
- Documents the witness DWARF contract and the cross-repo integration
  shape in the test's module docstring (witness intentionally stays
  out of meld-core's dep graph).

No production code changes — defaults are unchanged. Phased plan
(Phase 1.5 explicit policy, Phase 2 DWARF remap, Phase 3 adapter DIEs)
tracked in #130.

Refs #130

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(dwarf): refresh discovery test for post-Phase-1.5 default

Phase 1.5 shipped on main in PR #135 (commit c7a2c0b) during the 16
days this branch sat idle. The DWARF default flipped from PassThrough
(broken-but-present) to Strip (correct-but-lossy), and `FuserConfig`
gained a new `dwarf_handling` field.

Three rebase-driven updates:

1. Add the `dwarf_handling` field to both helper builders. The
   PassThrough path is the one Phase 2 (#143) will flip from broken
   to correct, so the existing tests' premise — pin the broken
   behaviour as a Phase-2 oracle — needs the explicit opt-in now
   that Strip is the default.

2. Rename `fuse_default` → `fuse_passthrough` to make its scope
   explicit. The discovery oracle was never about "whatever the
   default does" — it was about pinning passthrough behaviour for
   Phase 2 to flip — and that's clearer post-1.5.

3. Re-purpose the `current_default_is_merge_not_drop` test to
   `current_default_is_strip_post_phase_1_5`. The original was
   written to flag a future default flip; the flip has now
   happened, so the assertion inverts. Future changes (e.g.
   Phase 2 making PassThrough the new default) continue to be
   surfaced by this same test.

4. Update docstrings and inline comments referencing Phase 1.5 as
   "will ship" to "shipped in #135 / PR c7a2c0b".

All 5 discovery tests still pass against the updated helpers, and
the full meld-core lib suite (236/236) is unaffected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

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.

1 participant