Skip to content

FEAT-065: scry adjudicates its own oracle (verify_against), conservative by construction - #120

Draft
avrabe wants to merge 2 commits into
mainfrom
feat-065-verify-against
Draft

FEAT-065: scry adjudicates its own oracle (verify_against), conservative by construction#120
avrabe wants to merge 2 commits into
mainfrom
feat-065-verify-against

Conversation

@avrabe

@avrabe avrabe commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Closes the loop REQ-018 promised. v3.1 shipped a verification oracle as prose; this makes it a machine verdict, so an agent's edit is gated by a sound checker rather than by tests.

verify_against(before, after)discharged | still-open | regressed | moved | removed-with-code | uncertain.

Two findings forced the design (DD-021, new)

1. The id can't be the matching key. obligation_id includes the advisory code — the clean-room required it, since one i32.div_s raises two obligations at one pc. But fixing an obligation changes its code (div-by-zeroproven-safe) and therefore its id — exactly the transition we must detect. Matching on it would render every genuine discharge as "one id vanished, an unrelated one appeared."

So three keys, each with one job: obligation_id (cite), site_key (match — excludes code), group_key (the ordinal domain — the conservatism signal).

2. discharged has to be a certainty claim. ObligationId.v proves identity can alias (survivor_inherits_deleted_identity), which admits a false discharge: delete an open site, and a proven-safe same-kind sibling inherits its identity — the deleted obligation looks fixed. So discharged is withheld unless the ordinal domain's site set is unchanged; otherwise uncertain.

I verified the rule actually fires

Rather than trust a green test (the aliasing oracle accepts two outcomes), I probed the real verdict:

Uncertain  before=div-by-zero  after=Some("proven-safe")
  "looks proven safe, but this site's ordinal domain changed membership
   so identity may have aliased — discharge withheld"

Without the conservatism rule this case reports discharged for an obligation that was never fixed.

removed-with-code stays strictly distinct from discharged: deleting the code that carried an obligation proves nothing, and an agent rewarded for conflating them learns to delete rather than fix.

Honest residual (in DD-021)

A pure reordering of two same-kind operators in one region preserves the group's site set while swapping which site each key denotes — that shape can still mis-attribute a verdict. Disclosed; closing it needs content corroboration beyond the key.

Verification

4 FEAT-065 oracles (real fix → Discharged; deletion → RemovedWithCode, never Discharged; aliasing → Uncertain; lost fact → Regressed). core 106, viz 25, segment 10, poly 9, interval 8, octagon 26. clippy -D warnings clean across CI's package set; fmt clean; rivet validate PASS.

Scope: the pure adjudicator. CLI/MCP surfacing is FEAT-066/067. FEAT-065 stays proposed pending clean-room + CI.

🤖 Generated with Claude Code

…tive by construction

Closes the fix-verify loop REQ-018 promised: the v3.1 verification oracle was
PROSE; this makes it a machine verdict, so an agent's edit is gated by a sound
checker rather than by tests.

`verify_against(before, after) -> Vec<VerifyVerdict>` with outcomes
discharged / still-open / regressed / moved / removed-with-code / uncertain.

DD-021 (new) records two findings that forced the design:
1. `obligation_id` includes the advisory CODE (clean-room: one i32.div_s raises
   two obligations at one pc, so the site alone does not discriminate) — but
   FIXING an obligation changes its code (div-by-zero → proven-safe) and hence
   its id, which is exactly the transition to detect. Matching on the id would
   render every genuine discharge as two unrelated events. So THREE keys, each
   with one job: obligation_id (cite), site_key (match — excludes code),
   group_key (the ordinal domain — the conservatism signal).
2. `ObligationId.v` PROVES identity can alias (survivor_inherits_deleted_identity),
   which admits a FALSE discharge: an open site is deleted, a proven-safe
   same-kind sibling inherits its identity, and the deleted obligation looks
   fixed. So `discharged` is a CERTAINTY claim — withheld unless the ordinal
   domain's site set is unchanged; otherwise `uncertain`.

Verified the conservatism actually FIRES on that scenario rather than passing by
another route (a probe printed the real verdict before it was removed):
  Uncertain  before=div-by-zero after=Some("proven-safe")
  "looks proven safe, but this site's ordinal domain changed membership so
   identity may have aliased — discharge withheld"
Without the rule this case reports `discharged` for an obligation never fixed.

`removed-with-code` is kept strictly distinct from `discharged` — deleting the
code that carried an obligation proves nothing, and an agent rewarded for
conflating them learns to delete rather than fix.

HONEST RESIDUAL (DD-021 limitations): a pure REORDERING of two same-kind
operators in one region preserves the group's site set while swapping which site
each key denotes, so that edit shape can still mis-attribute a verdict. Disclosed;
closing it needs content corroboration beyond the key.

Tests: 4 FEAT-065 oracles (real fix → Discharged; deletion → RemovedWithCode and
never Discharged; aliasing → Uncertain; lost fact → Regressed). core 106, viz 25,
segment 10, poly 9, interval 8, octagon 26. clippy -D warnings clean across CI's
package set, fmt clean, rivet validate PASS.

Scope: the PURE adjudicator. CLI/MCP surfacing is FEAT-066/067. FEAT-065 stays
`proposed` pending clean-room + CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@avrabe
avrabe marked this pull request as draft August 11, 2026 19:59
@avrabe

avrabe commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Converting to draft — clean-room found 6 criticals, and one of them falsifies DD-021's core rationale

