Skip to content

FEAT-092 (scry#126): one operator, one name - #172

Merged
avrabe merged 2 commits into
mainfrom
feat-092-op-names
Aug 27, 2026
Merged

FEAT-092 (scry#126): one operator, one name#172
avrabe merged 2 commits into
mainfrom
feat-092-op-names

Conversation

@avrabe

@avrabe avrabe commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Reopens the work from #168, which GitHub auto-closed when I deleted its base branch
during the #170 merge (my error — --delete-branch on a branch that was the base of
three stacked PRs). Branch is unchanged apart from a clean rebase onto main; #168
carries the full review discussion
.

The defect

TrapCheck::op is documented as "the operator name (e.g. i32.div_s)" — wasm text
format. Measured on scry_mcdc.wasm, 2,800 of 10,520 advisories carried a Rust enum
identifier instead (I64Store, I32Load8U, MemoryCopy, …). Identical counts stripped
and unstripped, so not a build artifact.

op_report_name falls back to format!("{op:?}") for any operator op_name lacks an
arm for — and among memory ops it covered exactly two.

Why it's #126's operator ranking, not cosmetics

The same operator carried two names: the non-degraded path emits i64.store (287
sites), the degraded path I64Store (1,008). Both out-of-bounds. A frequency ranking
sees one operator as two rows and under-counts the top entry ~4.5× — i64.store is
really 1,295 sites.

Naming only — measured, not argued

before after
leaked Rust identifiers 2,800 71
out-of-bounds 8,162 8,162
proven-safe OOB 55 55

Every advisory-code count identical across all 10,520. The test pins the verdicts too,
so a later edit can't move what scry proves while claiming to rename.

Red first: leaked: ["I32Load8U", "I32Store8"], after the non-vacuity assertion
(>= 3 trap checks) passed. Mutation-checked: deleting the i32.load8_u arm —
asserted to match one site — turns it red naming exactly I32Load8U.

Not covered: 71 advisories still render a Rust identifier, all unsupported-op on
i64/i32 arithmetic scry doesn't model, each with a single name — the splitting defect
doesn't apply. Separate slice.

Also records the FEAT-069 pre-build measurement (0.67% proven rate) on its artifact.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

avrabe and others added 2 commits August 27, 2026 09:04
`TrapCheck::op` is documented as "the operator name (e.g. `i32.div_s`)" -- wasm
text format. Measured on scry's own scry_mcdc.wasm, 2,800 of 10,520 advisories
carried a RUST ENUM IDENTIFIER instead: I64Store, I32Load8U, I32Store8,
MemoryCopy, F64Load. Identical counts on the stripped and unstripped module, so
not an artifact of the build.

MECHANISM: op_report_name falls back to format!("{op:?}") for any operator
op_name has no arm for, and among memory operators op_name covered exactly two
-- I32Load and I32Store. Every other load/store rendered as its Rust variant.

WHY THIS IS #126's OPERATOR RANKING AND NOT COSMETICS: the same operator carried
TWO names at once. The non-degraded path labels the access from a literal
(`i64.store`, 287 sites); the degraded path calls op_report_name (`I64Store`,
1,008 sites). Both are out-of-bounds advisories. A consumer ranking operators by
frequency sees ONE operator as TWO rows and under-counts the top entry ~4.5x --
i64.store is really 1,295 sites.

NAMING ONLY, and measured rather than argued: after the change EVERY
advisory-code count on the real module is identical -- out-of-bounds 8,162 ->
8,162, proven-safe OOB 55 -> 55, every code equal across all 10,520 -- while
leaked identifiers drop 2,800 -> 71. The test pins the verdicts too, so a later
edit cannot move what scry proves while claiming to rename.

Red-first: failed with leaked: ["I32Load8U", "I32Store8"], AFTER the
non-vacuity assertion (>= 3 trap checks) passed -- the red was the contract, not
an empty fixture. Mutation-checked: deleting the i32.load8_u arm (asserted to
match exactly one site before applying) turns it red naming exactly I32Load8U.

NOT COVERED, stated rather than implied: 71 advisories still render a Rust
identifier. All 71 are `unsupported-op` on i64/i32 arithmetic and comparison
operators scry genuinely does not model, and each carries a SINGLE name -- the
ranking-splitting defect does not apply to them. Naming that family is a
separate mechanical slice.

tests=0 clippy=0 fmt=0 rivet=0 claim-check=0 gate-coverage=0.

Refs: FEAT-092

Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
FEAT-069 (safe-accesses.json, a v3.3.0 blocker) proposes exporting scry's
PROVEN-SAFE out-of-bounds verdicts so synth can elide software bounds checks.
Measured before anyone builds it, on scry's own scry_mcdc.wasm and identical
stripped vs unstripped: scry proves 55 memory accesses safe against 8,162 it
cannot -- a 0.67% proven rate. The export would carry 55 sites out of 8,217.
synth measures bounds checks at ~25-40% overhead, so eliding 0.67% of them
recovers on the order of 0.2% of runtime.

That does not kill the feature; it relocates the work. The blocker is not the
export FORMAT, it is PRECISION -- the same module shows 1,639
unmodeled-control-flow and 623 unsupported-op advisories, an if/else havocs its
region by design, and FEAT-089 measured that a disequality guard cannot refine
an interval at all. Shipping the channel before the payload exists would hand
synth a correct and nearly empty file.

Recorded on the artifact rather than only on the tracker, so a future tick does
not build it expecting a full payload.

(Also repairs three terms this edit itself blanked: the first attempt used an
unquoted heredoc, so the shell ran the backticked operator names as command
substitutions. `rivet validate` passed over the gaps -- structural validation
cannot see missing prose, which is worth remembering before trusting it as a
review.)

rivet=0 claim-check=0 fmt=0.

Refs: FEAT-069

Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📐 rivet artifact delta

PR: #172 Base SHA: 8b53ec21

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 (159 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 (158 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 262 263
full stats — head
Artifact summary:
  academic-reference               24
  competitive-analysis             11
  design-decision                  22
  feature                          93
  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                           263

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), 159 warning(s), 26 info(s)

Diff (base → head)

+ FEAT-092  v3.4 — One operator, one name: stop leaking Rust identifiers into the operator ranking (scry#126)
~ FEAT-069
  description: changed

1 added, 0 removed, 1 modified, 261 unchanged

~ NEW    WARN: [FEAT-069] prose mentions 'FEAT-089' but no typed link to it; add a link in `links:` or remove the mention
0 new errors, 0 resolved errors, 1 new warnings, 0 resolved warnings

AADL model — head

spar/scry.aadl: OK

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

@avrabe
avrabe merged commit 0749953 into main Aug 27, 2026
13 checks passed
@avrabe
avrabe deleted the feat-092-op-names branch August 27, 2026 07:35
avrabe added a commit that referenced this pull request Aug 27, 2026
Both shipped and CI-verified; leaving them proposed understates the release the
same way promoting them early would overstate it.

  FEAT-091 (#167, 13/13 green) -- commit traceability. Its gate's --self-test
    PASSES and the real check PASSES on main against HEAD~1..HEAD, and the job
    runs in CI as a REQUIRED check.
  FEAT-092 (#172, 13/13 green) -- one operator, one name. Its oracle re-run on
    main just now; the naming-only claim was measured, not argued (every
    advisory-code count identical on a real module, leaks 2,800 -> 71).

NOT promoted, and the reason matters:
  FEAT-093 -- merged in #167 and green, but #175 is OPEN and adds ACs to it.
    Promoting now would produce an `accepted` artifact that immediately gains
    unmet criteria. It goes accepted after #175 lands, not before.
  FEAT-089 -- filed, not built; its AC#1 demands a test still red by design.
  FEAT-057 / FEAT-065 / REQ-021 -- unbuilt.
  FEAT-064 -- AC1 still falsified, so REQ-020 stays blocked.

rivet=0 claim-check=0 drift-gate=0 fmt=0.

Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
avrabe added a commit that referenced this pull request Aug 27, 2026
Both shipped and CI-verified; leaving them proposed understates the release the
same way promoting them early would overstate it.

  FEAT-091 (#167, 13/13 green) -- commit traceability. Its gate's --self-test
    PASSES and the real check PASSES on main against HEAD~1..HEAD, and the job
    runs in CI as a REQUIRED check.
  FEAT-092 (#172, 13/13 green) -- one operator, one name. Its oracle re-run on
    main just now; the naming-only claim was measured, not argued (every
    advisory-code count identical on a real module, leaks 2,800 -> 71).

NOT promoted, and the reason matters:
  FEAT-093 -- merged in #167 and green, but #175 is OPEN and adds ACs to it.
    Promoting now would produce an `accepted` artifact that immediately gains
    unmet criteria. It goes accepted after #175 lands, not before.
  FEAT-089 -- filed, not built; its AC#1 demands a test still red by design.
  FEAT-057 / FEAT-065 / REQ-021 -- unbuilt.
  FEAT-064 -- AC1 still falsified, so REQ-020 stays blocked.

rivet=0 claim-check=0 drift-gate=0 fmt=0.

Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
avrabe added a commit that referenced this pull request Aug 27, 2026
…→4 (#176)

* Promote FEAT-091 / FEAT-092 to accepted — v3.4.0 not-ready 7 -> 5

Both shipped and CI-verified; leaving them proposed understates the release the
same way promoting them early would overstate it.

  FEAT-091 (#167, 13/13 green) -- commit traceability. Its gate's --self-test
    PASSES and the real check PASSES on main against HEAD~1..HEAD, and the job
    runs in CI as a REQUIRED check.
  FEAT-092 (#172, 13/13 green) -- one operator, one name. Its oracle re-run on
    main just now; the naming-only claim was measured, not argued (every
    advisory-code count identical on a real module, leaks 2,800 -> 71).

NOT promoted, and the reason matters:
  FEAT-093 -- merged in #167 and green, but #175 is OPEN and adds ACs to it.
    Promoting now would produce an `accepted` artifact that immediately gains
    unmet criteria. It goes accepted after #175 lands, not before.
  FEAT-089 -- filed, not built; its AC#1 demands a test still red by design.
  FEAT-057 / FEAT-065 / REQ-021 -- unbuilt.
  FEAT-064 -- AC1 still falsified, so REQ-020 stays blocked.

rivet=0 claim-check=0 drift-gate=0 fmt=0.

Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* Also promote FEAT-071 — v3.3.0 not-ready 6 -> 5

#174 landed FEAT-071 with 13/13 green, so it belongs in this pass rather than a
follow-up. Its oracle re-run on main just now: the scope manifest reaches the
feed as data, and the anti-drift property (every not-proven item present in BOTH
the page and the feed) holds. That property was mutation-checked when it landed
-- emitting empty strings in the feed while the page kept them kills the test.

Folded in here rather than opened separately because #176 had not started CI, so
it costs nothing; had it been mid-run the trade would have gone the other way.

rivet=0 claim-check=0 drift-gate=0 fmt=0.

Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* Also promote FEAT-093 — its refinement landed, so its criteria are complete

FEAT-093 was deliberately held back from the earlier promotion because #175 was
OPEN and adding acceptance criteria to it; promoting then would have produced an
`accepted` artifact that immediately acquired unmet criteria. #175 has now
merged, so the criteria are complete AND met.

Evidence re-run on main: the gate's 7-case --self-test passes, file mode passes,
and live mode passes with `file agrees: True` -- the ruleset, the checked-in
file and the CI jobs are all in agreement.

Folded in here rather than opened separately because #176 still had not started
CI. Same trade as FEAT-071 a moment ago, and the same reason.

rivet=0 claim-check=0 drift-gate=0 fmt=0.

Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

---------

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