Repository navigation
VCR-TIER-001 increment 1: canary gate over pseudo-op encoder expansions - #1061
Merged
Merged
Conversation
…tion site, derived into the census Each pseudo-op's encoder expansion now has a SCRATCH CONTRACT: the registers beyond its declared results (and the globally sanctioned R12) it may leave modified. `expansion_scratch_contract` in arm_encoder.rs is the single declaration site, next to the expansions it describes; the census dump example serializes it per instance (`scratch_contract`), replacing the example's per-instance `declared_temps` hand column — which was already stale: it still declared the shifts' rm_hi (r5) and the bit-counts' rnhi (r3) as clobberable temps after #1048 deleted exactly those writes, so a regression reintroducing the #1048 class would have been MASKED by the declarations that mirrored it. The contract table is EMPTY today — post-#1039/#1048 every rule-emitted expansion is R12-only on both backends (execution-measured, census re-run clean) — so every op carries the STRICTEST default, results only: precisely the silent claim the atomic ArmSemantics model makes, now stated where a gate can enforce it. A missing declaration in a dump defaults the same way. census: `execute()` grows an `ambient` override so the canary gate (next commit) reuses the same unicorn runner instead of writing a second one. Refs #242, Refs #1021, Refs #1048. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…sion executed under canaries, two-tier negative controls on every run
scripts/repro/expansion_canary_gate_1021.py (ci-status: wired, emulations
>= 1200; measured 1386) executes every ArmOp variant the shipped rule table
emits — real Thumb-2 AND A32 encoder bytes, unicorn, every non-operand
register holding a distinctive canary (R11 = 0xB11B11B1) over the census
valuations including the non-fixed-point shift amount — and asserts nothing
outside {declared results} ∪ {scratch contract} ∪ {R12} moved, SP restored,
memory confined to the expansion's own stack red-zone, full capstone decode,
and that no declared contract register goes unexercised (an over-broad
contract cannot hollow the gate). The census's unguarded-clobber set is
thereby pinned at EMPTY — stronger than the "does not grow" its header
promised for this increment.
Potency is proven on EVERY invocation, on BOTH register tiers, because one
red from one tier is exactly what i64_shr_599 already had while being
structurally blind to #1048: the committed fixtures carry the REAL old
encoders' bytes (generated in worktrees, no byte hand-written) and must red
on exactly the pinned registers —
pre-#1039 (708ae34): Popcnt:{r11} reserved-global tier (#1021)
+ i64 shifts {r4,r5} / bit-counts {r3}
pre-#1054 (main): i64 shifts {r4,r5} / bit-counts {r3} caller-operand
tier (#1048), and Popcnt must NOT red — the gate
discriminates the #1039 fix, not merely "old is bad"
Observed == pinned is exact in both directions; a drift either way exits 1.
Doctored-fixture negative test (clean HEAD bytes swapped in): POTENCY FAILED
fires as designed.
Known not covered, stated: register-ALIASING-dependent defects (one
non-aliased operand assignment per shape), CPSR/flag effects, and clobbers
gated on values outside the three census valuations.
Refs #242, Refs #1021, Refs #1048.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
force-pushed
the
feat/vcr-tier-001-canary-gate
branch
from
August 26, 2026 03:48
33d431d to
a5d35ca
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
avrabe
added a commit
that referenced
this pull request
Aug 26, 2026
Five artifacts. Both halves of the theme were EARNED during v0.59 rather than asserted, which is why this file leads with the evidence: RQ-60-CANARY VCR-TIER-001 increment 1 (delivered, PR #1061). Its immediate finding is the theme's best argument: the census's OWN hand-maintained `declared_temps` column declared the #1048 miscompile LEGAL — `&[R5]` (rm_hi) for the i64 shifts, `&[R3]` (rnhi) for the bit-counts, exactly the registers the defect clobbered. A checker that mirrors the defect it exists to catch. RQ-60-CFOBLIG #1057 (gale). 48% of a real object is covered by NEITHER proof half, and the cause is one level deeper than the issue could see: `Inductive wasm_instr` has NO control-flow constructor at all. There is no obligation for `BrIf` because the model has no `BrIf`. Verified before scoping — gale asked to be corrected and was right to. RQ-60-A64IMPORT VCR-REACH-002. AArch64 accepts 13/805 real modules (1.6%). Import dispatch (~121 modules) is synth's OWN ARM `--relocatable` undefined-symbol design ported, so it is a port of a shipped pattern, not a design question. RQ-60-RACOST VCR-RA-011. Cost model + tied operands, NOT a better search — with the ruled-out alternatives recorded so they are not re-litigated. RQ-60-ARTIFACTSPLIT #1059. The single-file artifact write surface that silently dropped a trace link during the v0.59 wave. Validated with the TYPED oracle, not a permissive one — the lesson from the v0.59 corruption this file's last artifact is about: rivet validate: OURS=0 (main baseline 0; rivet FAILs on main by construction) duplicate-key-STRICT loader: 5 artifacts, no duplicate ids structural: every artifact carries its own links: and a non-empty issue: release field consistent: {v0.60} The structural check is the mitigation RQ-60-ARTIFACTSPLIT proposes, run here by hand against this file. Refs #1021, Refs #1057, Refs #1017, Refs #242, Refs #1059 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
Aug 26, 2026
…rtifacts (#1070) * plan(v0.60): scope the release — "Derive what you check against" Five artifacts. Both halves of the theme were EARNED during v0.59 rather than asserted, which is why this file leads with the evidence: RQ-60-CANARY VCR-TIER-001 increment 1 (delivered, PR #1061). Its immediate finding is the theme's best argument: the census's OWN hand-maintained `declared_temps` column declared the #1048 miscompile LEGAL — `&[R5]` (rm_hi) for the i64 shifts, `&[R3]` (rnhi) for the bit-counts, exactly the registers the defect clobbered. A checker that mirrors the defect it exists to catch. RQ-60-CFOBLIG #1057 (gale). 48% of a real object is covered by NEITHER proof half, and the cause is one level deeper than the issue could see: `Inductive wasm_instr` has NO control-flow constructor at all. There is no obligation for `BrIf` because the model has no `BrIf`. Verified before scoping — gale asked to be corrected and was right to. RQ-60-A64IMPORT VCR-REACH-002. AArch64 accepts 13/805 real modules (1.6%). Import dispatch (~121 modules) is synth's OWN ARM `--relocatable` undefined-symbol design ported, so it is a port of a shipped pattern, not a design question. RQ-60-RACOST VCR-RA-011. Cost model + tied operands, NOT a better search — with the ruled-out alternatives recorded so they are not re-litigated. RQ-60-ARTIFACTSPLIT #1059. The single-file artifact write surface that silently dropped a trace link during the v0.59 wave. Validated with the TYPED oracle, not a permissive one — the lesson from the v0.59 corruption this file's last artifact is about: rivet validate: OURS=0 (main baseline 0; rivet FAILs on main by construction) duplicate-key-STRICT loader: 5 artifacts, no duplicate ids structural: every artifact carries its own links: and a non-empty issue: release field consistent: {v0.60} The structural check is the mitigation RQ-60-ARTIFACTSPLIT proposes, run here by hand against this file. Refs #1021, Refs #1057, Refs #1017, Refs #242, Refs #1059 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * plan(v0.60): fix the schema — this file had the #1064 defect I filed I wrote release-v0.60.yaml by copying v0.59's shape, so it carried the exact defect #1064 is about: top-level `metadata:` + `requirements:` instead of `artifacts:`. rivet's generic-yaml DENIES unknown top-level fields, so the whole file was skipped with a WARN carrying no `ERROR:` prefix. Which means my own validation of this file was VACUOUS. I ran `rivet validate`, got OURS=0, and reported it clean — but rivet had skipped the file entirely. Zero errors from a file that never loaded is not zero errors. Same shape as #1012 one level up, and the reason #1064's fix pins a FLOOR on artifacts loaded rather than only grepping for errors: a validator doing LESS work must fail, not pass quietly. Converted metadata: -> comments (v0.58's shape), requirements: -> artifacts:. Verified BY ID rather than by absence of an error — the distinction that hid this in the first place: RQ-60-CANARY -> RQ-60-CANARY (system-req) [proposed] RQ-60-CFOBLIG -> RQ-60-CFOBLIG (system-req) [proposed] RQ-60-A64IMPORT -> RQ-60-A64IMPORT (system-req) [proposed] RQ-60-RACOST -> RQ-60-RACOST (system-req) [proposed] RQ-60-ARTIFACTSPLIT -> RQ-60-ARTIFACTSPLIT (system-req) [proposed] CI-filter OURS = 0. Artifact count on this branch 447 -> 452 (+5); once #1065 lands the v0.59 fix the same 5 lift 463 -> 468, so this PR must raise ARTIFACT_FLOOR to 468 when it rebases onto #1065. All 5 already derive-from BR-001 (the correct stakeholder-req type), so unlike v0.59 no link retargeting is needed. Refs #1064 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * plan(v0.60): triage RQ-60-WCETKEY (#1063) — the hints seam has no key for internal functions gale (fathom) measured it on the E2 dissolved gust:os composite: synth-wcet-v1 takes its `name` from the EXPORT SECTION and falls back to `func_<index>` for every internal function, so 7 of 13 `loop` declines cannot be hinted at all — and `loop` is 13 of 28 declines with 11 `callee-unbounded` cascades behind it. WORSE THAN "NOT HINTABLE": a hint keyed on `func_22` SILENTLY RETARGETS when an edit shifts the index space. It still parses and still keys onto a function — just not the one the author verified. synth always emits its own DERIVED ceiling rather than the raw hint, so the bound stays synth-derived; what a mis-keyed hint corrupts is the OPT-IN, converting a decline for a function whose shape nobody looked at. An index is not an identity. gale pre-empted the obvious dismissal: rebuilding with `meld fuse --preserve-names` yields a BYTE-IDENTICAL .wcet.json while populating the name section 0 -> 59 of 68. synth carries the names and ignores them. Recorded with the caveat they volunteered, because it must shape the design: the names are v2 Rust mangling carrying a NON-content-derived crate disambiguator, and scry measured 43-45% of their function identities churning per build for exactly that reason (scry#123/#137). Better than an index, still not stable — fixing the blocker with a key that churns every build would trade an unaddressable decline for an unreliable one. Their kill-criterion adopted verbatim: a hints file keyed on the name-section name of one of those seven converts its `loop` decline to `hint-verified`, or is rejected with a NAMED reason. Being ignored because the key never matches is the failure. Validated the way #1064 taught — BY ID, not by absence of an error: all 6 v0.60 artifacts resolve via `rivet validate --explain`; CI-filter OURS=0; duplicate-key-strict loader clean; every artifact carries its own links: and issue:. Refs #1063 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * plan(v0.60): RQ-60-FLIPCOUPLE — three orphaned status flips in one supervised release Measured on v0.59, in a release where I was EXPLICITLY watching for this class because v0.58 had been burned by it: RQ-59-TIERCENSUS #1047 merged; no open PR flipped it RQ-59-GLOBALINIT #1058 merged; no open PR flipped it RQ-59-PARTIALCENSUS #1051 merged and did not flip its OWN status All three caught by hand and folded into unrelated PRs. Three misses in one supervised release is a coupling problem, not an attention problem: nothing mechanically ties "the code landed" to "the artifact says so". It fails SILENTLY and in the direction that looks like LESS work — a stale `proposed` makes v0.58's release-readiness query under-report scope at the cut, so a shipped artifact can be omitted from the notes and the evidence package. The compounding factor is why this is not just "add a checklist": #1064 showed the v0.59 file was never LOADED by rivet, so for most of the release the readiness query could not have caught a stale status even if run. The two defects hid each other — the file was invisible, so the statuses inside it were unfalsifiable. Three candidate fixes recorded with their tradeoffs rather than one asserted; deriving status from evidence is most in keeping with this release's theme, a CI check that a MERGED-PR artifact is not still `proposed` is the cheapest thing that would have caught all three. Kill-criterion: replay v0.59's three misses — a fix that would not have caught all three has not addressed the measurement. Validated BY ID: RQ-60-FLIPCOUPLE resolves; CI-filter OURS=0. Refs #1064 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * plan(v0.60): RQ-60-VFPPRESSURE (#1069) — three named functions block a complete falcon M7 cascade jess filed it with a fully public repro and measured it on a real RT1176 Renode model (memory byte-exact, 214,696 instructions retired). 2 of 5 cascade stages export; the loop cannot close on target without the other three. VERIFIED ALL THREE CLAIMS against current code before scoping — they measured 0.55.0, we shipped 0.59.0: * the S pool IS `[bool; 16]` = S0..S15; callee-saved S16..S31 / D8..D15 are absent and would roughly double it * NO __aeabi_ul2f/l2f/ul2d/l2d routing exists anywhere; #869's acceptance comment described exactly that route and inline-f64 shipped instead * has_double_fpu() gates f64 on FPUPrecision::Double, i.e. m7dp only REPRODUCED ON 0.59.0, minimal case sharper than the cascade: (func (param i64) (result f32) (f32.convert_i64_u (local.get 0))) m4f -> DECLINED "scalar f64 requires a double-precision FPU target" m7dp -> compiles A function with NO f64 in its signature is refused for needing f64, because our own lowering introduces it. A reach failure of our own making. HONEST RESIDUAL IN MY OWN VERIFICATION, recorded so a lane does not inherit a false premise: sub-problem 1 (S-exhaustion) is confirmed by CODE INSPECTION ONLY. My deep-f32 fixture compiled fine at 60 bytes — not deep enough to exhaust S0..S15. A lane must build a fixture that actually reddens phase 1 before claiming to fix it. Refs #1069, Refs #869 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * ci(#1064): raise ARTIFACT_FLOOR 464 -> 472 for v0.60's 8 artifacts The gate's own rule: a PR that ADDS artifacts raises the floor in the SAME PR, so every movement is a visible diff. 464 (main) + 8 (release-v0.60.yaml) = 472, measured under the job's own conditions rather than assumed. Re-verified the guard is still POTENT at the new value rather than assuming potency carried over — a raised gate that no longer fires is worse than the omission it was raised for: GREEN: measured=472 floor=472 RED : reintroduce the #1064 metadata:/requirements: schema defect -> measured drops below 472 -> FIRES 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>
avrabe
added a commit
that referenced
this pull request
Aug 26, 2026
…d 5th orphaned flips RQ-60-FLIPCOUPLE is now demonstrating itself. That artifact was filed BECAUSE three status flips were orphaned in v0.59; here are two more, in the release that scopes the fix: RQ-60-CANARY its work SHIPPED IN v0.59.0 (#1061, tag-verified) — the artifact was written describing already-delivered work and landed as `proposed` anyway RQ-60-A64IMPORT #1071 merged minutes ago and did not flip its own status Verified ON MAIN rather than inferred from the merge list: expansion_canary_gate_1021.py present, 1 CI invocation, `git tag --contains` reports v0.59.0 aarch64_import_dispatch_1017_differential.py present, 1 CI invocation ALSO TIGHTENED THE FLOOR 472 -> 473. #1071 added SWVER-025 without raising it. A floor only fails BELOW itself, so 473-measured against 472-pinned would have passed QUIETLY — slack, not red. The gate's own rule is that a PR adding artifacts raises the floor in that PR, and leaving it loose is the first crack in the discipline the gate exists to create. That is the same failure shape twice in one commit: a number that drifts in the direction that still looks green. Both are exactly what RQ-60-FLIPCOUPLE is scoped to make mechanical instead of vigilant. Verified BY ID: both resolve `[implemented]`; CI-filter OURS=0; measured 473 = floor 473; claim_check exit 0. Refs #1064, Refs #1017, Refs #1021 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
Aug 27, 2026
…d 5th orphaned flips, plus a floor left slack (#1074) * chore(rivet): RQ-60-CANARY + RQ-60-A64IMPORT implemented — the 4th and 5th orphaned flips RQ-60-FLIPCOUPLE is now demonstrating itself. That artifact was filed BECAUSE three status flips were orphaned in v0.59; here are two more, in the release that scopes the fix: RQ-60-CANARY its work SHIPPED IN v0.59.0 (#1061, tag-verified) — the artifact was written describing already-delivered work and landed as `proposed` anyway RQ-60-A64IMPORT #1071 merged minutes ago and did not flip its own status Verified ON MAIN rather than inferred from the merge list: expansion_canary_gate_1021.py present, 1 CI invocation, `git tag --contains` reports v0.59.0 aarch64_import_dispatch_1017_differential.py present, 1 CI invocation ALSO TIGHTENED THE FLOOR 472 -> 473. #1071 added SWVER-025 without raising it. A floor only fails BELOW itself, so 473-measured against 472-pinned would have passed QUIETLY — slack, not red. The gate's own rule is that a PR adding artifacts raises the floor in that PR, and leaving it loose is the first crack in the discipline the gate exists to create. That is the same failure shape twice in one commit: a number that drifts in the direction that still looks green. Both are exactly what RQ-60-FLIPCOUPLE is scoped to make mechanical instead of vigilant. Verified BY ID: both resolve `[implemented]`; CI-filter OURS=0; measured 473 = floor 473; claim_check exit 0. Refs #1064, Refs #1017, Refs #1021 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * chore(rivet): RQ-60-VFPPRESSURE implemented — the SIXTH orphaned flip #1073 merged as e6a3b27 and did not flip its own status. That is three in v0.59 and now three in v0.60, in the release whose RQ-60-FLIPCOUPLE artifact exists to fix exactly this. Verified ON MAIN, not inferred: 8 `__aeabi_ul2f`/`__aeabi_f2lz` references in crates/synth-synthesis/src/, and scripts/repro/aeabi_i64_float_1069_differential.py present. Six for six, every one caught by querying AFTER the merge rather than by any mechanism. That is the argument for RQ-60-FLIPCOUPLE stated as data rather than as a worry: a discipline that depends on somebody remembering fails on the tick they do not. Verified BY ID: CANARY / A64IMPORT / VFPPRESSURE all `[implemented]`; CI-filter OURS=0; measured 473 = floor 473; claim_check exit 0. Refs #1064, Refs #1069 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * fix(rivet): RQ-60-VFPPRESSURE back to `proposed` — my flip was PREMATURE I flipped it mechanically on "#1073 merged" without reading the artifact's own DEFINITION OF DONE: those three symbols reaching `nm -> T` — 5 of 5 stages exported Increment 1 did not achieve that. It cleared `position#tick` on single-precision cortex-m7; on **m7dp — jess's actual flight core — all three symbols still fail on main**. Increment 2 (#1075, open) is what delivers 5/5. The flip belongs there. This is the MIRROR of the orphaned-flip class I have been chasing all release. Six times I caught a status left `proposed` over shipped code; here I set one to `implemented` over code that had not shipped the thing the artifact promises. Both directions under-report the truth, and RQ-60-FLIPCOUPLE should derive status from EVIDENCE precisely so neither is a judgement call — "the PR merged" is not the same claim as "the artifact's stated outcome holds". ALSO: increment 2's written plan is marked RETIRED BY MEASUREMENT rather than deleted, so it is not re-proposed. The plan was "extend the S pool into callee-saved S16..S31". A discriminating variant — same pressure, different RESIDENCE — showed the wall is not capacity: 60 simultaneously-live f32 on the OPERAND STACK compile while 14 in HOMED LOCALS do not. Pool extension moves the wall 13 -> ~29: a bigger number and the same wall further out, paid with prologue/epilogue push/pop. Recorded because a retired plan that leaves no trace gets proposed again. v0.60 reads 2/8; VFPPRESSURE lands with #1075. CI-filter OURS=0, measured 473 = floor 473, claim_check exit 0. Refs #1069, Refs #1064 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 was referenced Aug 27, 2026
avrabe
added a commit
that referenced
this pull request
Aug 27, 2026
…n the failure they define (#1090) Both `done-when` predicates certified that code EXISTS. Neither artifact's claim is that code exists. RQ-60-A64IMPORT. Its description says, in capitals: "HONESTY REQUIREMENT: the acceptance number is the deliverable ... A change that adds a code path without moving the census has not delivered." Its signature was `contains:crates/synth-backend-aarch64/src/elf.rs:undefined_externals` — a code-existence check, i.e. precisely what the description says is NOT the deliverable. A predicate that cannot fail on the failure the artifact defines for itself is not a predicate. The status stays `implemented` — #1071's code is on main and EXECUTES (ld.lld links the objects against assembled definitions; unicorn runs the linked images: run(37)=42 through the import, table dispatch slot0 41->42 and slot1 21->42) — but the BASIS is now written where the release- readiness query's reader sees it, and it states the negative too: the AArch64 ACCEPTANCE RATE IS UNMEASURED since #1071. The 805-module corpus is not synth-local; the re-run is requested at #1017 and is named as increment 2 rather than quietly dropped. The v0.60 release notes assert no reach improvement. RQ-60-CANARY. Signature moves from `arm_encoder.rs:expansion_scratch_contract` (a function name) to the canary gate's own NON-VACUITY FLOOR, `scripts/repro/expansion_canary_gate_1021.py:emulations >= 1200`. The artifact's claim is that every rule-emitted expansion is EXECUTED with non-contract registers canaried; the old predicate would still hold with the gate deleted, and could never see the gate quietly emptied — the vacuity shape #910 exists for. SENSITIVITY PROVEN, not assumed: dropping the gate's floor from 1200 to 0 (needle counted == 1 before mutating) takes status-evidence from 0 failures to 1, naming RQ-60-CANARY. Restoring it returns 0. Also records `shipped-in: v0.59.0` on CANARY. Measured: the canary gate merged as #1061 at 08:50 on 2026-08-26, v0.59.0 was tagged at 15:19 the same day (so the gate is an ANCESTOR of that tag, and v0.59.0's notes already credit it), and the v0.60 plan was written at 18:56 — AFTER the tag — scoping as future work something already released. v0.60 carries this artifact's traceability closure, NOT the capability, and the notes say so. Every gate passed throughout, because each asks whether the declared evidence EXISTS and none asks which release it arrived in. Found by auditing all eight v0.60 artifacts against the bar each one's own description sets; three of eight pinned a `contains:` on an implementation path where the stated bar was measured or executed (the third, RQ-60-ARTIFACTSPLIT, was fixed in #1084). The proposed rules are R7 (evidence must belong to the release) and R9 (a `contains:` into `crates/**` is weaker than one pointing at the gate that exercises it) — both in #1085, neither implemented here. Gates: status-evidence 0 failures (60 artifacts / 5 files / 8 predicates), claim_check 51/51, 24 tests OK. Refs #1085, refs #1017, refs #1021. 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.
VCR-TIER-001 increment 1 — the enforcing gate over RQ-59-TIERCENSUS's findings, wired into CI. 52 of the 80 Rocq-proved rules emit a pseudo-op whose multi-instruction encoder expansion the proof never sees; an atomic model of such an expansion is a silent claim that the expansion is scratch-free. That claim shipped false twice, on two register tiers (#1021 R11, #1048 operand homes) — and the wired
i64_shr_599value differential passed on the miscompiling binary, because the value tier is structurally blind to the class. This gate checks the claim itself, by execution.Refs #242, Refs #1021, Refs #1048.
Base
Based on
origin/fix/i64-shift-amt-clobber-1048atc2bc4235(PR #1054, OPEN at branch time) — #1054 rewrites the same expansion surfaces this gate executes, so basing off main would both conflict and gate the unfixed bytes. Merge #1054 first; this PR then lands the gate that keeps its class closed.What landed — extend, not rebuild
expansion_scratch_contractincrates/synth-backend/src/arm_encoder.rsis the single declaration site, next to the expansions: the registers beyond{declared results} ∪ {R12}an expansion may leave modified. The census dump example serializes it (scratch_contract), replacing its per-instancedeclared_tempshand column — which was already stale on this base: it still declared the shifts'r5and the bit-counts'r3as clobberable after RQ-59-I64SHIFT (#1048): i64 shift/bit-count expansions destroyed their own operands — R12-only rewrite on both backends, operand-preservation now checker-visible #1054 deleted exactly those writes, so a regression reintroducing the thumb-2 + a32: i64 variable-shift expansions CLOBBER the shift-amount pair (in-place '& 63' mask + amt-32 into the home high register) — re-reading the amount after i64.shl/shr_u/shr_s returns a mangled value, both selectors (execution-confirmed) #1048 class would have been masked by the declaration that mirrored it. A pseudo-op with no declaration defaults to results-only — the strictest reading, the same claim the atomic model makes.scripts/repro/expansion_canary_gate_1021.pyreuses the census's unicorn/capstone runner (execute()grew anambientoverride; no second runner). EveryArmOpvariant the shipped rule table emits (77 instances, completeness-gated againstgenerated.rs) is executed on both Thumb-2 and A32, real encoder bytes, all non-operand registers canaried (R11 = 0xB11B11B1, one recognizable value per register) over the census valuations incl. the non-fixed-point shift amount. Asserted per instance/backend: nothing outside{results} ∪ {contract} ∪ {R12}moved; SP restored; memory confined to the expansion's own stack red-zone (a store through a corrupted base faults on the unmapped canary address); full capstone decode; and no declared contract register goes unexercised — an over-broad contract cannot hollow the gate.# ci-status: wired,# ci-checks: emulations >= 1200(measured 1386 viaoracle_run.py), a step in therepro-sweep-selector-oraclejob.oracle_wiring_check.pyandclaim_check.pyboth green.Potency — two reds, two tiers, re-proven on every CI run
The committed fixtures hold the real old encoders' bytes (generated in worktrees at the named commits; no byte hand-written), and the gate's default invocation requires them to red on exactly the pinned registers, both directions. Literal output:
Reserved-global tier (encoders at
708ae34b, pre-#1039):Popcntclobbers r11, the linear-memory base — the #1021 mechanism — on both backends.Caller-operand tier (encoders at
origin/mainc960903e, #1039 in / #1048 out): the shifts destroy their own amount registers (r4, r5), the bit-counts the operand's home hi (r3) — andPopcntis absent: the gate discriminates the #1039 fix rather than redding everything old.A third negative control on the checker itself: swapping a fixture's instances for clean HEAD bytes makes the run exit 1 with
POTENCY FAILED on caller-operand tier ... expected exactly ... observed NONE— the potency assertion can itself fail.Green leg and the derived unguarded set
The census's unguarded-clobber set is pinned at EMPTY — stronger than the "does not grow" its header promised (header updated to point at this gate). Census re-run on this base: 80 rules, 52 pseudo-emitting, 19 pseudo variants, r12-only net clobbers everywhere, all four headline sets NONE.
Hand-written vs derived
What this gate provably cannot cover
rd == rmis outside the instance table. Extending shapes over aliased assignments is a named follow-up, not silently claimed.SetCondconsumers read flags immediately after.ArmOpexpansions are the value-tier differentials' territory.Housekeeping
cargo fmt/clippy --workspace --all-targets -D warnings/cargo test --workspace/python3 scripts/claim_check.py claims.yamlall green locally (exit codes gated).mirror_marker_files,mirror_obligation_files) initially caught my comments using the words "mirrored"/"second source of truth"; reworded rather than waived — the ceilings did not move.artifacts/release-v0.60.yamlexists yet; the rivet entry for this increment is left to the coordinator's v0.60 planning file rather than creating the release file from a lane.🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L