feat(aarch64): RQ-64-ARM64LINUX — the arm64-Linux host-library claim, linked by ld.lld and EXECUTED (natively, qemu-user, unicorn) vs wasmtime - #1179
Merged
Conversation
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…landed: (R10 attribution) The status_evidence R10 rule demands the artifact acknowledge the PR that delivered it; the number did not exist until the PR was opened. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
… linked by ld.lld and EXECUTED (natively, qemu-user, unicorn) vs wasmtime `synth compile -b aarch64 --relocatable` has emitted a SysV ELF64 ET_REL that links into an arm64-Linux program since v0.51 — true by accident: no document claimed it, no oracle handed it to a host linker for that target, nothing executed the result. This lane makes it a claim backed by execution, and records the one thing the link found that does NOT work. The oracle (scripts/repro/arm64_linux_host_link_rq64_differential.py, `# ci-checks: emulations >= 2`): - compiles the fixture (arm64_linux_host_link_rq64.wat: host->synth in w/x/d regs, synth->host via the SHN_UNDEF import, synth->synth CALL26 to a non-exported local, linear memory via x28 checked from BOTH sides, globals in synth's own .data persisting across calls, call_indirect via the emitted funcref table, a value below an import call's args, memory.size); - GENERATES a freestanding C harness from its own case table (one source for the C and the wasmtime call sequences), `clang -target aarch64-unknown-linux-gnu -ffreestanding -nostdlib -ffixed-x28`, an asm `_start` that sets x28 once; only write+exit_group syscalls; - links with `ld.lld -m aarch64linux -static` and checks the image (ET_EXEC/EM_AARCH64/SYSV, 0 undefined, 0 .rela, all 28 synth symbols); - EXECUTES it: under unicorn with the Linux ELF-loader contract reproduced (PT_LOAD at vaddr, bss zeroed, e_entry); NATIVELY on the new `arm64-linux-native` job (ubuntu-24.04-arm, REQUIRE_NATIVE=1, no emulator anywhere); under qemu-user-static in `aarch64-oracle` (REQUIRE_QEMU=1, an independent loader + syscall layer). 17 wasmtime-first compares. - RED-FIRST built in: EM_ARM object -> `is incompatible with aarch64linux`; `-m elf_x86_64` -> `is incompatible with elf_x86_64`; missing import -> `undefined symbol: host_add`; and a bit flipped in `add` in the LINKED image must be a reported mismatch (measured: add -> 0xffffffff vs 0x7). NEGATIVE FINDING, measured and pinned: aarch64 emits `func_N` GLOBAL (ARM emits it LOCAL since #656), so two synth aarch64 objects cannot be linked into one program — `ld.lld: error: duplicate symbol: func_1`. Not fixed here (ELF-writer symtab ordering; every aarch64 oracle's expectations should move under review); the workaround `llvm-objcopy --regex --localize-symbol='func_[0-9]+'` is executed by the oracle (co-link succeeds, all 17 values still match) and documented. The pin is bidirectional: a writer change that makes it LOCAL reddens the oracle until the doc is corrected. docs/embedder-abi-relocatable-aarch64.md states the contract with every fact cited to the emitting file:line, split fixed / chosen / incidental (pinned: SYNTH-EMBEDDER-ABI-RELOCATABLE-AARCH64-RQ64): x28 = linear-memory base, set once before the first export, never written by emitted code; NO size register — the bounds limit is a BAKED IMMEDIATE, so the region must be at least the declared size; traps are `brk #0` = SIGTRAP on Linux (deliberately not exercised by this oracle); data segments refused; globals and the funcref table are emitted, not preconditions; `-static` is what is claimed (no PIE/dynamic/libc claim). Also: the CLI's post-compile "Link with: arm-none-eabi-ld … kiln_bridge.o" hint was printed for aarch64 objects too; it now names ld.lld -m aarch64linux and the x28 precondition. FEATURE_MATRIX template row and the README crate row carry the claim, the precondition and the limitation. `--exact-emulation-floor` 324845 -> 324847 (re-derived by oracle_wiring_check.py, not added) with SYNTH-ORACLE-CHECK-FLOORS-910-CI in lockstep; aarch64-oracle `--min-oracles` 16 -> 17. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…landed: (R10 attribution) The status_evidence R10 rule demands the artifact acknowledge the PR that delivered it; the number did not exist until the PR was opened. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
force-pushed
the
feat/arm64linux-1178
branch
from
September 7, 2026 06:21
0d5d004 to
19d422a
Compare
This was referenced Sep 7, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…sweep's EXPECTED_DECLINES, and make the sweep report the REAL decline reason The `repro sweep — ARM corpus (#973)` job compiles every scripts/repro/*.wat for ARM Thumb-2 and went red on #1179: the new aarch64 host-link fixture's `f64_scale` export (there to cross the AAPCS64 C boundary in d-registers) needs a double-precision FPU on the ARM target (GI-FPU-002), so one of its 14 functions is skipped and `--all-exports` correctly refuses under #952. That is the gate working, not a regression — the job is green on main `7b8b7e36` and at v0.63.0. Listed on EXPECTED_DECLINES with the reason written out; the sweep's RATCHET arm reddens the day it compiles, so the entry cannot rot. The defect the red EXPOSED (FIX 2): the sweep printed Reason: [2m…Z[0m [32m INFO[0m 12 bytes of machine code `compile_arm` returns stderr THEN stdout, and the reporter took `splitlines()[-1]` — always the last line of STDOUT, a tracing line — while the actual `Error: #952: …` sat on stderr and was never shown. Every NEW DECLINE this sweep has ever reported displayed a tracing line instead of the reason; the `"#952" in log` classification was always right. New `decline_reason()` prefers the first `Error:` line, then the line naming #952, then the last line, and strips ANSI escapes. Measured on this fixture's real log: OLD: '\x1b[2m2026-…Z\x1b[0m \x1b[32m INFO\x1b[0m 12 bytes of machine code' NEW: 'Error: #952: 1 of 12 requested export(s) were skipped (not in the output object): f64_scale. Exiting non-zero rather than shipping…' Fallbacks checked: no Error/#952 line -> last line (ANSI stripped); #952 without an `Error:` prefix -> that line; empty log -> ''. Refs #242 #973 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…dentity sweep + macOS host-link execution differential, before any writer exists The oracle, then the writer — the gating rule this artifact was deferred from v0.63 to honour. `scripts/repro/macho_host_link_rq64_differential.py` follows #1179's shape (one case table generating both the C harness and the wasmtime sequence, wasmtime-first, red-first controls built in) and adds the increment this artifact is actually about: * BYTE IDENTITY on every host: `.text` == `__TEXT,__text`, `.data` == `__DATA,__data`, symbols map 1:1 under the Darwin `_` prefix, and the relocation SET maps 1:1 under CALL26/JUMP26 -> BRANCH26, PG_HI21 -> PAGE21, LO12 -> PAGEOFF12 — for the fixture AND every repo `.wat` the backend accepts (139 today), with acceptance required to AGREE across containers. The Mach-O is read by the file's own ~60-line parser so the leg runs on the Linux runner too. * an identity MUTATION control (bit 30 of `add`'s first word flipped in `__text` must be reported); * on arm64-Darwin (REQUIRE_NATIVE=1 makes any other host RED, never a skip): clang -arch arm64 -ffixed-x28 + an x28 shim, linked by Apple ld through the clang driver, checked by Apple nm, EXECUTED natively vs wasmtime; the ELF twin handed to Apple ld must be refused `unknown file type` (measured), a missing `_host_add` refused by name, ld.lld must refuse the Mach-O when present, the mutated object linked and run must mismatch, and the #1180 `_func_1` co-link collision is pinned. Measured RED against the flagless binary: exit 1, `unexpected argument '--object-format'`, driver floor `compiles >= 100` unmet (measured 2). The fixture is byte-for-byte #1179's module below its header (verified by diff), so the same bytes' values on arm64-Linux and macOS read side by side. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…, so a second container cannot disagree with it (140/140 objects byte-identical) `plan_object` now computes everything a relocatable object SAYS — the concatenated `.text`, the `.data` image, the symbol list in emission order (function aliases, `.data` symbols, the #1017 referenced externals; first occurrence wins on a duplicated name), and the resolved relocations with the #1013 unplaced-symbol refusal, message verbatim — and `build_relocatable_object_full` only lays ELF around it. The Mach-O writer that follows consumes the SAME plan, which is what makes `.text` identity between the two containers a property of one function rather than of two writers happening to agree (the North Star's "derive what you check against from the artifact you ship"; a hand-copied symbol-ordering rule in a second writer would be the mirror it forbids). Gated as a pure refactor: every one of the 140 repo `.wat` modules the aarch64 backend accepts (`scripts/repro/*.wat` + `tests/**/*.wat`) compiles to bytes IDENTICAL to the pre-refactor binary (corpus captured before, compared after: accepted=140 identical=140 differ=0), and the crate's 156 unit tests — including the layout-pinning ELF tests — pass unchanged. The `let info = if f.is_object { 0x11 } else { 0x12 };` line #1179's claim pin counts is kept verbatim. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…ative arm64-macOS host-link oracle, so the container claim is GATED Re-applied against main's ci.yml after #1179 landed. The first attempt was dropped in the rebase: git's conflict boundary fell THROUGH a cache step rather than between jobs, so a mechanical "keep both sides" produced invalid YAML with an orphaned `key:` line. Re-applied surgically instead — the new step, the ledger bump and the new job placed individually, then the file parsed (59 jobs) rather than assumed correct. - byte-identity sweep, as a step in `aarch64-oracle`: for the fixture and every `.wat` the aarch64 backend accepts, BOTH containers are emitted and `.text`/`.data`, the symbols (under Darwin's `_`) and the relocation SET must be identical, with the acceptance decision agreeing. This is the host-independent half of the artifact's thesis — that the container, not the ISA, is what blocks shipping synth output as a host library — and it needs no linker and no execution to prove it. - `macho-host-link-native` on `macos-latest`: asserts the runner really is arm64 macOS, links with Apple ld and EXECUTES against wasmtime-first values. REQUIRE_NATIVE=1, so a wrong host is RED, never a silent skip. Not a required check, per the #1179 precedent: a new runner pool that GitHub cannot schedule would deadlock every merge. CUMULATIVE COUNTERS RE-DERIVED ON THE MERGED TREE, never carried textually: `--min-oracles` in aarch64-oracle is 17 on main because #1179 already bumped 16->17, so this makes it 18 — copying the pre-rebase value would have silently un-gated one oracle. The emulation floor is UNCHANGED at 324847 and that is correct, not an oversight: the Mach-O differential declares `compiles >= 100`, so the compiles bucket moves 9 scripts/43 to 10/143 while emulations does not. oracle_wiring reports 190 scripts, 182 wired, 0 unwired debt. SYNTH-SUBTRACTION-MIRRORS: 59 -> 60 with a waiver, NOT a loosened gate. Both new files say "mirror" only to state that they are not one — elf.rs explains that a second hand-written copy of the symbol-ordering rules "would be exactly the mirror the North Star forbids" (the reason ObjectPlan exists), and the differential explains that "a hand-mirrored pair would drift" (why it generates the C harness and the wasmtime sequence from one case table). Rewording to dodge the word count would delete the explanation and leave the metric happy. Verified: claim_check 60/60, oracle_wiring exit 0 at the pinned floor, status_evidence exit 0, ci.yml parses, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…dentity sweep + macOS host-link execution differential, before any writer exists The oracle, then the writer — the gating rule this artifact was deferred from v0.63 to honour. `scripts/repro/macho_host_link_rq64_differential.py` follows #1179's shape (one case table generating both the C harness and the wasmtime sequence, wasmtime-first, red-first controls built in) and adds the increment this artifact is actually about: * BYTE IDENTITY on every host: `.text` == `__TEXT,__text`, `.data` == `__DATA,__data`, symbols map 1:1 under the Darwin `_` prefix, and the relocation SET maps 1:1 under CALL26/JUMP26 -> BRANCH26, PG_HI21 -> PAGE21, LO12 -> PAGEOFF12 — for the fixture AND every repo `.wat` the backend accepts (139 today), with acceptance required to AGREE across containers. The Mach-O is read by the file's own ~60-line parser so the leg runs on the Linux runner too. * an identity MUTATION control (bit 30 of `add`'s first word flipped in `__text` must be reported); * on arm64-Darwin (REQUIRE_NATIVE=1 makes any other host RED, never a skip): clang -arch arm64 -ffixed-x28 + an x28 shim, linked by Apple ld through the clang driver, checked by Apple nm, EXECUTED natively vs wasmtime; the ELF twin handed to Apple ld must be refused `unknown file type` (measured), a missing `_host_add` refused by name, ld.lld must refuse the Mach-O when present, the mutated object linked and run must mismatch, and the #1180 `_func_1` co-link collision is pinned. Measured RED against the flagless binary: exit 1, `unexpected argument '--object-format'`, driver floor `compiles >= 100` unmet (measured 2). The fixture is byte-for-byte #1179's module below its header (verified by diff), so the same bytes' values on arm64-Linux and macOS read side by side. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…, so a second container cannot disagree with it (140/140 objects byte-identical) `plan_object` now computes everything a relocatable object SAYS — the concatenated `.text`, the `.data` image, the symbol list in emission order (function aliases, `.data` symbols, the #1017 referenced externals; first occurrence wins on a duplicated name), and the resolved relocations with the #1013 unplaced-symbol refusal, message verbatim — and `build_relocatable_object_full` only lays ELF around it. The Mach-O writer that follows consumes the SAME plan, which is what makes `.text` identity between the two containers a property of one function rather than of two writers happening to agree (the North Star's "derive what you check against from the artifact you ship"; a hand-copied symbol-ordering rule in a second writer would be the mirror it forbids). Gated as a pure refactor: every one of the 140 repo `.wat` modules the aarch64 backend accepts (`scripts/repro/*.wat` + `tests/**/*.wat`) compiles to bytes IDENTICAL to the pre-refactor binary (corpus captured before, compared after: accepted=140 identical=140 differ=0), and the crate's 156 unit tests — including the layout-pinning ELF tests — pass unchanged. The `let info = if f.is_object { 0x11 } else { 0x12 };` line #1179's claim pin counts is kept verbatim. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…ative arm64-macOS host-link oracle, so the container claim is GATED Re-applied against main's ci.yml after #1179 landed. The first attempt was dropped in the rebase: git's conflict boundary fell THROUGH a cache step rather than between jobs, so a mechanical "keep both sides" produced invalid YAML with an orphaned `key:` line. Re-applied surgically instead — the new step, the ledger bump and the new job placed individually, then the file parsed (59 jobs) rather than assumed correct. - byte-identity sweep, as a step in `aarch64-oracle`: for the fixture and every `.wat` the aarch64 backend accepts, BOTH containers are emitted and `.text`/`.data`, the symbols (under Darwin's `_`) and the relocation SET must be identical, with the acceptance decision agreeing. This is the host-independent half of the artifact's thesis — that the container, not the ISA, is what blocks shipping synth output as a host library — and it needs no linker and no execution to prove it. - `macho-host-link-native` on `macos-latest`: asserts the runner really is arm64 macOS, links with Apple ld and EXECUTES against wasmtime-first values. REQUIRE_NATIVE=1, so a wrong host is RED, never a silent skip. Not a required check, per the #1179 precedent: a new runner pool that GitHub cannot schedule would deadlock every merge. CUMULATIVE COUNTERS RE-DERIVED ON THE MERGED TREE, never carried textually: `--min-oracles` in aarch64-oracle is 17 on main because #1179 already bumped 16->17, so this makes it 18 — copying the pre-rebase value would have silently un-gated one oracle. The emulation floor is UNCHANGED at 324847 and that is correct, not an oversight: the Mach-O differential declares `compiles >= 100`, so the compiles bucket moves 9 scripts/43 to 10/143 while emulations does not. oracle_wiring reports 190 scripts, 182 wired, 0 unwired debt. SYNTH-SUBTRACTION-MIRRORS: 59 -> 60 with a waiver, NOT a loosened gate. Both new files say "mirror" only to state that they are not one — elf.rs explains that a second hand-written copy of the symbol-ordering rules "would be exactly the mirror the North Star forbids" (the reason ObjectPlan exists), and the differential explains that "a hand-mirrored pair would drift" (why it generates the C harness and the wasmtime sequence from one case table). Rewording to dodge the word count would delete the explanation and leave the metric happy. Verified: claim_check 60/60, oracle_wiring exit 0 at the pinned floor, status_evidence exit 0, ci.yml parses, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
… the ARM sweep's EXPECTED_DECLINES Same shape and same cause as its arm64-Linux sibling in #1179. The ARM corpus sweep compiles EVERY `.wat` under scripts/repro for ARM Thumb-2, and this PR adds an aarch64 fixture carrying an `f64_scale` export. On the ARM default target that hits GI-FPU-002 phase 2 (scalar f64 requires a double-precision FPU), so `--all-exports` would ship a partial object and synth correctly REFUSES under #952. Not a regression — the gate noticing a new fixture with no expectation. Measured against the branch binary at `--target cortex-m4`, not inferred: warning: skipping function 'f64_scale': ... GI-FPU-002 phase 2: scalar f64 requires a double-precision FPU Error: #952: 1 of 12 requested export(s) were skipped ... f64_scale The sweep's RATCHET arm reddens if an EXPECTED_DECLINES entry ever starts compiling, so the entry cannot rot silently — which is why this is the right mechanism rather than excluding the file from the sweep. Verified on the rebased tree: `#973 ARM CORPUS SWEEP: PASS` (compiled 158/177, executed 2526/2526, mismatches 0), oracle_wiring exit 0 at the pinned floor 324847 with 190 scripts / 183 wired / 0 unwired debt, claim_check 60/60, status_evidence exit 0, ci.yml parses at 59 jobs, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…dentity sweep + macOS host-link execution differential, before any writer exists The oracle, then the writer — the gating rule this artifact was deferred from v0.63 to honour. `scripts/repro/macho_host_link_rq64_differential.py` follows #1179's shape (one case table generating both the C harness and the wasmtime sequence, wasmtime-first, red-first controls built in) and adds the increment this artifact is actually about: * BYTE IDENTITY on every host: `.text` == `__TEXT,__text`, `.data` == `__DATA,__data`, symbols map 1:1 under the Darwin `_` prefix, and the relocation SET maps 1:1 under CALL26/JUMP26 -> BRANCH26, PG_HI21 -> PAGE21, LO12 -> PAGEOFF12 — for the fixture AND every repo `.wat` the backend accepts (139 today), with acceptance required to AGREE across containers. The Mach-O is read by the file's own ~60-line parser so the leg runs on the Linux runner too. * an identity MUTATION control (bit 30 of `add`'s first word flipped in `__text` must be reported); * on arm64-Darwin (REQUIRE_NATIVE=1 makes any other host RED, never a skip): clang -arch arm64 -ffixed-x28 + an x28 shim, linked by Apple ld through the clang driver, checked by Apple nm, EXECUTED natively vs wasmtime; the ELF twin handed to Apple ld must be refused `unknown file type` (measured), a missing `_host_add` refused by name, ld.lld must refuse the Mach-O when present, the mutated object linked and run must mismatch, and the #1180 `_func_1` co-link collision is pinned. Measured RED against the flagless binary: exit 1, `unexpected argument '--object-format'`, driver floor `compiles >= 100` unmet (measured 2). The fixture is byte-for-byte #1179's module below its header (verified by diff), so the same bytes' values on arm64-Linux and macOS read side by side. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…, so a second container cannot disagree with it (140/140 objects byte-identical) `plan_object` now computes everything a relocatable object SAYS — the concatenated `.text`, the `.data` image, the symbol list in emission order (function aliases, `.data` symbols, the #1017 referenced externals; first occurrence wins on a duplicated name), and the resolved relocations with the #1013 unplaced-symbol refusal, message verbatim — and `build_relocatable_object_full` only lays ELF around it. The Mach-O writer that follows consumes the SAME plan, which is what makes `.text` identity between the two containers a property of one function rather than of two writers happening to agree (the North Star's "derive what you check against from the artifact you ship"; a hand-copied symbol-ordering rule in a second writer would be the mirror it forbids). Gated as a pure refactor: every one of the 140 repo `.wat` modules the aarch64 backend accepts (`scripts/repro/*.wat` + `tests/**/*.wat`) compiles to bytes IDENTICAL to the pre-refactor binary (corpus captured before, compared after: accepted=140 identical=140 differ=0), and the crate's 156 unit tests — including the layout-pinning ELF tests — pass unchanged. The `let info = if f.is_object { 0x11 } else { 0x12 };` line #1179's claim pin counts is kept verbatim. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…ative arm64-macOS host-link oracle, so the container claim is GATED Re-applied against main's ci.yml after #1179 landed. The first attempt was dropped in the rebase: git's conflict boundary fell THROUGH a cache step rather than between jobs, so a mechanical "keep both sides" produced invalid YAML with an orphaned `key:` line. Re-applied surgically instead — the new step, the ledger bump and the new job placed individually, then the file parsed (59 jobs) rather than assumed correct. - byte-identity sweep, as a step in `aarch64-oracle`: for the fixture and every `.wat` the aarch64 backend accepts, BOTH containers are emitted and `.text`/`.data`, the symbols (under Darwin's `_`) and the relocation SET must be identical, with the acceptance decision agreeing. This is the host-independent half of the artifact's thesis — that the container, not the ISA, is what blocks shipping synth output as a host library — and it needs no linker and no execution to prove it. - `macho-host-link-native` on `macos-latest`: asserts the runner really is arm64 macOS, links with Apple ld and EXECUTES against wasmtime-first values. REQUIRE_NATIVE=1, so a wrong host is RED, never a silent skip. Not a required check, per the #1179 precedent: a new runner pool that GitHub cannot schedule would deadlock every merge. CUMULATIVE COUNTERS RE-DERIVED ON THE MERGED TREE, never carried textually: `--min-oracles` in aarch64-oracle is 17 on main because #1179 already bumped 16->17, so this makes it 18 — copying the pre-rebase value would have silently un-gated one oracle. The emulation floor is UNCHANGED at 324847 and that is correct, not an oversight: the Mach-O differential declares `compiles >= 100`, so the compiles bucket moves 9 scripts/43 to 10/143 while emulations does not. oracle_wiring reports 190 scripts, 182 wired, 0 unwired debt. SYNTH-SUBTRACTION-MIRRORS: 59 -> 60 with a waiver, NOT a loosened gate. Both new files say "mirror" only to state that they are not one — elf.rs explains that a second hand-written copy of the symbol-ordering rules "would be exactly the mirror the North Star forbids" (the reason ObjectPlan exists), and the differential explains that "a hand-mirrored pair would drift" (why it generates the C harness and the wasmtime sequence from one case table). Rewording to dodge the word count would delete the explanation and leave the metric happy. Verified: claim_check 60/60, oracle_wiring exit 0 at the pinned floor, status_evidence exit 0, ci.yml parses, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
… the ARM sweep's EXPECTED_DECLINES Same shape and same cause as its arm64-Linux sibling in #1179. The ARM corpus sweep compiles EVERY `.wat` under scripts/repro for ARM Thumb-2, and this PR adds an aarch64 fixture carrying an `f64_scale` export. On the ARM default target that hits GI-FPU-002 phase 2 (scalar f64 requires a double-precision FPU), so `--all-exports` would ship a partial object and synth correctly REFUSES under #952. Not a regression — the gate noticing a new fixture with no expectation. Measured against the branch binary at `--target cortex-m4`, not inferred: warning: skipping function 'f64_scale': ... GI-FPU-002 phase 2: scalar f64 requires a double-precision FPU Error: #952: 1 of 12 requested export(s) were skipped ... f64_scale The sweep's RATCHET arm reddens if an EXPECTED_DECLINES entry ever starts compiling, so the entry cannot rot silently — which is why this is the right mechanism rather than excluding the file from the sweep. Verified on the rebased tree: `#973 ARM CORPUS SWEEP: PASS` (compiled 158/177, executed 2526/2526, mismatches 0), oracle_wiring exit 0 at the pinned floor 324847 with 190 scripts / 183 wired / 0 unwired debt, claim_check 60/60, status_evidence exit 0, ci.yml parses at 59 jobs, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…dentity sweep + macOS host-link execution differential, before any writer exists The oracle, then the writer — the gating rule this artifact was deferred from v0.63 to honour. `scripts/repro/macho_host_link_rq64_differential.py` follows #1179's shape (one case table generating both the C harness and the wasmtime sequence, wasmtime-first, red-first controls built in) and adds the increment this artifact is actually about: * BYTE IDENTITY on every host: `.text` == `__TEXT,__text`, `.data` == `__DATA,__data`, symbols map 1:1 under the Darwin `_` prefix, and the relocation SET maps 1:1 under CALL26/JUMP26 -> BRANCH26, PG_HI21 -> PAGE21, LO12 -> PAGEOFF12 — for the fixture AND every repo `.wat` the backend accepts (139 today), with acceptance required to AGREE across containers. The Mach-O is read by the file's own ~60-line parser so the leg runs on the Linux runner too. * an identity MUTATION control (bit 30 of `add`'s first word flipped in `__text` must be reported); * on arm64-Darwin (REQUIRE_NATIVE=1 makes any other host RED, never a skip): clang -arch arm64 -ffixed-x28 + an x28 shim, linked by Apple ld through the clang driver, checked by Apple nm, EXECUTED natively vs wasmtime; the ELF twin handed to Apple ld must be refused `unknown file type` (measured), a missing `_host_add` refused by name, ld.lld must refuse the Mach-O when present, the mutated object linked and run must mismatch, and the #1180 `_func_1` co-link collision is pinned. Measured RED against the flagless binary: exit 1, `unexpected argument '--object-format'`, driver floor `compiles >= 100` unmet (measured 2). The fixture is byte-for-byte #1179's module below its header (verified by diff), so the same bytes' values on arm64-Linux and macOS read side by side. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…, so a second container cannot disagree with it (140/140 objects byte-identical) `plan_object` now computes everything a relocatable object SAYS — the concatenated `.text`, the `.data` image, the symbol list in emission order (function aliases, `.data` symbols, the #1017 referenced externals; first occurrence wins on a duplicated name), and the resolved relocations with the #1013 unplaced-symbol refusal, message verbatim — and `build_relocatable_object_full` only lays ELF around it. The Mach-O writer that follows consumes the SAME plan, which is what makes `.text` identity between the two containers a property of one function rather than of two writers happening to agree (the North Star's "derive what you check against from the artifact you ship"; a hand-copied symbol-ordering rule in a second writer would be the mirror it forbids). Gated as a pure refactor: every one of the 140 repo `.wat` modules the aarch64 backend accepts (`scripts/repro/*.wat` + `tests/**/*.wat`) compiles to bytes IDENTICAL to the pre-refactor binary (corpus captured before, compared after: accepted=140 identical=140 differ=0), and the crate's 156 unit tests — including the layout-pinning ELF tests — pass unchanged. The `let info = if f.is_object { 0x11 } else { 0x12 };` line #1179's claim pin counts is kept verbatim. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…ative arm64-macOS host-link oracle, so the container claim is GATED Re-applied against main's ci.yml after #1179 landed. The first attempt was dropped in the rebase: git's conflict boundary fell THROUGH a cache step rather than between jobs, so a mechanical "keep both sides" produced invalid YAML with an orphaned `key:` line. Re-applied surgically instead — the new step, the ledger bump and the new job placed individually, then the file parsed (59 jobs) rather than assumed correct. - byte-identity sweep, as a step in `aarch64-oracle`: for the fixture and every `.wat` the aarch64 backend accepts, BOTH containers are emitted and `.text`/`.data`, the symbols (under Darwin's `_`) and the relocation SET must be identical, with the acceptance decision agreeing. This is the host-independent half of the artifact's thesis — that the container, not the ISA, is what blocks shipping synth output as a host library — and it needs no linker and no execution to prove it. - `macho-host-link-native` on `macos-latest`: asserts the runner really is arm64 macOS, links with Apple ld and EXECUTES against wasmtime-first values. REQUIRE_NATIVE=1, so a wrong host is RED, never a silent skip. Not a required check, per the #1179 precedent: a new runner pool that GitHub cannot schedule would deadlock every merge. CUMULATIVE COUNTERS RE-DERIVED ON THE MERGED TREE, never carried textually: `--min-oracles` in aarch64-oracle is 17 on main because #1179 already bumped 16->17, so this makes it 18 — copying the pre-rebase value would have silently un-gated one oracle. The emulation floor is UNCHANGED at 324847 and that is correct, not an oversight: the Mach-O differential declares `compiles >= 100`, so the compiles bucket moves 9 scripts/43 to 10/143 while emulations does not. oracle_wiring reports 190 scripts, 182 wired, 0 unwired debt. SYNTH-SUBTRACTION-MIRRORS: 59 -> 60 with a waiver, NOT a loosened gate. Both new files say "mirror" only to state that they are not one — elf.rs explains that a second hand-written copy of the symbol-ordering rules "would be exactly the mirror the North Star forbids" (the reason ObjectPlan exists), and the differential explains that "a hand-mirrored pair would drift" (why it generates the C harness and the wasmtime sequence from one case table). Rewording to dodge the word count would delete the explanation and leave the metric happy. Verified: claim_check 60/60, oracle_wiring exit 0 at the pinned floor, status_evidence exit 0, ci.yml parses, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
… the ARM sweep's EXPECTED_DECLINES Same shape and same cause as its arm64-Linux sibling in #1179. The ARM corpus sweep compiles EVERY `.wat` under scripts/repro for ARM Thumb-2, and this PR adds an aarch64 fixture carrying an `f64_scale` export. On the ARM default target that hits GI-FPU-002 phase 2 (scalar f64 requires a double-precision FPU), so `--all-exports` would ship a partial object and synth correctly REFUSES under #952. Not a regression — the gate noticing a new fixture with no expectation. Measured against the branch binary at `--target cortex-m4`, not inferred: warning: skipping function 'f64_scale': ... GI-FPU-002 phase 2: scalar f64 requires a double-precision FPU Error: #952: 1 of 12 requested export(s) were skipped ... f64_scale The sweep's RATCHET arm reddens if an EXPECTED_DECLINES entry ever starts compiling, so the entry cannot rot silently — which is why this is the right mechanism rather than excluding the file from the sweep. Verified on the rebased tree: `#973 ARM CORPUS SWEEP: PASS` (compiled 158/177, executed 2526/2526, mismatches 0), oracle_wiring exit 0 at the pinned floor 324847 with 190 scripts / 183 wired / 0 unwired debt, claim_check 60/60, status_evidence exit 0, ci.yml parses at 59 jobs, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…dentity sweep + macOS host-link execution differential, before any writer exists The oracle, then the writer — the gating rule this artifact was deferred from v0.63 to honour. `scripts/repro/macho_host_link_rq64_differential.py` follows #1179's shape (one case table generating both the C harness and the wasmtime sequence, wasmtime-first, red-first controls built in) and adds the increment this artifact is actually about: * BYTE IDENTITY on every host: `.text` == `__TEXT,__text`, `.data` == `__DATA,__data`, symbols map 1:1 under the Darwin `_` prefix, and the relocation SET maps 1:1 under CALL26/JUMP26 -> BRANCH26, PG_HI21 -> PAGE21, LO12 -> PAGEOFF12 — for the fixture AND every repo `.wat` the backend accepts (139 today), with acceptance required to AGREE across containers. The Mach-O is read by the file's own ~60-line parser so the leg runs on the Linux runner too. * an identity MUTATION control (bit 30 of `add`'s first word flipped in `__text` must be reported); * on arm64-Darwin (REQUIRE_NATIVE=1 makes any other host RED, never a skip): clang -arch arm64 -ffixed-x28 + an x28 shim, linked by Apple ld through the clang driver, checked by Apple nm, EXECUTED natively vs wasmtime; the ELF twin handed to Apple ld must be refused `unknown file type` (measured), a missing `_host_add` refused by name, ld.lld must refuse the Mach-O when present, the mutated object linked and run must mismatch, and the #1180 `_func_1` co-link collision is pinned. Measured RED against the flagless binary: exit 1, `unexpected argument '--object-format'`, driver floor `compiles >= 100` unmet (measured 2). The fixture is byte-for-byte #1179's module below its header (verified by diff), so the same bytes' values on arm64-Linux and macOS read side by side. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…, so a second container cannot disagree with it (140/140 objects byte-identical) `plan_object` now computes everything a relocatable object SAYS — the concatenated `.text`, the `.data` image, the symbol list in emission order (function aliases, `.data` symbols, the #1017 referenced externals; first occurrence wins on a duplicated name), and the resolved relocations with the #1013 unplaced-symbol refusal, message verbatim — and `build_relocatable_object_full` only lays ELF around it. The Mach-O writer that follows consumes the SAME plan, which is what makes `.text` identity between the two containers a property of one function rather than of two writers happening to agree (the North Star's "derive what you check against from the artifact you ship"; a hand-copied symbol-ordering rule in a second writer would be the mirror it forbids). Gated as a pure refactor: every one of the 140 repo `.wat` modules the aarch64 backend accepts (`scripts/repro/*.wat` + `tests/**/*.wat`) compiles to bytes IDENTICAL to the pre-refactor binary (corpus captured before, compared after: accepted=140 identical=140 differ=0), and the crate's 156 unit tests — including the layout-pinning ELF tests — pass unchanged. The `let info = if f.is_object { 0x11 } else { 0x12 };` line #1179's claim pin counts is kept verbatim. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…ative arm64-macOS host-link oracle, so the container claim is GATED Re-applied against main's ci.yml after #1179 landed. The first attempt was dropped in the rebase: git's conflict boundary fell THROUGH a cache step rather than between jobs, so a mechanical "keep both sides" produced invalid YAML with an orphaned `key:` line. Re-applied surgically instead — the new step, the ledger bump and the new job placed individually, then the file parsed (59 jobs) rather than assumed correct. - byte-identity sweep, as a step in `aarch64-oracle`: for the fixture and every `.wat` the aarch64 backend accepts, BOTH containers are emitted and `.text`/`.data`, the symbols (under Darwin's `_`) and the relocation SET must be identical, with the acceptance decision agreeing. This is the host-independent half of the artifact's thesis — that the container, not the ISA, is what blocks shipping synth output as a host library — and it needs no linker and no execution to prove it. - `macho-host-link-native` on `macos-latest`: asserts the runner really is arm64 macOS, links with Apple ld and EXECUTES against wasmtime-first values. REQUIRE_NATIVE=1, so a wrong host is RED, never a silent skip. Not a required check, per the #1179 precedent: a new runner pool that GitHub cannot schedule would deadlock every merge. CUMULATIVE COUNTERS RE-DERIVED ON THE MERGED TREE, never carried textually: `--min-oracles` in aarch64-oracle is 17 on main because #1179 already bumped 16->17, so this makes it 18 — copying the pre-rebase value would have silently un-gated one oracle. The emulation floor is UNCHANGED at 324847 and that is correct, not an oversight: the Mach-O differential declares `compiles >= 100`, so the compiles bucket moves 9 scripts/43 to 10/143 while emulations does not. oracle_wiring reports 190 scripts, 182 wired, 0 unwired debt. SYNTH-SUBTRACTION-MIRRORS: 59 -> 60 with a waiver, NOT a loosened gate. Both new files say "mirror" only to state that they are not one — elf.rs explains that a second hand-written copy of the symbol-ordering rules "would be exactly the mirror the North Star forbids" (the reason ObjectPlan exists), and the differential explains that "a hand-mirrored pair would drift" (why it generates the C harness and the wasmtime sequence from one case table). Rewording to dodge the word count would delete the explanation and leave the metric happy. Verified: claim_check 60/60, oracle_wiring exit 0 at the pinned floor, status_evidence exit 0, ci.yml parses, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
… the ARM sweep's EXPECTED_DECLINES Same shape and same cause as its arm64-Linux sibling in #1179. The ARM corpus sweep compiles EVERY `.wat` under scripts/repro for ARM Thumb-2, and this PR adds an aarch64 fixture carrying an `f64_scale` export. On the ARM default target that hits GI-FPU-002 phase 2 (scalar f64 requires a double-precision FPU), so `--all-exports` would ship a partial object and synth correctly REFUSES under #952. Not a regression — the gate noticing a new fixture with no expectation. Measured against the branch binary at `--target cortex-m4`, not inferred: warning: skipping function 'f64_scale': ... GI-FPU-002 phase 2: scalar f64 requires a double-precision FPU Error: #952: 1 of 12 requested export(s) were skipped ... f64_scale The sweep's RATCHET arm reddens if an EXPECTED_DECLINES entry ever starts compiling, so the entry cannot rot silently — which is why this is the right mechanism rather than excluding the file from the sweep. Verified on the rebased tree: `#973 ARM CORPUS SWEEP: PASS` (compiled 158/177, executed 2526/2526, mismatches 0), oracle_wiring exit 0 at the pinned floor 324847 with 190 scripts / 183 wired / 0 unwired debt, claim_check 60/60, status_evidence exit 0, ci.yml parses at 59 jobs, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Sep 7, 2026
…lan, linked by Apple ld and EXECUTED on macOS (#1184) * test(aarch64): RQ-64-MACHO oracle lands RED-FIRST — ELF/Mach-O byte-identity sweep + macOS host-link execution differential, before any writer exists The oracle, then the writer — the gating rule this artifact was deferred from v0.63 to honour. `scripts/repro/macho_host_link_rq64_differential.py` follows #1179's shape (one case table generating both the C harness and the wasmtime sequence, wasmtime-first, red-first controls built in) and adds the increment this artifact is actually about: * BYTE IDENTITY on every host: `.text` == `__TEXT,__text`, `.data` == `__DATA,__data`, symbols map 1:1 under the Darwin `_` prefix, and the relocation SET maps 1:1 under CALL26/JUMP26 -> BRANCH26, PG_HI21 -> PAGE21, LO12 -> PAGEOFF12 — for the fixture AND every repo `.wat` the backend accepts (139 today), with acceptance required to AGREE across containers. The Mach-O is read by the file's own ~60-line parser so the leg runs on the Linux runner too. * an identity MUTATION control (bit 30 of `add`'s first word flipped in `__text` must be reported); * on arm64-Darwin (REQUIRE_NATIVE=1 makes any other host RED, never a skip): clang -arch arm64 -ffixed-x28 + an x28 shim, linked by Apple ld through the clang driver, checked by Apple nm, EXECUTED natively vs wasmtime; the ELF twin handed to Apple ld must be refused `unknown file type` (measured), a missing `_host_add` refused by name, ld.lld must refuse the Mach-O when present, the mutated object linked and run must mismatch, and the #1180 `_func_1` co-link collision is pinned. Measured RED against the flagless binary: exit 1, `unexpected argument '--object-format'`, driver floor `compiles >= 100` unmet (measured 2). The fixture is byte-for-byte #1179's module below its header (verified by diff), so the same bytes' values on arm64-Linux and macOS read side by side. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * refactor(aarch64): RQ-64-MACHO — one ObjectPlan behind the ELF writer, so a second container cannot disagree with it (140/140 objects byte-identical) `plan_object` now computes everything a relocatable object SAYS — the concatenated `.text`, the `.data` image, the symbol list in emission order (function aliases, `.data` symbols, the #1017 referenced externals; first occurrence wins on a duplicated name), and the resolved relocations with the #1013 unplaced-symbol refusal, message verbatim — and `build_relocatable_object_full` only lays ELF around it. The Mach-O writer that follows consumes the SAME plan, which is what makes `.text` identity between the two containers a property of one function rather than of two writers happening to agree (the North Star's "derive what you check against from the artifact you ship"; a hand-copied symbol-ordering rule in a second writer would be the mirror it forbids). Gated as a pure refactor: every one of the 140 repo `.wat` modules the aarch64 backend accepts (`scripts/repro/*.wat` + `tests/**/*.wat`) compiles to bytes IDENTICAL to the pre-refactor binary (corpus captured before, compared after: accepted=140 identical=140 differ=0), and the crate's 156 unit tests — including the layout-pinning ELF tests — pass unchanged. The `let info = if f.is_object { 0x11 } else { 0x12 };` line #1179's claim pin counts is kept verbatim. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * feat(aarch64): RQ-64-MACHO — `--object-format macho` emits a CPU_TYPE_ARM64 MH_OBJECT over the ELF plan; Apple ld links it and macOS EXECUTES it 17/17 vs wasmtime The container was the blocker, not the ISA — now measured rather than argued. `crates/synth-backend-aarch64/src/macho.rs` lays Mach-O around the SAME `ObjectPlan` the ELF writer consumes (the previous commit): one unnamed LC_SEGMENT_64 with `__TEXT,__text` (+ `__DATA,__data` when the module has globals, file offsets congruent with addresses), LC_BUILD_VERSION (macOS, minos 11.0 — the one macOS-specific fact), LC_SYMTAB + LC_DYSYMTAB with every symbol N_EXT under Darwin's `_` prefix, and one `__text` relocation per planned relocation, all r_extern/r_length 2: CALL26/JUMP26 -> ARM64_RELOC_BRANCH26, ADR_PREL_PG_HI21 -> PAGE21, ADD_ABS_LO12_NC -> PAGEOFF12 (addends are zero in both containers, so no ADDEND entry is ever needed; any other kind fails loudly, the ELF rule). MH_SUBSECTIONS_VIA_SYMBOLS is deliberately NOT set so `__text` stays one atom with exactly the ELF layout. The flag is EXPLICIT and narrow: `--object-format {elf,macho}`, default `elf` (every pre-v0.64 compile byte-identical — the ELF path was corpus-diffed 140/140 in the previous commit), and `macho` is REFUSED on any backend but `-b aarch64` rather than silently emitting ELF under a flag that says otherwise. `build_aarch64_object` in synth-cli is the one place the container is chosen; both the single-function and `--all-exports` paths route through it. The post-compile hint names the toolchain the oracle actually exercised. MEASURED, by the red-first oracle from two commits ago, now green (`SYNTH=… python scripts/oracle_run.py scripts/repro/macho_host_link_rq64_differential.py`, arm64 macOS 26.6, Apple ld-1267, clang 21): * byte identity: `.text == __text` (580 B), `.data == __data`, 29 symbols and 20 relocations map 1:1 for the fixture; 139/139 corpus modules byte-identical, 0 acceptance disagreements (140 in all); * identity mutation control: a flipped bit in `__text` is reported; * Apple ld links the object with NO warnings; nm sees all 32 wanted symbols, `_host_add` bound to the C definition; * EXECUTED natively: 17/17 values match wasmtime (w/x/d registers, x28 memory from both sides, globals persisting in __DATA, call_indirect via BRANCH26 trampolines, import call, RQ-63-A64STACK shape); * refusals by name: the ELF twin into Apple ld (`unknown file type`), a missing `_host_add`, the Mach-O into ld.lld (`unknown file type`); * execution mutation control: the mutated object linked and run mismatches (add -> 0xffffffff vs 0x7); * #1180 pinned: two Mach-O objects collide `duplicate symbol '_func_1'` exactly as ELF does — noted, not fixed here; * driver floor compiles >= 100, measured 387. Six unit tests in macho.rs pin the header/sections/build-version, the symbol prefix + defined-then-undefined partition, the kind-for-kind reloc packing, `.text`/`.data` identity with the ELF writer, the no-globals single-section shape, and the shared #1013 refusal. Refs #242, #1180 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * chore(aarch64): RQ-64-MACHO — clippy -D warnings clean (needless borrow, is_multiple_of, test type alias); ELF corpus still 140/140 identical Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * test(ci): RQ-64-MACHO (#242) — wire the byte-identity sweep and the native arm64-macOS host-link oracle, so the container claim is GATED Re-applied against main's ci.yml after #1179 landed. The first attempt was dropped in the rebase: git's conflict boundary fell THROUGH a cache step rather than between jobs, so a mechanical "keep both sides" produced invalid YAML with an orphaned `key:` line. Re-applied surgically instead — the new step, the ledger bump and the new job placed individually, then the file parsed (59 jobs) rather than assumed correct. - byte-identity sweep, as a step in `aarch64-oracle`: for the fixture and every `.wat` the aarch64 backend accepts, BOTH containers are emitted and `.text`/`.data`, the symbols (under Darwin's `_`) and the relocation SET must be identical, with the acceptance decision agreeing. This is the host-independent half of the artifact's thesis — that the container, not the ISA, is what blocks shipping synth output as a host library — and it needs no linker and no execution to prove it. - `macho-host-link-native` on `macos-latest`: asserts the runner really is arm64 macOS, links with Apple ld and EXECUTES against wasmtime-first values. REQUIRE_NATIVE=1, so a wrong host is RED, never a silent skip. Not a required check, per the #1179 precedent: a new runner pool that GitHub cannot schedule would deadlock every merge. CUMULATIVE COUNTERS RE-DERIVED ON THE MERGED TREE, never carried textually: `--min-oracles` in aarch64-oracle is 17 on main because #1179 already bumped 16->17, so this makes it 18 — copying the pre-rebase value would have silently un-gated one oracle. The emulation floor is UNCHANGED at 324847 and that is correct, not an oversight: the Mach-O differential declares `compiles >= 100`, so the compiles bucket moves 9 scripts/43 to 10/143 while emulations does not. oracle_wiring reports 190 scripts, 182 wired, 0 unwired debt. SYNTH-SUBTRACTION-MIRRORS: 59 -> 60 with a waiver, NOT a loosened gate. Both new files say "mirror" only to state that they are not one — elf.rs explains that a second hand-written copy of the symbol-ordering rules "would be exactly the mirror the North Star forbids" (the reason ObjectPlan exists), and the differential explains that "a hand-mirrored pair would drift" (why it generates the C harness and the wasmtime sequence from one case table). Rewording to dodge the word count would delete the explanation and leave the metric happy. Verified: claim_check 60/60, oracle_wiring exit 0 at the pinned floor, status_evidence exit 0, ci.yml parses, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * chore(release): RQ-64-MACHO (#242) — flip to implemented, with provenance split between lane and coordinator The lane was terminated mid-step by an API session limit; the coordinator finished the rebase and the CI wiring. The verified-by says which claims come from which, and marks the macOS 17/17 execution as the lane's measurement for CI to confirm rather than restating it as though re-run here. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * chore(release): RQ-64-MACHO (#242) — record PR #1184 in the artifact's landed: (R10 attribution) Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * fix(ci): RQ-64-MACHO (#242) — the macOS oracle's own precondition named a path that never exists The `Mach-O host-link oracle, NATIVE arm64-macOS` job went RED at its FIRST assertion, before running the oracle at all. The defect is in the wiring I added in this PR, not in the lane's differential. "$(brew --prefix llvm)/bin/ld.lld" --version Two things wrong at once, and each hides the other: - `brew --prefix llvm` prints a path whether or not the formula is installed, so the expression always LOOKS resolvable. - brew's `llvm` formula does not ship `ld.lld` at all. The separate `lld` formula does. Measured on an arm64 Darwin host with llvm 22.1.8 and lld 22.1.8 both installed: `/opt/homebrew/opt/llvm/bin/ld.lld` is ABSENT, `/opt/homebrew/opt/lld/bin/ld.lld` is present and symlinked onto PATH. So the step installed the wrong formula and then checked a path that formula would not have created either way. Fixed: install `lld`, and assert via `command -v ld.lld` + `ld.lld --version` rather than a reconstructed prefix. The assertion still REQUIRES the tool rather than probing for it — the differential itself skips its ld.lld reverse-refusal control when the tool is missing, and a skipped red-first control is exactly the silent-skip class this repo keeps finding. We control this runner, so absence is an error and the control stays non-vacuous. Verified: the corrected assertion runs green on an arm64 Darwin host (`uname -m` arm64, `uname -s` Darwin, `command -v ld.lld` resolves, `ld.lld --version` prints LLD 21.0.0); ci.yml parses at 59 jobs. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * fix(ci): RQ-64-MACHO (#242) — the SAME bad brew path was in a second place; sweep the class, not the instance The previous commit fixed `"$(brew --prefix llvm)/bin/ld.lld"` in the job's ASSERTION step and left the identical expression in the step that actually runs the oracle: SYNTH=./target/debug/synth REQUIRE_NATIVE=1 LLD="$(brew --prefix llvm)/bin/ld.lld" So the assertion went green and the oracle then failed one step later — `LLD` pointed at a binary that does not exist, the ld.lld reverse-refusal probe did not run, `host-linker refusals` came back 2 instead of 3, and the step's grep failed. Fixing the instance instead of the class is the v0.56 lesson (#932/#953/#959, where the same sentinel bug was patched three releases running before anyone swept all 54 sites). SWEPT, and the sweep found one more use that is CORRECT and is deliberately left alone: `OBJCOPY="$(brew --prefix llvm)/bin/llvm-objcopy"` in `aarch64-native-matrix`. Measured on an arm64 Darwin host with llvm 22.1.8 installed — the llvm formula ships `llvm-objcopy` and `clang` but NOT `ld.lld`, which lives in the separate `lld` formula. So the pattern is not uniformly wrong and a blanket replace would have been its own defect. Fix: drop the LLD override entirely. `brew install lld` (previous commit) puts `ld.lld` on PATH, which is where the differential's `find_tool` looks by default. VERIFIED by reproducing the CI invocation locally on arm64 Darwin, with no LLD override, exactly as CI will now run it: byte-identical modules: 141 acceptance disagreements: 0 identity mutation: detected executions: 17 host-linker refusals: 3 native-abi runs: 1 mutation: detected RESULT: PASS The run also answers a question #1180 left open: two synth Mach-O objects DO collide on `_func_1` exactly as the ELF pair does, so the `func_N` STB_GLOBAL shape is shared across containers rather than ELF-specific. The oracle pins that as a limitation rather than asserting the opposite. ci.yml parses at 59 jobs. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * fix(repro): RQ-64-MACHO (#242) — list the Mach-O host-link fixture on the ARM sweep's EXPECTED_DECLINES Same shape and same cause as its arm64-Linux sibling in #1179. The ARM corpus sweep compiles EVERY `.wat` under scripts/repro for ARM Thumb-2, and this PR adds an aarch64 fixture carrying an `f64_scale` export. On the ARM default target that hits GI-FPU-002 phase 2 (scalar f64 requires a double-precision FPU), so `--all-exports` would ship a partial object and synth correctly REFUSES under #952. Not a regression — the gate noticing a new fixture with no expectation. Measured against the branch binary at `--target cortex-m4`, not inferred: warning: skipping function 'f64_scale': ... GI-FPU-002 phase 2: scalar f64 requires a double-precision FPU Error: #952: 1 of 12 requested export(s) were skipped ... f64_scale The sweep's RATCHET arm reddens if an EXPECTED_DECLINES entry ever starts compiling, so the entry cannot rot silently — which is why this is the right mechanism rather than excluding the file from the sweep. Verified on the rebased tree: `#973 ARM CORPUS SWEEP: PASS` (compiled 158/177, executed 2526/2526, mismatches 0), oracle_wiring exit 0 at the pinned floor 324847 with 190 scripts / 183 wired / 0 unwired debt, claim_check 60/60, status_evidence exit 0, ci.yml parses at 59 jobs, rivet at main's 40-error baseline. Refs #242 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RQ-64-ARM64LINUX — the arm64-Linux host-library claim, linked by a real host linker and EXECUTED
synth compile -b aarch64 --target cortex-a53 --relocatablehas emitted a SysV ELF64ET_RELforEM_AARCH64that links into an arm64-Linux program since v0.51 — true by accident: no document claimed it, no oracle handed it to a host linker for that target, nothing executed the result.fileandnmwere the whole evidence base. This PR makes it a claim backed by execution, states the embedder precondition to the emittingfile:line, and records the one thing the link found that does NOT work.Refs #242 (VCR epic). Artifact
artifacts/release-v0.64/RQ-64-ARM64LINUX.yaml→implemented.What the oracle links and executes
scripts/repro/arm64_linux_host_link_rq64_differential.py(# ci-checks: emulations >= 2), fixturearm64_linux_host_link_rq64.wat:-b aarch64 --target cortex-a53 --relocatable --all-exports) →synth.o, 28 defined symbols, exactly one undefined (host_add, the import);clang -target aarch64-unknown-linux-gnu -ffreestanding -nostdlib -ffixed-x28, plus an asm_startthat setsx28once; the harness's only kernel surface iswrite(2)+exit_group(2);ld.lld -m aarch64linux -static— the linker resolves everyR_AARCH64_CALL26/JUMP26/ADR_PREL_PG_HI21/ADD_ABS_LO12_NCsynth emits, places synth's.data(__synth_globals), binds theSHN_UNDEFimport to the C definition — and the image is checked with pyelftools:ET_EXEC,EM_AARCH64,ELFOSABI_SYSV, 0 undefined symbols, 0.relasections left, all 28 synth symbols present;blto a non-exported local, linear memory throughx28checked from both sides (synth stores, C readsbase+16; C writes, synth loads), globals in synth's own.datapersisting across calls,call_indirectthrough the emitted funcref table, a value below an import call's args (RQ-63-A64STACK),memory.size.Three execution legs, because the host is arm64-Darwin and honesty about the substrate matters:
e_entry) + the two syscalls servicedaarch64-oraclejob (x86-64),REQUIRE_QEMU=1arm64-linux-nativeonubuntu-24.04-arm,REQUIRE_NATIVE=1Each leg's stdout must be byte-identical to the unicorn leg's and match wasmtime. The native job is deliberately NOT a required check (a new runner pool must not be able to deadlock merges).
What it does NOT verify (written into the oracle, the doc, and the matrix row)
brk #0= SIGTRAP on Linux, which kills an unprepared process. Trap PLACEMENT stays gated by the sibling unicorn oracles; what the embedder does with SIGTRAP is its contract.-static, freestanding. Every relocation synth emits is PC-relative so-pieis plausible; it is not claimed.Red-first (measured)
Built into the oracle, run every time — each must be REFUSED by the linker with the linker's own words, exit != 0:
The mutation control flips one bit in the LINKED image (ADD-shifted-reg → SUB) and requires a reported mismatch — a check that cannot fail is not a check (#1113). Externally: pointing the oracle at a wrapper "synth" that ignores
-b aarch64and emits the EM_ARM object reddens it at its first gate (RED: synth compile failed/declined— the ARM path declines the fixture's f64 export and skips it; the oracle treats a skipping compiler as red before it ever links).Green transcript (arm64-Darwin host, rebuilt binary):
The precondition, stated (the #1131 rule)
docs/embedder-abi-relocatable-aarch64.md— every fact cited to the emittingfile:line, split fixed / chosen / incidental, pinned bySYNTH-EMBEDDER-ABI-RELOCATABLE-AARCH64-RQ64(16 evidence items binding the doc's sentences toselector.rs/backend.rs/elf.rs/substrate.rs/main.rs/ci.yml):x28= linear-memory (memory 0) base, set once before the first export; emitted code never writes it (LINMEM_BASE,selector.rs:181; the temp universe isx9..x15/v16..v23); anything called out to preserves it by AAPCS64. Two measured ways to keep it:-ffixed-x28+ set in startup (what the oracle runs), or a per-call asm trampoline. NOT from inline asm inside ordinary C.MemBounds::Software { limit_bytes: config.linear_memory_bytes },backend.rs:77-79) → the region atx28must be ≥initial_pages × 65536bytes and nothing can say otherwise;memory.sizeis the declared constant,memory.growis −1.__synth_globals,.data, initializers in the bytes) and the funcref table (__synth_func_table,.text) are EMITTED — not preconditions. Active data segments are REFUSED at compile time (backend.rs:259-275), so there is no--embedder-data-initpromise on this path.brk #0= SIGTRAP;--safety-bounds noneremoves the OOB trap entirely (compliance envelope).--target cortex-a53is the only target; the object carries nothing OS-specific (EI_OSABI0, no notes/PLT/GOT/TLS) — its "Linux-ness" is the SysV ELF64 container + AAPCS64, which is whatld.lld -m aarch64linuxconsumes. Only arm64-Linux is claimed, because that is what executes.NEGATIVE FINDING (measured, pinned, documented — not fixed here)
Two independently compiled synth aarch64 objects cannot be linked into one program. aarch64 emits
func_NGLOBAL (elf.rs:193,0x12); ARM emits it LOCAL since #656 for exactly this reason.Not fixed in this lane: it changes symbol-table ordering (
sh_info) in the ELF writer, and every aarch64 oracle's expectations should move with it under review. The workaround is executed by the oracle every run —llvm-objcopy --regex --localize-symbol='func_[0-9]+'on all but one object; co-link succeeds and all 17 values still match (the object's own intra-object relocations bind to the now-local symbols). The pin is bidirectional: the day the writer emitsfunc_NLOCAL,count-eqon the0x12line and the oracle's pinned refusal both go red until the doc's collision section is removed.Also in this PR
Link with: arm-none-eabi-ld … kiln_bridge.ofor aarch64 objects too; it now namesld.lld -m aarch64linuxand the x28 precondition (main.rs)..github/workflows/ci.yml:aarch64-oracleinstallslld clang llvm qemu-user-staticand runs the oracle withREQUIRE_QEMU=1(--min-oracles16 → 17); NEWarm64-linux-nativejob onubuntu-24.04-arm(assertsuname -m= aarch64 first,REQUIRE_NATIVE=1, grep on the native leg's ownokline).--exact-emulation-floor324845 → 324847 — RE-DERIVED bypython3 scripts/oracle_wiring_check.pyon the rebased tree (not added);SYNTH-ORACLE-CHECK-FLOORS-910-CIin lockstep.Gates run locally (rebased onto
8862ee2f, the merged v0.64 plan)claim_check.py claims.yaml --emit-status→ 60/60 claims holdoracle_wiring_check.py --exact-emulation-floor 324847→ exit 0 (189 scripts, 181 wired, 0 unwired)status_evidence_check.py→ 0 failures (R7-SKIP on the uncommitted artifact only)rivet validate→ 40 errors (main's baseline; the +24 warnings are plan(v0.64): scope the release — "The number you plan from" (9 artifacts, 4 carried) #1177's nine new artifacts)cargo fmt --checkclean;cargo clippy --workspace --all-targets -- -D warningsexit 0;cargo test -p synth-cligreen🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L