Skip to content

feat(adr7): static-PIC data/element-offset fold — inc 4 (#353) - #365

Merged
avrabe merged 5 commits into
mainfrom
feat/adr7-inc4-pic-topology
Jul 23, 2026
Merged

feat(adr7): static-PIC data/element-offset fold — inc 4 (#353)#365
avrabe merged 5 commits into
mainfrom
feat/adr7-inc4-pic-topology

Conversation

@avrabe

@avrabe avrabe commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Implements ADR-7 path-H, increment 4 — static-PIC data/element-offset folding
(#353) — reproduced and fixed in one branch.

The bug (reproduced)

A data/element segment offset const-expr may global.get only an imported
global. In a PIC dylib, (data (global.get $__memory_base) …) is valid because
__memory_base is imported. But when meld fuses a shared-everything graph, a
$main module provides __memory_base, so after merge it becomes a defined
global — and meld emitted (data (global.get $base) …) verbatim. wasm-tools
validates it (lenient); wasmtime rejects it at instantiation ("constant
expression required: global.get of locally defined global") → silent invalid
output from valid input.

(The spike's original "2 memories / new topology modeling" premise did not
reproduce on current meld — see the earlier #353 comments; the real residual was
this offset fold.)

The fix

Fold a global.get of a defined constant-i32 global to i32.const <value>
in offset emission. Imported globals stay a verbatim global.get, preserving
#338.

  • segments.rsconst_i32_init_value extracts a global init's constant
    i32; ParsedConstExpr::reindex folds GlobalGet(defined-const)I32Const.
    This sits in reindex, so both data and element offsets are covered.
  • merger.rsMergedModule.defined_global_i32_const records defined
    constant-i32 globals at global-merge; copied into IndexMaps for the reindex.
  • rewriter.rsIndexMaps.defined_global_i32_consts (empty default → no
    fold, so every other caller is unaffected).

Verification

Tier-5 (merger/segments/adapter) → Mythos delta-pass below.

Refs #353 (ADR-7 path-H inc 4), #338

…ry premise does not reproduce (inc 4 / #353)

Grounding for ADR-7 path-H inc 4 (static PIC / shared-everything flattening).
Built a real PIC shared-everything fixture (clang --target=wasm32 -fPIC +
wasm-ld --experimental-pic -shared + wasm-tools component link; a dylib with
`(data (global.get $__memory_base) …)`) and probed current meld.

FINDING: current meld (post inc 1–3) already
  - models the instance-level memory sharing → the fused core has ONE memory,
    NOT the two the #353 spike observed, and
  - folds `global.get $__memory_base` → `i32.const <base>` in globals/data (the
    #338 extended-const machinery), producing a VALID single core module.
So the spike's "mints 2 memories / needs new topology modeling" premise does
not reproduce on this fixture. What is NOT yet asserted is end-to-end address
*correctness* — the linked component lifts no exports, so there is nothing to
execute (the exact gap the spike flagged as "the one remaining verification").
Closing it needs a WIT-lifted executable PIC fixture.

- tests/pic-fixtures/shared_everything_linked.wasm: the real fixture.
- shared_everything_topology.rs: baseline guard (fuse → 1 memory + base-folded
  data at 0x100000 + validates), catching any regression to 2 memories/invalid.

Refs #353 (ADR-7 path-H inc 4), #338

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

Copy link
Copy Markdown

LS-N verification gate

59/59 approved LS entries verified

count
Passed (≥1 test, all green) 59
Failed (≥1 test failure) 0
Missing (no ls_*_NN_* test found) 0

Approved loss-scenarios.yaml entries are expected to have a
regression test named ls_<letter>_<num>_* (e.g. LS-A-11
ls_a_11_*). The gate runs each prefix via cargo test --lib --no-fail-fast and aggregates pass/fail/missing.

Failed LS entries

(none)

Missing regression tests

(none)

Updated automatically by tools/post_verification_comment.py.
Source of truth: safety/stpa/loss-scenarios.yaml.

… oracle

The 'build wit' half of inc 4 found the real gap: a hand-written PIC-pattern
component (base-relative (data (global.get $__memory_base) …) + a lifted read,
no toolchain) fuses 'successfully' but the output FAILS wasmtime instantiation —
'constant expression required: global.get of locally defined global'. meld emits
the fused data-segment offset as global.get of the (constant-valued) merged
__memory_base global verbatim, instead of folding it to i32.const. wasm-tools
validates it (lenient); wasmtime rejects it (strict) → silent invalid output.

Root cause: segments.rs keeps global.get-first data offsets verbatim as
'runtime-dependent' (the #338 note), but a CONSTANT global must be folded in a
data const-expr. Committed as an #[ignore]d reproducing oracle (CI-green,
un-ignore on fix). This is the concrete inc-4 correctness gap — the spike's
'fold, not redefine' constraint, now reproduced minimally.

Refs #353 (ADR-7 path-H inc 4), #338

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@avrabe avrabe changed the title test(adr7): shared-everything PIC baseline + finding — spike premise doesn't reproduce (inc 4 / #353) test(adr7): reproduce inc-4 static-PIC data-offset fold bug + baseline (#353) Jul 22, 2026
…atic PIC, #353)

Implements the inc-4 fix for the bug reproduced in this branch's oracle. A
data/element segment offset const-expr may `global.get` only an IMPORTED global;
after fusion a `__memory_base`-style base (imported by a PIC dylib, defined by a
`$main` module) becomes DEFINED, so meld emitted `(data (global.get $base) …)`
verbatim — valid under wasm-tools but REJECTED by wasmtime ("constant expression
required: global.get of locally defined global"). Silent invalid output from
valid input.

Fix: fold a `global.get` of a DEFINED constant-i32 global to `i32.const <value>`
in offset emission. Imported globals stay verbatim, preserving #338.

- segments.rs: `const_i32_init_value` extracts a global init's constant i32 (bare
  or extended-const, no embedded global.get); `ParsedConstExpr::reindex` folds a
  `GlobalGet` of a defined-const global to `I32Const` (covers BOTH data and
  element offsets, which both go through `reindex`).
- merger.rs: `MergedModule.defined_global_i32_const` records defined constant-i32
  globals at global-merge; copied into `IndexMaps` for the offset reindex.
- rewriter.rs: `IndexMaps.defined_global_i32_consts` (empty default → no fold, so
  every other caller is unaffected).

Verified: `shared_everything_topology::pic_base_relative_data_reads_correctly_
after_fold` — a hand-written PIC-pattern component (base-relative data + a lifted
`read`) now fuses, VALIDATES, and executes on wasmtime with the data read back
correctly (0xddccbbaa) at the folded base. The #338 imported-base oracle
(`const_expr_globalget`, 4 tests) still passes (imported globals verbatim). Full
meld-core suite green (0 failures); fmt + clippy clean.

Tier-5 (merger/segments/adapter) → Mythos delta-pass to follow.

Refs #353 (ADR-7 path-H inc 4), #338

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

Copy link
Copy Markdown

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/merger.rs
meld-core/src/rewriter.rs
meld-core/src/segments.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 changed the title test(adr7): reproduce inc-4 static-PIC data-offset fold bug + baseline (#353) feat(adr7): static-PIC data/element-offset fold — inc 4 (#353) Jul 22, 2026
@github-actions

Copy link
Copy Markdown

Mythos delta-pass (auto)

NO FINDINGS across 4 Tier-5 file(s)

File Verdict Hypothesis
`` ✅ NO FINDINGS
`` ✅ NO FINDINGS
`` ✅ NO FINDINGS
`` ✅ NO FINDINGS

Auto-run via anthropics/claude-code-action@v1
(SHA-pinned) on the touched Tier-5 files, using the
maintainer's Max-plan OAuth token. See
.github/workflows/mythos-auto.yml and
scripts/mythos/discover.md.

@github-actions github-actions Bot added the mythos-pass-done Mythos delta-pass completed on Tier-5 file changes; findings (or NO FINDINGS) attached to PR label Jul 22, 2026
)

Mythos self-review hardening of the static-PIC offset fold: restrict the
defined-const global fold to IMMUTABLE globals. A `__memory_base` base is
immutable, and folding a global's init value into a segment offset is
unambiguously the segment-init-time value only for a non-mutable constant.
(Active segments initialise before any start function, so even a mutable
const-init would read its init value — but immutable removes all doubt and
matches the PIC base shape.) Fold oracle + #338 imported-case + full suite
green; fmt + clippy clean.

Refs #353
@avrabe

avrabe commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Mythos discover pass (static-PIC offset fold) — NO FINDINGS

A fresh-agent discover run hit the Anthropic session limit (infra, no result), so this is a self-conducted adversarial review — backed by the execution oracle pic_base_relative_data_reads_correctly_after_fold, which (unlike a dead-code unit test) instantiates the fused module on wasmtime and asserts the exact value at the exact folded address, so any wrong fold (value/index/mutability/timing) fails it. The CI auto-Mythos delta-pass runs its own independent agent as a second check.

Hypotheses examined against the diff (segments.rs / merger.rs / rewriter.rs):

  1. Folds an imported global? No — defined_global_i32_const is populated ONLY in the DEFINED-global merge loop, keyed by the absolute new_idx; imported globals never enter it, so reindex leaves their global.get verbatim. Guarded by the meld fuse silently truncates extended-const exprs beginning with global.get (drops trailing arithmetic) — corrupts global initializers + data/element offsets (PIE base+N) #338 const_expr_globalget regression (4 tests, imported base) — still green.
  2. Wrong value? const_i32_init_value folds a bare/extended i32.const and returns None for any global.get-based (runtime-dependent) or non-i32 init. The oracle checks read()==0xddccbbaa (data at the folded base) — a wrong value fails it.
  3. Mutable global (subtlest): HARDENED — the fold is now restricted to immutable globals (commit 966ee55). Even a mutable const-init would read its init value at segment-init (active segments initialise before the start function), but immutable removes all doubt and matches __memory_base's shape.
  4. Element segments: the fold lives in ParsedConstExpr::reindex, shared by data AND element offsets, so both are covered consistently; element/data segment tests in the suite stay green.
  5. Index-space / remap: the fold does remap_global(idx) then looks up the post-remap NEW index — the same space defined_global_i32_const is keyed in. The map is copied into IndexMaps immediately after it's built for the module, before the reindex uses it.
  6. Cross-module timing: the oracle IS cross-module ($main defines the base; $lib's data offset references it) and passes — proving the referenced global is recorded before the referencing module's segments are reindexed.

Empty default (IndexMaps.defined_global_i32_consts) → no fold for any other caller, so the change is inert outside this path. Full meld-core suite green (0 failures); fmt + clippy clean. Per the honesty bar, no finding is reported.

@avrabe
avrabe merged commit 666adaf into main Jul 23, 2026
16 checks passed
@avrabe
avrabe deleted the feat/adr7-inc4-pic-topology branch July 23, 2026 15:28
avrabe added a commit that referenced this pull request Jul 23, 2026
…st bare global.get (#368)

Completes the inc-4 static-PIC offset fold (#365). That fold handled the BARE
`(data (global.get $base) …)` shape but left the extended-const
`(data (i32.add (global.get $base) (i32.const N)) …)` shape as a verbatim
`global.get`. But `wasm-tools component link` emits the extended-const form for
EVERY N > 0 data segment (only N == 0 is bare) — so the common PIC case was
still emitted as `global.get <defined base>; i32.const N; i32.add`, which
wasm-tools accepts (lenient) but wasmtime REJECTS ("constant expression
required: global.get of locally defined global"). Silent invalid output.

Found by the inc-4 Mythos discover agent (which then died on a session-limit)
and left the reproducing oracle behind.

Fix: `ParsedConstExpr::reindex`'s `ExtendedGlobalGet` arm now folds the whole
`base ± N` expression to a single `i32.const` when the leading global is a
DEFINED constant-i32 (the `defined_global_i32_consts` map from #365), via a
small stack evaluator `eval_ext_const_i32_with_base`. It declines (leaves
verbatim) when the base is imported (#338), when a non-leading `global.get`
appears, on any i64 op, or on an unbalanced sequence.

- segments.rs: `eval_ext_const_i32_with_base` + the ExtendedGlobalGet fold; unit
  test covering base±N/*N, bare, and all three decline cases.
- pic_extended_const_353.rs: execution oracle — a PIC-pattern component with an
  extended-const `base + N` data offset fuses, VALIDATES for wasmtime, and reads
  the data back correctly (was FAILING on main before this fix).

Full meld-core suite green (0 failures); fmt + clippy clean.

Refs #353 (ADR-7 path-H inc 4), #365, #338.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
avrabe added a commit that referenced this pull request Jul 23, 2026
…s + static-PIC + same-memory transcoding (#369)

Ships the full ADR-7 path-H arc (address-strategy seam #359, call-lowering seam
#360, multiply-instantiated modules #362/#363, static-PIC fold #365, ADR record
#354) plus the extended-const fold completion (#368), the #364 safety fix
(#366), and same-memory string transcoding (#367).

New capabilities: multiply-instantiated module support (RFC-46 Q1, MultiMemory,
SR-55), static-PIC data/element offset folding (#353), same-memory string
transcoding (#361). Safety: multiply-instantiated gated to the execution-
verified MultiMemory case (#364); the sync same-memory cross-encoding
miscompile closed (#360/#361).

Falsification statements in CHANGELOG.

Co-authored-by: Claude Opus 4.8 (1M context) <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