Skip to content

Make the evidence say what it measures: scope the coverage number, assert what the oracles actually execute (#910) - #918

Merged
avrabe merged 11 commits into
mainfrom
lane/v055-l5-evidence-scope
Aug 6, 2026
Merged

Make the evidence say what it measures: scope the coverage number, assert what the oracles actually execute (#910)#918
avrabe merged 11 commits into
mainfrom
lane/v055-l5-evidence-scope

Conversation

@avrabe

@avrabe avrabe commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

v0.55 lane L5. Chose options (2)+(3) from #910 and declined (1) with reason: instrumenting the binary the differentials run changes the artifact under test — those oracles exist to execute the shipped bytes — and it buys precision on an axis that is still the wrong completeness instrument.

(2) Scope the number honestly

Code CoverageRust-test Line Coverage (unit + integration only). Verified first that it is NOT one of main's 9 required contexts (renaming a required one deadlocks merges). The scope caveat is placed in three surfaces that travel with the number — job body, $GITHUB_STEP_SUMMARY, README badge — and pinned in claims.yaml so it cannot be dropped while the number stays quotable.

(3) Assert what the oracles execute

scripts/oracle_run.py — an in-process (runpy) driver wrapping unicorn.Uc.emu_start, wasmtime.Func.__call__ and subprocess synth … compile. 159 CI step lines routed; no harness edited. Chosen over 152 bespoke greps, because 152 patterns mirroring 150 harnesses' output strings is the drift shape this repo keeps paying for.

Aggregate now asserted: 133 oracles → 294,914 emulator entries per CI run; 7 assert a printed count (458); 9 assert compilations (43); 1 binds to nothing. Reported per mode, never summed — three different units. Ratcheted by oracle_wiring_check.py --min-emulation-floor 294914 inside the already-required Claim Check.

F10 — the premise was understated

Not the 63 oracles #890 wired: 152 of the 160 steps that run a repro oracle asserted only the exit code, pre-#890 hand-wired steps included. Exactly 8 asserted a verdict or count.

Mutation evidence — 7 legs, all red

The load-bearing one: M1 makes a harness return before its comparison loop. It still prints ORACLE: PASS and still exits 0 → measured 0 emulations → RED. A grep -q "ORACLE: PASS" would have greened it, and so would all 152 exit-only steps. Also: floor lowered → ratchet red; header deleted → red; stdout regex without a capture group → red; a routed step demoted to a comment → red (re-proves v0.54's run: | strip under 159 rewritten bodies); steps un-routed → claims count-min red; short job ledger → red.

Calibration was measured, not assumed — every floor derived by executing each CI step verbatim out of ci.yml. Four self-reporting oracles agree 1:1 (#846 CHECKS=75/75→75, 35 checks (23 trap, 12 value)→35, 17 checks→17, 662 float-boundary→662).

Honest caveat about our own headline

trunc_sat_782 (192,672) + i64_float_conv_869 (96,276) = 288,948 of the 294,914. The other 131 oracles contribute ~5,900, median floor ~12. The number is literally true and per-mode honest, but read as surface strength it would mislead the way the coverage percentage did. Stated in ORACLE_WIRING.md.

Weak floors, itemized rather than averaged away

aarch64_matrix.sh (none — POSIX shell); i64_param_518_riscv_loudskip.py and postlink_359_oracle.py (compiles >= 1 — a loud-skip contract and a link-layout assertion, neither executes by design); five fact_spec_* (compiles >= 2 — each has an --expect-decline leg emulating nothing); call_indirect_275_selfcontained_differential.py (compiles >= 4); the #275 RED step deliberately not routed (it inverts its verdict).

Gates

Lane lost clippy/test/frozen to a full disk mid-flight and correctly did not claim green. Re-verified by the coordinator on a clean worktree: cargo test --workspace exit 0, 130 suites · fmt --check 0 · claim_check 0 · oracle_wiring_check 0 · ci.yml parses. Also checked the risk the lane flagged — no Rust code reads the rewritten .py files or ci.yml (the four scripts/repro reads are all .wasm fixtures).

First CI run is the real calibration: floors were measured on darwin with --features verify; most oracle jobs are ubuntu without it. If a step lands below its floor, lower that script's # ci-checks: header, then --min-emulation-floor and the two pinned copies — never the ratchet alone.

Closes #910.

avrabe added 6 commits August 5, 2026 18:02
Traceability leads the lane. VG-001..VG-008 all say "a property is not yet
proven"; these two say something different in kind — an instrument REPORTS
something other than what its name implies, and the measurement itself is the
defect.

VG-009 (#910): `Code Coverage` runs `cargo llvm-cov --workspace`, i.e. the Rust
test suite. The execution differentials spawn the compiler as a separate,
UNINSTRUMENTED process from different CI jobs, so every one of those executions
is invisible to the percentage — it understates real testing AND cannot be read
as completeness. Records the v0.54.0 measurement and the decline of #910
option 1 with its reason (instrumenting the binary changes the artifact under
test; the differentials exist to execute the SHIPPED bytes).

VG-010 (#910 F10): measured — 152 of the 160 workflow steps that run a
scripts/repro/ oracle assert nothing beyond the process exit code. Not only
the 63 wired by #890; the pre-existing hand-wired steps too. Exactly 8 assert
a printed verdict or count.

Both carry the RESOLUTION TAKEN so the artifact states the shipped decision,
not just the complaint.
`Code Coverage` -> `Rust-test Line Coverage (unit + integration only)`. The old
name implied whole-system coverage; the job runs `cargo llvm-cov --workspace`,
i.e. one population — the Rust test suite, in-process.

The scope note travels WITH the number in three places, because a caveat that
lives somewhere else does not survive being quoted:

  * the job body, for whoever edits it;
  * `$GITHUB_STEP_SUMMARY`, so reading the percentage and reading the caveat are
    the same act;
  * the README, under the badge.

All three say the same two things: the number UNDERSTATES the testing that
exists (the differentials run an uninstrumented subprocess from other jobs, so
`backend.rs` reads ~42 % while being exercised end-to-end by nearly every
differential), and it is NOT a completeness measure.

Verified before renaming that `Code Coverage` is NOT among main's 9 required
status checks — renaming a required context deadlocks every merge until branch
protection is updated, which is a coordinator decision, not a lane one.

  gh api repos/pulseengine/synth/branches/main/protection/required_status_checks
    --jq '.contexts'
  ["Format","Clippy","Test","Z3 Verification","Claim Check",
   "Version Pin Sweep","Bazel Build & Proofs","Kani Verification",
   "Rivet Validation"]

No emitted byte moves; 37/37 claims still hold.
Measured first, because the premise was understated: not 63 but **152 of the
160 workflow steps** that run a `scripts/repro/` oracle asserted nothing beyond
the process exit code. Exactly 8 asserted a printed verdict or count — and the
pre-#890 hand-wired steps are mostly in the bare 152 too.

Exit 0 does not distinguish "emulated 240 vectors, all bit-identical" from
"the fixture list came back empty, printed PASS". That is #890's inert gate one
level down: wired, but what it attests is unstated.

MECHANISM — `scripts/oracle_run.py`, an in-process driver (runpy) that wraps
three entry points and counts them:

    unicorn.Uc.emu_start          -> emulations
    wasmtime.Func.__call__        -> wasmtime_calls
    subprocess `synth … compile …` -> compiles

The count comes from the emulator, not from the harness's own bookkeeping, so a
comparison loop that never runs cannot fake it. Chosen over 152 bespoke greps
because it is uniform and needs no edit to any harness; chosen over #910
option 1 (instrumenting the binary) because that changes the artifact under
test.

DECLARATION — one `# ci-checks:` header per oracle, same locality argument as
`# ci-status:`: the floor lives in the file it describes and cannot outlive it.
Floors are `>=`, never equality, so adding a fixture cannot redden a step.

CALIBRATION, not assumption — every floor below is a MEASURED value, obtained
by executing each CI oracle step VERBATIM (parsed out of ci.yml, so there is no
transcription drift) with the invocation routed through the driver. Four
oracles that self-report a check count agree with the driver 1:1:

    gpio_thin_846            prints `#846 CHECKS=75/75`   driver 75
    aarch64_call_indirect_851 prints `35 checks (23 trap, 12 value)` driver 35
    aarch64_globals_851      prints `17 checks`           driver 17
    aarch64_float_completion_851 (the "662 float-boundary checks")  driver 662

150 wired oracles now declare:

    emulations  133 scripts   294,914 emulator entries asserted
    stdout        7 scripts       458 printed counts asserted
    compiles      9 scripts        43 compilations asserted
    none          1 script   aarch64_matrix.sh — a POSIX shell oracle the
                             in-process driver cannot instrument; its step
                             already carries its own >= 32 accepted-ops
                             assertion

The mode is the STRONGEST that holds on EVERY invocation: several oracles run
twice, once executing and once on a decline / byte-identity leg that executes
nothing by design, and a floor that only holds for the good leg is not a floor.
The weaker floor loses nothing — every counter is still measured and recorded.

159 CI step lines routed. The one deliberately NOT routed is the #275 RED
non-vacuity step (`! python …`), which inverts its verdict: routing it would
file a below-floor record for a run that is SUPPOSED to fail.

No emitted byte moves; no existing assertion removed.
…he floor

Two gates on top of the per-step floors:

1. `oracle_wiring_check.py` now also requires a `# ci-checks:` declaration on
   every `wired` oracle, and sums the floors PER MODE. It shares the driver's
   parser by importing it (`_load_oracle_run`) rather than re-implementing the
   grammar — two hand-maintained copies of one declaration format is the
   mirror-drift shape this repo keeps paying for.

   `--min-emulation-floor 294914` is the RATCHET, wired into the existing
   (required) `Claim Check` job rather than a new job — a brand-new job is not
   a required context on main and could sit red for weeks, which is the exact
   failure #890 exists to kill. Anti-vacuity in the gate itself: zero declared
   emulation floor is a hard failure, not a clean sheet.

2. `scripts/oracle_evidence.py` closes every oracle job with what it MEASURED,
   from the JSONL the driver appends to ($ORACLE_EVIDENCE_JSONL, set at
   workflow level so no oracle job can forget it). It asserts every record met
   its floor AND that the expected number of oracles reported at all — a step
   deleted, commented out or skipped by an early exit leaves the ledger short,
   and a short ledger is a red job rather than a quietly smaller number.
   Wired into 37 oracle jobs with their own `--min-oracles` count.

REPORTED PER UNIT, NEVER SUMMED ACROSS UNITS. Emulator entries, wasmtime
reference executions and compilations are three different things; one
impressive combined figure is precisely the defect #910 is about. Both step
summaries say so, and say that none of it is visible to `Rust-test Line
Coverage` — the two populations are reported side by side and never added.

Both directions exercised locally: --min-oracles 2 green on a 2-record ledger,
--min-oracles 3 red on the same ledger with the reason printed.
claims.yaml gains four entries, all pinned to CAPABILITY GAPS rather than issue
numbers (the v0.53 burn: a ledger pinned to a CLOSED issue green-confirms a
false residual, and correcting the prose then turns it RED):

  SYNTH-ORACLE-CHECK-FLOORS-910     — every wired oracle carries a floor
                                      (count-min 150), the execution population
                                      does not shrink (count-min 133), and the
                                      "nothing can be bound" hatch stays at ONE
                                      (count-max 1)
  SYNTH-ORACLE-CHECK-FLOORS-910-CI  — the doc's number and the number the gate
                                      ENFORCES cannot drift, and the routing
                                      cannot be quietly undone (count-min 159
                                      routed steps, 37 job ledgers)
  SYNTH-COVERAGE-SCOPE-910          — the scope caveat cannot be dropped while
  SYNTH-COVERAGE-SCOPE-910-README     the percentage stays quotable

ORACLE_WIRING.md gains the whole #910 half: the mechanism, why a driver instead
of 152 greps, why #910 option 1 was declined, the declaration grammar, the
CALIBRATION table (four self-reporting oracles agreeing 1:1), the per-mode floor
table, the "this is not the coverage percentage and must never be added to it"
section, and the itemized weak-floor list.

The FEATURE_MATRIX template (a source file) drops the now-closed "the sweeps
assert exit status rather than a per-script check count" residual and states
both #910 outcomes; docs/status/FEATURE_MATRIX.md regenerated via --emit-status,
never hand-edited.

41/41 claims hold.
The mechanism must not become the thing it polices. Each leg runs the step
EXTRACTED VERBATIM from ci.yml (yaml.safe_load -> the step's `run:` block ->
bash -e), so nothing here is a transcription of what CI does.

  M1  harness returns before its comparison loop  -> driver measured 0, step RED
  M2  one floor lowered to 0                      -> ratchet 294912 < 294914 RED
  M3  `# ci-checks:` header deleted               -> wiring gate RED
  M4  stdout regex with no capture group          -> driver rejects, RED
  M5  a routed step demoted to a COMMENT          -> wiring gate RED
  M6  oracle steps un-routed                      -> claims count-min RED
  M7  job ledger short (1 of 15 oracles)          -> ledger RED

BASELINE and RESTORED both green; `git status --porcelain` empty afterwards.

M1 is the load-bearing leg: the mutated harness STILL prints `ORACLE: PASS` and
STILL exits 0. A `grep -q '^ORACLE: PASS'` would have greened it, and so would
every one of the 152 exit-status-only steps this replaces. Only the emulator
count catches it — because that count does not come from the harness.

M5 re-proves the v0.54 comment-stripping fix under this lane's edits rather than
assuming it: 159 `run:` bodies were rewritten here, and that is precisely the
surface the fix covers.

M6's nuance is written down rather than rounded off — the substitution hit both
the `python3` and `python` spellings, so it un-routed two lines (159 -> 157),
not one. The leg proves the direction.
@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

avrabe added 5 commits August 6, 2026 06:29
All three failures were this lane's own, and none was the CI-floor
calibration the lane predicted. Reading the logs beat predicting them.

1. WCET sweep — "ledger SHORT: 3 oracles, expected >= 4".
   A TRUE POSITIVE with its root cause in the ledger's own harness.
   `ORACLE_EVIDENCE_JSONL` is a RELATIVE path and oracles run in-process
   (runpy), so a harness that chdir's redirects the append into its own
   scratch directory, which is then deleted. Exactly one of the four WCET
   phase scripts chdir's (phase2, line 213) and exactly that one's record
   went missing — 17 emulations recorded of 25 executed.
   Fixed twice over, because they are different failure modes:
     - resolve the ledger to an ABSOLUTE path at import, before any oracle
       can move the cwd;
     - restore `os.getcwd()` in run_oracle's finally block. It already
       restored sys.argv and sys.path; the third piece of interpreter state
       an in-process oracle can move was the one that bit.
   Red-first: a chdir'ing fixture records 0 ledger lines before, 1 after.
   No new gate — the --min-oracles assert IS the regression test for this
   class; it is what caught it.

2. Instrument independence — the failing step is `git diff --exit-code`,
   the assert that the v0.53 mutation never persists. The oracle steps
   `tee` into *.out AND those files were COMMITTED, so every fresh run
   dirties the tree and trips a soundness assert that has nothing to do
   with the mutation. Untracked all five and ignored them; the steps that
   produce and consume them at runtime are unchanged.

3. Rivet Validation — VG-009/VG-010 were typed `sys-verification`, a
   verification MEASURE, which rivet requires to `verifies` a system
   requirement. They are recorded GAPS and verify nothing. Typed
   `system-req` as VG-001..VG-008; their links already matched that shape.
   The species distinction the file draws is real, but it belongs in the
   prose, not the schema type.

Refs #910, #918
# Conflicts:
#	.github/workflows/ci.yml
#	CHANGELOG.md
…ot parse

A merge-created defect, present in NEITHER parent. The merge conflicted in TWO
files; I read the output through `tail -5` and saw only the CHANGELOG one, then
`git add -A` staged ci.yml with its markers intact and the commit succeeded.
GitHub reported it as `.github/workflows/ci.yml: failure` with ZERO checks —
not a red gate, an ABSENT one, which is the harder failure to notice.

Resolved keeping both sides: #599 keeps this lane's oracle_run.py routing, and
main's new #916 zero-fill differential is kept verbatim as raw `python` — it
carries no `# ci-checks:` header and the driver hard-errors on a script it
cannot bind a floor to. Listed in the weak-floor table so the residue stays
counted rather than silently unrouted.

Also corrects the ORACLE_WIRING.md path in VG-010 and in the new comment:
the file is at scripts/repro/, never docs/development/.

Post-merge asserts, since resolving one conflict is not resolving the merge:
zero conflict markers tree-wide, and both edited YAML files parse.
…face (#910)

`Claim Check` went red on the lane's OWN gate, correctly. Two oracles reached
main AFTER the floors were measured and declare nothing:

  scripts/repro/i64_high_reg_zero_fill_916_differential.py   (via #919)
  scripts/repro/proven_safe_bounds_901_differential.py       (via #915)

Both are real unicorn+wasmtime execution differentials, so both get
`emulations >= N`. Floors MEASURED through the driver, never guessed — a guessed
floor is the vacuous number this lane exists to remove:

  #916  measured=48   emulations=48   wasmtime_calls=48
  #901  measured=371  emulations=371  wasmtime_calls=188  compiles=5

Both steps now route through `scripts/oracle_run.py`, so they report to the
per-job ledger like every other wired oracle. This RETRACTS the comment I added
in the previous commit claiming the #916 harness could not be bound and that
declaring a floor was a follow-up: the gate disagreed, and the gate was right.
Its weak-floor table row is dropped for the same reason.

Totals move 133 -> 135 oracles, 294,914 -> 295,333 emulator entries.

THE FIND: that number lives on THREE surfaces, and only two were pinned.
ORACLE_WIRING.md and ci.yml are in `claims.yaml`; the FEATURE_MATRIX template
was not — so with the matrix still reading "133 oracles assert 294,914" the
ledger reported 42/42 HOLD. A number quotable in a shipped doc and bound to no
gate is #880 exactly: the gate checked the matrix against its RENDER, never its
CONTENT. Added SYNTH-ORACLE-CHECK-FLOORS-910-MATRIX, pinned on the TEMPLATE
rather than the generated file — pinning the render is satisfiable by faithfully
regenerating wrong prose.

Negative-controlled, not assumed: reverting the template to 133/294,914 yields
`FAIL SYNTH-ORACLE-CHECK-FLOORS-910-MATRIX`; restoring gives 43/43.

Local: oracle wiring 159 scripts, 0 UNDECLARED, emulations 135 / floor 295333.

Refs #910, #918
@avrabe
avrabe merged commit 1817bb3 into main Aug 6, 2026
52 checks passed
@avrabe
avrabe deleted the lane/v055-l5-evidence-scope branch August 6, 2026 14:39
avrabe added a commit that referenced this pull request Aug 6, 2026
Fan-in round 3. Conflicts kept-both:

- CHANGELOG.md — 2 blocks, 7 bullets, count-asserted.
- artifacts/sw-verification.yaml — NO id collision this time: main carries L3's
  SWVER-023 and this lane holds SWVER-024, because both were renumbered off
  022 before either merged. The pre-emptive split is why this was mechanical.

`Claim Check` was red for the same structural reason it was on #918: this lane's
own oracle predates the rule that every oracle declare what it attests, so
`aarch64_brtable_blockvals_851_differential.py` carried a `# ci-status:` but no
`# ci-checks:`. No lane did anything wrong — L5 changed the requirement while
this one was in flight.

Floor MEASURED through the driver, not guessed:

  measured=88  emulations=88  wasmtime_calls=88  compiles=1
  (88 checks — 2 trap, 86 value — across 19 exported functions)

The step now routes through `scripts/oracle_run.py`, so it reports to the
per-job ledger like every other wired oracle; its existing tee+grep non-vacuity
assertions are unchanged and still bind.

Totals 135 -> 136 oracles, 295,333 -> 295,421 entries, updated on ALL THREE
pinned surfaces (ORACLE_WIRING.md, ci.yml, and the FEATURE_MATRIX template —
the third one only became gate-backed earlier in this release, when the ledger
was found reporting 42/42 HOLD over a matrix carrying a stale number).

Local: 43/43 claims hold; 160 repro scripts, 0 UNDECLARED, emulations 136 /
floor 295421.

Refs #851, #910
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.

Coverage is blind to the execution differentials — the numbers understate, and can't be read as completeness either

1 participant