fix(selector): RQ-65-DECLINE (#1208) — narrow i64 memory ops, i64 select and computed-condition value-if decline to the direct selector - #1228
Merged
Conversation
This was referenced Sep 9, 2026
avrabe
added a commit
that referenced
this pull request
Sep 9, 2026
…measured evidence, CHANGELOG entry The RQ-65-DECLINE artifact moves proposed -> implemented with `landed:` (what PR #1228 carries) and `verified-by:` (the per-defect classification, each justified by the direct selector's bytes and executed result for its own shape; the anchor, parity red-first, byte-identity, reach and ledger- sensitivity runs as actually executed). The emulation floor is referred to as re-derived by oracle_wiring_check, never restated (floor-prose 0). CHANGELOG [Unreleased] gains the entry under main's existing header. Refs #1208 #1213 #1205 #1204 #1206 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…ect and computed-condition value-if decline to the direct selector Three optimized-path miscompile classes RQ-65-PARITY found by executing the spec suite — every one exit 0, no warning — now decline with a machine reason in the #120/#372/#374 pattern; the direct selector's bytes were read for each shape and its executed results equal wasmtime, so each fallback is complete: - #1208 the nine narrow i64 memory forms (i64.load8/16/32_{s,u}, i64.store8/16/32): loads lowered to an EMPTY body (bx lr), stores dropped. The #372 guard is extended to the nine forms. - #1213 an i64 `select` (register-pair operands): Opcode::Select moves one register. The Select arm declines when a value operand is in `i64_halves`, fed by the one `push_i64` helper every pair producer now pushes through. - #1205 a value-`if` with simple arms and a COMPUTED condition: the select rewrite moved the condition past the arm values. `preprocess_wasm_ops` is now `Result` and declines instead. Classified, not landed, with measurements: #1204 (an unsaved R9-R11 write — the covering predicate diverts 0.9 % of optimized functions on the spec corpus but 5.3 % on scripts/repro, the memory-heavy shapes the optimized path exists for; the fix is the prologue save) and #1206 (loop-carried non-param local; class boundary not statable — sum_to_n has the shape and is correct). #1209/#1210/#1211/#1214/#1215 are wrong on both selectors and stay pinned. Evidence: the parity oracle on the new binary with the OLD table reports exactly the five pins as VANISHED (90+7+1+1+1 assertions -> ok, unpinned 0); the pins are removed here. Byte identity over 205 scripts/repro inputs x 3 ARM configs: one differing module (mem746_wide_static.wat: its three narrow-op functions + one Reset_Handler immediate tracking the grown .text); 0 newly declined in every config and on 221 local real modules. SYNTH-ARCH-LOUD-DECLINE re-pointed from the decoder's `fn is_intentionally_ignored` (green by construction while i64.load8_u lowered to bx lr) to the lowering layer: exact count of optimized-path decline sites (14) and of pinned optimized-path wrong answers in the parity oracle (4). Sensitivity proved by mutation (13 != 14, 5 != 4), restored. ARCHITECTURE.md's honesty sentence now states how it is enforced and what remains pinned. Refs #1208 #1213 #1205 #1204 #1206 #197 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…measured evidence, CHANGELOG entry The RQ-65-DECLINE artifact moves proposed -> implemented with `landed:` (what PR #1228 carries) and `verified-by:` (the per-defect classification, each justified by the direct selector's bytes and executed result for its own shape; the anchor, parity red-first, byte-identity, reach and ledger- sensitivity runs as actually executed). The emulation floor is referred to as re-derived by oracle_wiring_check, never restated (floor-prose 0). CHANGELOG [Unreleased] gains the entry under main's existing header. Refs #1208 #1213 #1205 #1204 #1206 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
force-pushed
the
fix/decline-1208
branch
from
September 9, 2026 04:02
4a6b655 to
960eb3f
Compare
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-65-DECLINE (#1208) — silent wrong answers on the optimized path become loud declines
Refs #1208, #1213, #1205 (declined), #1204, #1206 (classified, stay pinned), #1209 #1210 #1211 #1214 #1215 (class c, stay pinned), #1207 (acceptance bug). Artifact:
artifacts/release-v0.65/RQ-65-DECLINE.yaml(status: implemented; the file is also modified by #1219 — if that merges first, the rebase keeps both edits).The anchor, reproduced before anything was changed
Eleven one-op modules
(memory 1) (func (export "f") (param i32) ...), main binary (580d53f9), default vs--no-optimize, function bytes read from the ELF symtab:--no-optimize)i64.load8_s/u,load16_s/u,load32_s/u7047=bx lr, the whole body;[path-debug] optimized (ir_to_arm ok)ldrsb/ldrb/ldrsh/ldrh/ldr+ extend into r0:r1i64.store8/16/32(const or extended value)mov r1,r5; mov r0,r4; pop— no storestrb.w/strh.w/str.w r1,[fp,r0]i64.load/i64.storedirect (fallback: … issue #372), byte-equal to directAll eleven exit 0, no warning. On this branch all nine narrow forms are
direct (fallback: … issue #1208)and byte-equal to--no-optimize.Classification — every optimized-path-only defect, each by ITS OWN bytes and executed result
The coordinator's mid-task correction is honoured: the direct selector is not globally trustworthy (#1222 is on it), so no decline below rests on a blanket claim.
address.wastm1's 90 assertions execute equal to wasmtime on the direct legselectsel64_lomoves the PAIR underit ne/eq(movne r5,r1; movne r6,r2; moveq r5,r3; moveq r6,r4); probe (sel64_wrap,sel64_lox2) and specas-convert-operandequal to wasmtimeSelectarm declines when either value operand is ini64_halves, a set fed by the onepush_i64helper every pair producer now pushes through (no second type walk)if, computed conditionvif_gt=cmp r0,r1; ite gt; movgt/movle r2; cmp r2,#0; beq …— a real compare on the operands; probe shapesgt_s/add/eqz/mixed-arm and speccheck_jamx7,load.wast/local_tee.wastas-if-condequal to wasmtimepreprocess_wasm_ops, nowResult) declines instead of moving a non-zero-input condition past the arm values. Pattern 2 is unaffected (it re-emits the popped condition in place)scripts/repro— and those 19 arebase_cse_branch,redundant_base_materialization,spill_frame_499,stack_canary_687,volatile_segment_543, …: the memory-heavy shapes the optimized path exists for, several of them frozen goldens. Fix = the prologue save (ensure_callee_saved_prologuehard-codes R4–R8)countdown,countdown_set,countdown_nop_firsthang;countdown_paramandsum_to_n— same pre-loop-defined, in-loop-redefined local — are correct; none of the four lever opt-outs changes it. No statable predicate short of "every loop redefining a pre-loop local"None of the three landed declines can relocate a function into #1222's class:
has_wide_paramroutes every i64-param function to the direct selector BEFORE the bridge runs, so every re-routed function has no i64 param by construction.The pins moved — red-first, inherited
Parity oracle, main binary:
RESULT: PASS, 722 pinned assertions / 108 pins, 19145 assertions / 328 modules (main's table reproduced exactly; wasmtime-py 48.0.0, unicorn 2.1.4).New binary, OLD pin table: exit 1 with exactly five
PINNED DIVERGENCE VANISHEDlines —anti_pinch.wast m0 check_jam(pinned 7, #1205),load.wast m0 as-if-cond(1, #1205),local_tee.wast m0 as-if-cond(1, #1205),address.wast m1 *(90, #1208),select.wast m0 as-convert-operand(1, #1213) —unpinned: 0, every non-vacuity floor met (optimized_funcs 1211 >= 1150, differing_funcs 1423 >= 1350), 19145/19145 assertions over 328 modulesNew binary, edited table (the five pins removed): the discriminating subset on the rebased tree (
--only address,select,anti_pinch,local_tee,load, plus the untouched controlscontrol_*,r11_clobber,int_literals):unpinned: 0in every run, no moved pin, the remaining #1209/#1210/#1204/#1206/#539 pins in those files hold at exactly their counts; the full run is the CI job on the pushed treePopulation: optimized routing 1267 → 1211, fallback 1527 → 1583, byte-differing functions 1479 → 1423, verdict
ok12447 → 12547,parity-divergence158 → 58,contract-violation14 → 14 (#1204, untouched).Byte identity, proved not reasoned
Main binary vs branch over all 205
scripts/reproinputs, three ARM configurations:--relocatable(direct)--no-optimizeThe one difference is
mem746_wide_static.wat: its three narrow-op functions (narrow8,narrow16s,narrow32) plus ONEReset_Handlerimmediate —movw r0,#592→movw r0,#744(+0x98), which is exactly the.textgrowth 0x278 → 0x310 of those three bodies (the address of the #758 data-segment initializer blob that follows the code inside.text: blob start = text size - 0x28 on both binaries). Function counts are equal in every config.Reach, measured
No module and no function newly declines in any configuration — the fallback is per-function and the direct selector accepts every re-routed function. Denominators: 205 repro inputs × 3 configs (above), the parity corpus (2245 modules; routing above), and the real modules on this host: 221 loom/kiln/relay inputs — default config 37 identical / 0 differing / 0 newly declined (184 decline on BOTH binaries: import-carrying modules need
--relocatable),--relocatable23 / 0 / 0 (198 both-declined); function and fallback counts equal on both binaries. The 805-module corpus (#1017) is gale's and is not on this machine — stated, not estimated.The ledger pin that could not have failed
SYNTH-ARCH-LOUD-DECLINEbound "declines loudly" tofn is_intentionally_ignoredin the DECODER — one layer above the lowering that emittedbx lr. Re-pointed at the lowering layer: exact count of optimized-path decline sites inoptimizer_bridge.rs(14) and exact count of pinned optimized-path wrong answers in the parity oracle (4, the named residual). Sensitivity, run and restored:The ARCHITECTURE.md sentence now says how the rule is enforced and names what remains pinned.
Gates run before push
cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings, unit tests 7/7 bridge + 4/4 backend,oracle_wiring_check.py --exact-emulation-floor 345122(no script header changed; floor re-derives unchanged),claim_check.py62/62,status_evidence_check.py,rivet validate(40 errors — the main baseline, none new).🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L