Skip to content

VCR-TIER-001 increment 1: canary gate over pseudo-op encoder expansions - #1061

Merged
avrabe merged 2 commits into
mainfrom
feat/vcr-tier-001-canary-gate
Aug 26, 2026
Merged

avrabe merged 2 commits into
mainfrom
feat/vcr-tier-001-canary-gate

Conversation

@avrabe

@avrabe avrabe commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

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_599 value 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-1048 at c2bc4235 (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

  1. Declared scratch contracts — expansion_scratch_contract in crates/synth-backend/src/arm_encoder.rs is 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-instance declared_temps hand column — which was already stale on this base: it still declared the shifts' r5 and the bit-counts' r3 as 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.
  2. The canary gate — scripts/repro/expansion_canary_gate_1021.py reuses the census's unicorn/capstone runner (execute() grew an ambient override; no second runner). Every ArmOp variant the shipped rule table emits (77 instances, completeness-gated against generated.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.
  3. CI wiring — # ci-status: wired, # ci-checks: emulations >= 1200 (measured 1386 via oracle_run.py), a step in the repro-sweep-selector-oracle job. oracle_wiring_check.py and claim_check.py both 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:

$ python3 scripts/repro/expansion_canary_gate_1021.py --dump scripts/repro/expansion_canary_1021_red_pre1039.json
dump leg: 77 instances, 19 pseudo variants
violations: I64Clz:['r3']; I64Ctz:['r3']; I64Popcnt:['r3']; I64Shl:['r4', 'r5']; I64ShrS:['r4', 'r5']; I64ShrU:['r4', 'r5']; Popcnt:['r11']
exit=1

Reserved-global tier (encoders at 708ae34b, pre-#1039): Popcnt clobbers r11, the linear-memory base — the #1021 mechanism — on both backends.

$ python3 scripts/repro/expansion_canary_gate_1021.py --dump scripts/repro/expansion_canary_1021_red_pre1054.json
dump leg: 77 instances, 19 pseudo variants
violations: I64Clz:['r3']; I64Ctz:['r3']; I64Popcnt:['r3']; I64Shl:['r4', 'r5']; I64ShrS:['r4', 'r5']; I64ShrU:['r4', 'r5']
exit=1

Caller-operand tier (encoders at origin/main c960903e, #1039 in / #1048 out): the shifts destroy their own amount registers (r4, r5), the bit-counts the operand's home hi (r3) — and Popcnt is 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

live leg: 77 instances, 19 pseudo variants (both backends, canaried)
live violations beyond contract: NONE
...
EXPANSION CANARY GATE: GREEN — every rule-emitted expansion is contract-clean on
both backends, and both negative-control tiers red exactly as pinned

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

  • The contract values are intent declarations by nature (a contract read off the bytes would rubber-stamp any clobber) — but the table is empty: no per-op hand entry exists today, every op sits on the strictest default, and the gate's unexercised-contract check bites any future over-declaration.
  • Hand-pinned: the fixtures' expected violation sets (measured from the old encoders' executed bytes at fixture creation, exact-equality asserted) and the representative operand choice in the dump example (pre-existing; no derivation can pick operands).

What this gate provably cannot cover

Housekeeping

  • cargo fmt / clippy --workspace --all-targets -D warnings / cargo test --workspace / python3 scripts/claim_check.py claims.yaml all green locally (exit codes gated).
  • Two prose ratchets (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.
  • No artifacts/release-v0.60.yaml exists 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

@avrabe
avrabe changed the base branch from main to fix/i64-shift-amt-clobber-1048 August 26, 2026 01:56
Base automatically changed from fix/i64-shift-amt-clobber-1048 to main August 26, 2026 03:47
avrabe and others added 2 commits August 26, 2026 05:48
…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
avrabe force-pushed the feat/vcr-tier-001-canary-gate branch from 33d431d to a5d35ca Compare August 26, 2026 03:48
@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/synth-backend/src/arm_encoder.rs 0.00% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@avrabe
avrabe merged commit 1f05893 into main Aug 26, 2026
61 checks passed
@avrabe
avrabe deleted the feat/vcr-tier-001-canary-gate branch August 26, 2026 06:50
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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant