Skip to content

FEAT-084 (scry#126): interpret the i32 bitwise family through the proven bits domain - #156

Merged
avrabe merged 2 commits into
mainfrom
feat-084-bits-interval-reduction
Aug 26, 2026
Merged

FEAT-084 (scry#126): interpret the i32 bitwise family through the proven bits domain#156
avrabe merged 2 commits into
mainfrom
feat-084-bits-interval-reduction

Conversation

@avrabe

@avrabe avrabe commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Implements FEAT-084 (artifacts/roadmap-v3.6.yaml, filed in #154): make i32.and — the top named operator behind the corpus unsoundness-fallbacks (433 of them; 97% of 468 real modules hit fallback, only 18% of memory-touching modules fully provable) — model-able inside interpret_op, so a masked address gets an interval tight enough for the in-bounds decision.

What is modelled

interpret_op arms for i32.and, i32.or, i32.xor, and i32.shl / i32.shr_u with a constant count, each a round-trip through the PROVEN known-bits × congruence domain (scry-sai-bits, FEAT-037, mechanized admit-free in proofs/rocq/BitsCongruence.v):

interval → BitsCong (only two justified conversions: an i32 singleton → the exact constant; a non-negative interval → known-0 high bits) → the domain's own transfer (and/or/xor/shl/shr_u — no mask reasoning reimplemented) → interval (sound projection of the unsigned [umin, umax]; a range straddling 2^31 projects to ⊤).

The headline case x & M (M a non-negative constant) projects to [0, M], so the bounds-check idiom proves, and i32.and stops scrubbing whole functions to ⊤.

What is deliberately NOT modelled

  • i64 bitwise family, i32.shr_s, rotl/rotr — still take the honest unsupported-op fallback.
  • Sign-bit masks (x & 0x8000_0FFF): the unsigned range straddles 2^31; result is ⊤. i32 is sign-agnostic — a negative M does NOT bound x above by M in the signed reading.
  • Variable shift counts: count 0 leaves the value unbounded, so ⊤.
  • All unmodelled shapes push ⊤ for the result only — never a function-wide degrade, never a false bound. The unsupported-op gap is removed only for the five operators genuinely modelled.
  • These ops write no locals/memory, so the octagon (classify_storeOtherforget) and the FEAT-058 memory domain are untouched — no lockstep change needed.

Red-first evidence (measured on unmodified main)

All six positive tests written first and run against unmodified code — actual failure, quoted:

tests::feat084_masked_address_proven_safe panicked:
assertion `left == right` failed: x & 0xFFF ≤ 4095 < 65536-4: the masked load must be PROVEN-SAFE
  left: PotentialTrap
 right: ProvenSafe

(6 failed on main: masked/downstream/or/xor/shl/shr_u; the 3 negative tests passed on main, as they encode the sound status quo.) After the change: 9/9 pass.

Negative tests (the ones that keep this honest)

  • feat084_unbounding_mask_stays_potential_trapx & 0x1FFFF (reaches 131071 ≥ 65536) stays POTENTIAL-TRAP.
  • feat084_negative_mask_stays_potential_trapx & 0x80000FFF stays POTENTIAL-TRAP.
  • feat084_variable_shift_count_stays_potential_trapx >> y stays POTENTIAL-TRAP.
  • Every test asserts the load actually produced an OutOfBounds obligation before checking its verdict (.expect(...)), so none can pass vacuously.

Mutation checks (each mutation run, confirmed red, reverted)

  1. Disable the I32And arm (fall back to unsupported path) → the 5 and-dependent tests go red; shr_u (no and) and all negatives stay green.
  2. Unsoundly tighten the projection (hi: umaxhi: umin) → killed by exactly and only feat084_unbounding_mask_stays_potential_trap (falsely proves [0,0]) — the negative test alone catches an implementation that over-claims.
  3. Straddle branch returns a tight positive bound instead of ⊤ → killed by exactly and only feat084_negative_mask_stays_potential_trap.

Local verification (by exit code)

  • cargo test -p scry-sai-core -p scry-sai-viz → exit 0 (123 + 37 pass, 0 failed; no regressions)
  • cargo clippy -p scry-sai-core -p scry-sai-viz --all-targets -- -D warnings → exit 0
  • cargo fmt --all --check → exit 0
  • rivet validate → exit 0 (PASS; the new implementation-notes field is INFO-level, same pattern as residual on FEAT-074..077)
  • python3 tools/claim-check.py → exit 0 (7/7 claims hold)

Verified locally only — CI has not been observed on this branch and no claim is made about it.

Not verified here (named honestly)

  • AC#4, the number that measures success: the corpus figure "modules where ALL memory accesses are provable" (18% at scry#126). Needs avrabe's offered re-run against this branch. The artifact stays implemented (not verified) until that lands, whichever way it goes.
  • No Rocq changes: the reduction reuses BitsCongruence.v's proven transfers; the two interval↔bits conversions are new UNPROVEN Rust (documented soundness arguments in the code). If they should be mechanized, that is a follow-up obligation.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

avrabe and others added 2 commits August 26, 2026 17:32
…ven bits domain

i32.and/or/xor and constant-count i32.shl/shr_u get real interpret_op arms:
interval -> BitsCong (sound approximation) -> the FEAT-037 domain's own
transfer (mechanized admit-free in BitsCongruence.v) -> interval (sound
projection). The headline case, `x & M` with M a non-negative constant,
projects to [0, M] — tight enough for the in-bounds decision, so the
masked-address idiom turns PROVEN-SAFE, and i32.and (433 fallbacks in the
468-module corpus) stops scrubbing whole functions to top.

Sound by construction, never a false bound:
- a sign-bit mask straddles 2^31 in the unsigned reading -> top;
- a variable shift count -> top (count 0 leaves the value unbounded);
- any operand shape outside the two justified conversions -> top for the
  RESULT only, never a function-wide degrade;
- these ops write no locals/memory, so octagon (classify_store: Other ->
  forget) and the FEAT-058 memory domain are untouched.

NOT modelled (still the honest unsupported-op fallback): the i64 bitwise
family, i32.shr_s, rotl/rotr.

Red-first: all six positive tests measured failing on unmodified main
(PotentialTrap where ProvenSafe required); the negative tests (unbounding
mask 0x1FFFF, sign-bit mask 0x80000FFF, variable shift count) pass before
AND after — they encode the sound status quo the reduction must preserve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc
…outstanding

Status proposed -> implemented, with implementation-notes recording exactly
what was modelled (i32.and/or/xor + constant-count shl/shr_u through the
proven scry-sai-bits domain) and what deliberately was NOT (i64 bitwise
family, i32.shr_s, rotl/rotr; variable shift counts and sign-bit masks push
top for the result only). AC#4 — the corpus "modules where ALL memory
accesses are provable" figure — needs avrabe's re-run and is named as the
gap keeping this short of verified.

rivet validate PASS (exit 0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc
@avrabe avrabe closed this Aug 26, 2026
@avrabe avrabe reopened this Aug 26, 2026
@github-actions

Copy link
Copy Markdown

📐 rivet artifact delta

PR: #156 Base SHA: 76162466

Validation

head — `rivet validate` result
  SR-11 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-12 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-13 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-2 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-3 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-4 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-5 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-6 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-7 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-8 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-9 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SYS-1 (system-req, status: accepted) — missing: sys-integration-verification
  SYS-2 (system-req, status: accepted) — missing: sys-integration-verification
  SYS-3 (system-req, status: accepted) — missing: sys-integration-verification
  SYS-4 (system-req, status: accepted) — missing: sys-integration-verification
  SYS-5 (system-req, status: accepted) — missing: sys-integration-verification
  → run `rivet validate --explain SR-1` to see which link type and source types satisfy a gap

Result: PASS (141 warnings)
Schemas: common@0.3.0 (embedded), dev@0.3.0 (embedded), research@0.1.0 (embedded), research-ext@0.1.0 (on-disk), safety-case@0.1.0 (embedded), aspice@0.2.0 (embedded)
base — `rivet validate` result (for comparison)
  SR-11 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-12 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-13 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-2 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-3 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-4 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-5 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-6 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-7 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-8 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SR-9 (sw-req, status: accepted) — missing: sw-integration-verification, unit-verification
  SYS-1 (system-req, status: accepted) — missing: sys-integration-verification
  SYS-2 (system-req, status: accepted) — missing: sys-integration-verification
  SYS-3 (system-req, status: accepted) — missing: sys-integration-verification
  SYS-4 (system-req, status: accepted) — missing: sys-integration-verification
  SYS-5 (system-req, status: accepted) — missing: sys-integration-verification
  → run `rivet validate --explain SR-1` to see which link type and source types satisfy a gap

Result: PASS (141 warnings)
Schemas: common@0.3.0 (embedded), dev@0.3.0 (embedded), research@0.1.0 (embedded), research-ext@0.1.0 (on-disk), safety-case@0.1.0 (embedded), aspice@0.2.0 (embedded)

Artifact stats

base head
Total artifacts 254 254
full stats — head
Artifact summary:
  academic-reference               24
  competitive-analysis             11
  design-decision                  22
  feature                          84
  market-finding                    7
  requirement                      21
  safety-context                    3
  safety-goal                       5
  safety-justification              4
  safety-solution                   6
  safety-strategy                   1
  stakeholder-req                   3
  sw-req                           13
  sw-verification                  13
  sys-verification                  5
  system-req                        5
  technology-evaluation            12
  verification                     15
  TOTAL                           254

Orphan artifacts (no links): 12
  CA-001
  CA-002
  CA-003
  CA-004
  CA-005
  CA-006
  CA-007
  CA-008
  CA-009
  CA-010
  CA-011
  FEAT-078

Diagnostics: 0 error(s), 141 warning(s), 18 info(s)

Diff (base → head)

~ FEAT-084
  status: - proposed -> + implemented
  field changed: implementation-notes

0 added, 0 removed, 1 modified, 253 unchanged

AADL model — head

spar/scry.aadl: OK

Posted by the rivet-delta workflow. Informational only — does not gate the PR.

@avrabe
avrabe merged commit 123fc7d into main Aug 26, 2026
11 of 21 checks passed
@avrabe
avrabe deleted the feat-084-bits-interval-reduction branch August 26, 2026 18:22
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