Adversarial review of this adjudicator found six wrong-verdict paths, four of which the design did not anticipate. Not mergeable. Recording them here; the rework is tracked separately.

The rationale sentence is false

DD-021 asserts: "aliasing by deletion or insertion NECESSARILY changes the ordinal domain's membership." That is the sentence the entire conservatism rule rests on, and it is wrong. Pair a deletion with a same-kind insertion in the same region and the group's site_key set is byte-identical:

;; before — div#0 OPEN (param divisor), div#1 proven safe
i32.const 10 local.get 0 i32.div_s    i32.const 20 i32.const 5 i32.div_s   i32.add
;; after — the OPEN one deleted, a new SAFE one appended
i32.const 20 i32.const 5 i32.div_s    i32.const 30 i32.const 6 i32.div_s   i32.add

Group set identical ⇒ domain_stablesingle verdict: Discharged, attributed to a proven fact about a different operator, with no compensating Regressed. This is precisely the delete-instead-of-fix reward hack the rule exists to prevent.

The other criticals

  1. Cross-function identity collision. body_shape_hash (the no-name/no-export fallback) is the whole function identity, so two unnamed functions with the same opcode sequence share site_key/group_key. Deleting an entire function carrying an obligation reports Discharged.
  2. Obligation laundering via a typed region. (block (result i32) …) routes through havoc_region, which emits no trap check, no gap, no advisory when the write set is empty and there's no call. A live obligation vanishes and reports RemovedWithCode. One line, no knowledge of the identity scheme required. (Pre-existing FEAT-040/046 reporting hole; this feature promotes it to a wrong verdict.)
  3. Regressed fabricated on a byte-identical module. verify_against(&m, &m) returns contradictory verdictsStillOpen and Regressed under the same obligation_id, with an invented before_code: "proven-safe". Root cause: site_key excludes the code, so an open div-by-zero and a proven signed-overflow at one i32.div_s share a site key, putting it in before_proven. Fires on the ordinary const / var division shape. My own test feat065_regression_is_reported passes vacuously — it would pass on a self-comparison too.
  4. New obligations are invisible. Zero verdicts for an obligation introduced at a site with no prior advisory. An agent that fixes function A while introducing a div-by-zero in function B passes the gate clean — blind in the direction that matters most.
  5. A genuine fix reads as RemovedWithCode in stripped modules. body_shape_hash changes on any opcode edit, so for a function with no name and no export — i.e. anything through wasm-opt --strip-debugDischarged is unreachable for the canonical fix shape.

Confirmed closed

The advisory-less-operator vector I suspected is not a hole (ordinals are per-kind and per-region, and nested regions get their own counters), and ⊤-degradation does not suppress trap checks. The module sentinel cannot collide with a real site (kind = "<module>" is unreachable from op_report_name).

Assessment

An adjudicator that can wrongly say "fixed" is worse than none, because an agent optimises straight into it. Findings 1–3 are that failure; finding 5 means it cannot see new faults; finding 4 makes the Regressed channel unusable. The pure-library scope (no CLI/WIT surface yet) means nothing shipped — it does not soften the ranking.

Adversarial review of the FEAT-065 adjudicator (PR #120, now draft) falsified
this decision's central justification. DD-021 asserted that "aliasing by
deletion or insertion NECESSARILY changes the ordinal domain's membership" — the
sentence the whole conservatism rule rested on. It is FALSE: a deletion paired
with a same-kind insertion leaves the group's site_key set byte-identical, so
the check passes and a FALSE `discharged` is produced — the delete-instead-of-fix
reward hack the rule exists to prevent.

Retracted in place (not quietly reworded) and the six reproduced findings
recorded in `limitations`, including two the design did not anticipate at all:
new obligations produce no verdict whatsoever, and `regressed` is fabricated on
a byte-identical module (contradictory verdicts under one id).

Correcting the claim, not the ledger. The implementation stays in draft until
matching uses CONTENT corroboration rather than a positional ordinal plus a
population check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📐 rivet artifact delta

PR: #120 Base SHA: bf445c7e

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 (119 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: unit-verification, sw-integration-verification
  SR-12 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-13 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-2 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-3 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-4 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-5 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-6 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-7 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-8 (sw-req, status: accepted) — missing: unit-verification, sw-integration-verification
  SR-9 (sw-req, status: accepted) — missing: unit-verification, sw-integration-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 (117 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 222 223
full stats — head
Artifact summary:
  academic-reference               24
  competitive-analysis             11
  design-decision                  21
  feature                          71
  market-finding                    7
  requirement                      20
  safety-context                    3
  safety-goal                       5
  safety-justification              3
  safety-solution                   6
  safety-strategy                   1
  stakeholder-req                   3
  sw-req                           13
  sw-verification                  13
  sys-verification                  5
  system-req                        5
  technology-evaluation            12
  TOTAL                           223

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

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

Diff (base → head)

+ DD-021  v3.3 — Adjudicating a NON-INJECTIVE identity: three keys, and `discharged` as a certainty claim

1 added, 0 removed, 0 modified, 222 unchanged

~ NEW    WARN: [DD-021] prose mentions 'FEAT-064' but no typed link to it; add a link in `links:` or remove the mention
~ NEW    WARN: [DD-021] prose mentions 'FEAT-040' but no typed link to it; add a link in `links:` or remove the mention
0 new errors, 0 resolved errors, 2 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.

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