Skip to content

docs(adr): ADR-7 — ABI & linking-strategy architecture (canonical mix-and-match vs symmetric/PIC fast lane) - #354

Merged
avrabe merged 6 commits into
mainfrom
docs/adr7-abi-linking-strategy
Jul 17, 2026
Merged

docs(adr): ADR-7 — ABI & linking-strategy architecture (canonical mix-and-match vs symmetric/PIC fast lane)#354
avrabe merged 6 commits into
mainfrom
docs/adr7-abi-linking-strategy

Conversation

@avrabe

@avrabe avrabe commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What

ADR-7 (open design question): how should meld support the shared-address-space
fast lane (PIC #353 + Christof's symmetric ABI) without sacrificing RFC-46
canonical mix-and-match
? Drafted per the "be careful / stay true / think if we
need a rework to split" steer.

Not a code change — a decision artifact for review (@cpetig too). Status open;
humans promote.

The core argument

Paths

G bolt-on (rejected) · H clean strategy-split (recommended) · I separate tool
(rejected) · J do-nothing/canonical-only (baseline).

Does not block

#352 (canonical --emit-relocs backstop) ships regardless — it serves the
mix-and-match path today.

Refs #353, RFC-46, ADR-4, ADR-6.

@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.

avrabe added a commit that referenced this pull request Jul 16, 2026
…erified stack

Human decision (2026-07-16): status open → resolved.
- Identity: balanced/dual — meld is BOTH the RFC-46 canonical reference AND the
  sealed-safety (symmetric+PIC) product; both first-class.
- Ownership: own + formally verify the FULL lowering stack (canonical FACT +
  symmetric + PIC), no external lowering dependency — a safety tool must own a
  frozen verifiable trusted base (overrides the review's track-upstream default).
- Reconciliation: own the IMPLEMENTATION; ABIs/conventions stay open standards
  (symmetric→BA, PIC→tool-conventions); path-H canonical fallback keeps
  mix-and-match, so this is not fragmentation.
- Accepted risks named (scope/budget, parity treadmill, proof surface); the
  heterogeneous-composition theorem is now mandatory.
- Next increments: extract address strategy; formalize call-lowering seam;
  RFC-46 Q1 multiply-instantiated; #353 Path-A PIC flatten.

Refs #353, #354, RFC-46

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
avrabe and others added 4 commits July 16, 2026 23:46
…uestion)

Frames how meld should support the shared-address-space fast lane (PIC #353 +
symmetric ABI) WITHOUT sacrificing RFC-46 canonical mix-and-match. Recommends
path-H: an ABI-agnostic verified core + pluggable per-boundary call-lowering
(canonical-FACT default / symmetric-direct opt-in, canonical as universal
fallback) + pluggable address strategy (multi / shared-rebase / static-base-PIC).
Grounds the 'split not rewrite' verdict in current coupling (adapter already
separable; reloc interleaved) and ties in the RFC-46 multiply-instantiated-
modules gap. Status: open — for human decision.

Refs #353, RFC-46

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

Adds the decision-independent consensus from a 10-persona strategic review as
requirements on ADR-7 (status stays open):
- give away the ABIs, keep the proofs/attestation (the moat is verification)
- silent downgrade = hard error (per-boundary strategy declared/attested/observable)
- symmetric ABI must be standardized (BA/wit-bindgen) before a safety product;
  gated experimental/non-portable until then
- concrete shape = one binary, two attested profiles (open/ecosystem + sealed-safety)
- new heterogeneous-composition theorem as the key proof obligation
- frames the one open decision: meld's identity + the load-bearing
  track-upstream-FACT-vs-own-the-fork sub-choice

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
meshless_* fixtures are outdated; the live symmetric path is
crates/cpp/tests/symmetric.rs symmetric_integration() running the standard
tests/runtime* suite under symmetric=true + -shared. Producer contract noted.

Refs #353
…erified stack

Human decision (2026-07-16): status open → resolved.
- Identity: balanced/dual — meld is BOTH the RFC-46 canonical reference AND the
  sealed-safety (symmetric+PIC) product; both first-class.
- Ownership: own + formally verify the FULL lowering stack (canonical FACT +
  symmetric + PIC), no external lowering dependency — a safety tool must own a
  frozen verifiable trusted base (overrides the review's track-upstream default).
- Reconciliation: own the IMPLEMENTATION; ABIs/conventions stay open standards
  (symmetric→BA, PIC→tool-conventions); path-H canonical fallback keeps
  mix-and-match, so this is not fragmentation.
- Accepted risks named (scope/budget, parity treadmill, proof surface); the
  heterogeneous-composition theorem is now mandatory.
- Next increments: extract address strategy; formalize call-lowering seam;
  RFC-46 Q1 multiply-instantiated; #353 Path-A PIC flatten.

Refs #353, #354, RFC-46

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
avrabe added a commit that referenced this pull request Jul 17, 2026
…th-H inc 1) (#359)

* refactor(adr7): extract the address strategy seam from the merger (path-H inc 1)

Executes ADR-7 path-H, increment 1: extract the per-module address/memory
strategy resolution out of Merger::merge into a dedicated address_strategy
module, behavior-preservingly. This is the pluggable seam the decided
architecture hangs off — the shared-rebase strategy lives here now; multi-memory
resolves to an empty plan; static-base PIC (#353) and the per-boundary
call-lowering seam come in later increments.

- address_strategy.rs: AddressPlan + resolve_address_plan — the full decision +
  validation (path-F MissingRelocMetadata, memory64 reject, #351 MisalignedReloc
  backstop). has_direct_memory_access passed as a closure to keep the original
  lazy short-circuit exactly.
- merger.rs: the ~50-line reloc-consumption block replaced with one call.
- 4 unit tests (rebasing-off/base-0/no-reloc-direct-fail/bulk-only + laziness).

No behavior change: canonical gating fixtures (test_326_reloc_const_rebasing,
test_address_rebasing) + drop_realloc + full meld-core suite all green;
fmt/clippy clean.

Refs #354 (ADR-7)

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

* docs(adr7): clarify address-plan scope — empty plan is not fusion disabled

A colleague reading #359 read "multi-memory resolves to an empty plan"
as "multi-memory + FACT fusion is stopped". It is not: an AddressPlan
carries only which reloc sites to shift for a shared-memory base. An
empty plan means no address rebasing is needed (multi-memory keeps each
component's memory at its own base) — it does not touch cross-component
adapter (FACT) generation, which runs identically. Spell that out in the
module doc so the seam can't be misread.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@avrabe
avrabe merged commit fa8744f into main Jul 17, 2026
8 checks passed
@avrabe
avrabe deleted the docs/adr7-abi-linking-strategy branch July 17, 2026 12:09
avrabe added a commit that referenced this pull request Jul 21, 2026
…C-46 Q1, inc 3)

Completes RFC-46 Q1 "duplicate": meld now SUPPORTS a component that
instantiates the same core module more than once, instead of rejecting it.

The `core_instance_topology` normalization pass is wired into
`Fuser::fuse_with_stats` before resolve/merge. It gives each instantiation a
distinct module identity, so the merger's per-module machinery (proven correct
for N distinct modules) allocates each instance independent functions / memory /
tables / globals — no shared mutable state (STPA H-1), no (component, module)-
keyed map overwrites. After the pass no module is instantiated more than once,
so the DuplicateModuleInstantiation reject becomes an unreachable backstop
(retained; its ls_m_5 unit test still passes). The pass is a no-op for
single-instantiation components and idempotent for a repeated fuse.

Differential EXECUTION oracle (the gate for flipping this safety behavior):
tests/multiply_instantiated_runtime.rs — a component instantiating one core
module (a mutable counter) TWICE is fused (MultiMemory, CoreModule), VALIDATED,
and executed on wasmtime. The two instances' counters advance independently
(inc→1,2; inc$0→1; inc→3; inc$0→2); a shared-state H-1 corruption would fail the
load-bearing `inc$0` first-call == 1 assertion.

- lib.rs: wire the normalization pass (with an info log of how many modules
  were duplicated).
- multiply_instantiated_runtime.rs: the differential execution oracle.
- safety-requirements.yaml: SR-55 draft→implemented (mechanism + wiring +
  oracle green locally; verified pending CI/merge); SR-31 noted as superseded
  for handleable cases, reject retained as backstop.

Full meld-core suite green (0 failures, no regression); fmt + clippy clean;
rivet validate PASS.

Refs #354 (ADR-7 path-H inc 3), RFC-46 Q1

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
avrabe added a commit that referenced this pull request Jul 21, 2026
…inc 3) (#362)

* feat(adr7): core-instance topology normalization — RFC-46 Q1 mechanism (path-H inc 3, slice 1)

RFC-46 Q1 (multiply-instantiated modules) "duplicate" resolution: meld
currently REJECTS a component that instantiates the same core module more
than once (SR-31, DuplicateModuleInstantiation). This lands the MECHANISM to
support it instead — as a bounded, structurally-verified first slice.

`core_instance_topology::expand_multiply_instantiated_modules` deep-clones a
module per 2nd..Nth instantiation and rewrites that instantiation to the
clone, so after the pass no module is instantiated more than once. Each
instance then gets its OWN functions/memory/tables/globals via the merger's
per-module machinery (already proven correct for N distinct modules) — no
shared mutable state (STPA H-1), and every (component, module)-keyed merge
map gets a distinct key per instance (no silent overwrite). The whole class
of duplication-corruption bugs is dissolved by reusing the existing proof.

Deliberately NOT wired: activating this (dropping the reject) flips a
verified safety requirement and must be gated on a differential EXECUTION
oracle proving two instances keep independent mutable state end-to-end
(identical-content module duplication can stress export-name / segment
handling a structural test can't see). Until that oracle + a Tier-5 Mythos
pass on the wiring land, meld still rejects multiply-instantiated modules;
this module is exercised only by its own 6 structural unit tests.

- core_instance_topology.rs: the pass + 6 unit tests (single/distinct
  unchanged; double/triple/interleaved → N distinct module identities;
  FromExports ignored).
- lib.rs: register the module.
- safety-requirements.yaml: SR-55 (draft) — the duplicate-support capability,
  refines SR-31, mitigates LS-M-5; verification-description records the
  execution-oracle gate. rivet validate PASS.

Full meld-core lib suite green (487, unaffected — pass is unwired); fmt +
clippy clean.

Refs #354 (ADR-7 path-H inc 3), RFC-46 Q1

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

* feat(adr7): wire multiply-instantiated support + execution oracle (RFC-46 Q1, inc 3)

Completes RFC-46 Q1 "duplicate": meld now SUPPORTS a component that
instantiates the same core module more than once, instead of rejecting it.

The `core_instance_topology` normalization pass is wired into
`Fuser::fuse_with_stats` before resolve/merge. It gives each instantiation a
distinct module identity, so the merger's per-module machinery (proven correct
for N distinct modules) allocates each instance independent functions / memory /
tables / globals — no shared mutable state (STPA H-1), no (component, module)-
keyed map overwrites. After the pass no module is instantiated more than once,
so the DuplicateModuleInstantiation reject becomes an unreachable backstop
(retained; its ls_m_5 unit test still passes). The pass is a no-op for
single-instantiation components and idempotent for a repeated fuse.

Differential EXECUTION oracle (the gate for flipping this safety behavior):
tests/multiply_instantiated_runtime.rs — a component instantiating one core
module (a mutable counter) TWICE is fused (MultiMemory, CoreModule), VALIDATED,
and executed on wasmtime. The two instances' counters advance independently
(inc→1,2; inc$0→1; inc→3; inc$0→2); a shared-state H-1 corruption would fail the
load-bearing `inc$0` first-call == 1 assertion.

- lib.rs: wire the normalization pass (with an info log of how many modules
  were duplicated).
- multiply_instantiated_runtime.rs: the differential execution oracle.
- safety-requirements.yaml: SR-55 draft→implemented (mechanism + wiring +
  oracle green locally; verified pending CI/merge); SR-31 noted as superseded
  for handleable cases, reject retained as backstop.

Full meld-core suite green (0 failures, no regression); fmt + clippy clean;
rivet validate PASS.

Refs #354 (ADR-7 path-H inc 3), RFC-46 Q1

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
avrabe added a commit that referenced this pull request Jul 21, 2026
… verified (#363)

Strengthens the RFC-46 Q1 (multiply-instantiated modules) verification: the
merged inc-3 oracle proved only GLOBAL-state independence. This adds the other
critical mutable-state axis — independent LINEAR MEMORY and DATA SEGMENTS.

`two_instances_keep_independent_memory_and_data_segments`: a core module keeps
its counter in linear memory, seeded to 5 by a DATA segment, instantiated twice.
Fused + validated + executed on wasmtime: bump→6,7; bump$0→6 (its own
data-seeded 5, independent); bump→8; bump$0→7. A shared memory / mis-based
segment (the segment-duplication risk an index-space audit flagged) would make
bump$0's first call observe the other instance's writes.

With globals + memory + data-segments all execution-proven, the H-1 hazard is
comprehensively covered → SR-55 status implemented→verified. One axis remains
un-execution-tested and is noted in SR-55: per-instance IMPORT wiring (distinct
args per instance); the fixtures are import-free. Not a mutable-state hazard.

Test + requirement only (no src change). Both oracles green; fmt clean; rivet
validate PASS.

Refs #362, #354 (ADR-7 path-H inc 3), RFC-46 Q1

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant