FEAT-087 (scry#122): surviving your own edit is a second, independent identity bit - #162
Merged
Conversation
scry#122 item 2 asks that an adjudicator never claim `discharged` when the function identity came from `body_shape_hash`. The obvious repair — mark that tier `id_build_local: true` — is wrong in the other direction, and expensively: a body-shape hash IS cross-build comparable (same body, same hash), so marking it build-local would suppress cross-build citation for 100% of every stripped module to fix a different property, gutting REQ-020 for the common release case. `id_build_local` is a one-bit answer to a three-way question. Two properties: tier comparable? survives own edit? 1 unique stripped name yes yes 2 shared stripped -> raw NO (marked) yes (name is body-independent) 3 name, no disambiguator yes yes 4 unnamed -> body_shape_hash yes NO Only the first was encoded. This adds the second, `ident_survives_own_edit`, named after what it LICENSES rather than the mechanism that produced it — DD-022's standing lesson is that consumers read mechanism names as rankings. The consumer rule is the conjunction: read a missing key as evidence a site is gone only when `!id_build_local && ident_survives_own_edit`; else `uncertain`. MEASURED, on a stripped build of scry's own scry_mcdc.wasm (wasm-tools strip -a, 8.2MB -> 484KB, 853 funcs / 32 exported): 766 of 766 obligation-carrying functions and all 10,520 obligations land on the body-shape-hash tier, every one previously advertised as a stable identity. Stripping is standard in release builds, so this is the common production shape. After: schema 4, 10,519 of 10,520 marked false; the single `true` is the module-scoped `unbounded-stack`, whose ident is the literal `<module>` and IS body-independent. HONEST SCOPE: this fixes the CONTRACT BEFORE THE CONSUMER LANDS. FEAT-065 (`verify_against`) is still `proposed`, PR #120 is parked, and nothing on main turns a missing key into `discharged`. The reason to do it now is that the flag is already public in feed v3, so every v3 consumer inherits the ambiguity. The 100% is scoped to stripped modules on scry's own binary; whether avrabe's 468-module corpus (scry#126) is stripped is NOT claimed here. NOT COVERED, stated rather than implied: the FEAT-072 delta view still does not carry the new bit, and that page is exactly where a consumer reads "this site vanished". Next slice. Red-first: seeded `true` at all five construction sites, failed at lib.rs:10823 on the tier-4 assertion with both advisories located. Mutation-checked both ways: field forced `true` kills only the discrimination test (109 pass); forced `false` kills discrimination AND tier-2 independence (108); baseline 110. The strict superset is the signature of two independent bits. The six pre-existing `assert!(!a.id_build_local)` assertions stay green under both — they gate nothing here. Also de-tautologised FEAT-068's schema assertion. The version bump turned `contains("guidance_schema":3)` red; repairing it by comparing against GUIDANCE_SCHEMA_VERSION would be vacuous, since the feed is emitted FROM that constant (the class that shipped `scry 0.0.0`, scry#152). It now parses the declared integer and floors it at 2, mutation-checked: renaming the key kills it, regressing the version to 1 kills it. tests=0 clippy=0 fmt=0 rivet=0 claim-check=0 gate-coverage=0. Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Review catch. The one advisory reporting `ident_survives_own_edit: true` on the stripped module is the module-scoped `unbounded-stack`, and I explained it as "`<module>` is body-independent, so true is correct". The value was right and the reasoning was right, but the CODE had not decided it: the module-scoped loop in stamp_obligation_ids sets the three identity keys and never touched this field, so the observed `true` was simply the construction-site default I seeded. An artifact AC then asserted the field "discriminates even within one module" on the strength of a default. That is a claim about a decision that was not made. Now assigned deliberately in that loop, and pinned by feat087_a_module_scoped_ident_survives_any_edit. Mutation-checked: forcing the new line false kills exactly that test (2 pass, 1 fail) and restoring it is green. The AC records the correction rather than quietly reading correct. tests=0 clippy=0 fmt=0 rivet=0 claim-check=0 gate-coverage=0. Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…FEAT-077 Bumping the guidance feed 3 -> 4 makes two written claims literally false. Both are in roadmap-3.0.yaml and neither would have been caught by a gate — rivet validates structure, not whether an AC still describes reality. FEAT-068 AC: "VERIFIED on a real feed: guidance_schema=3, ..." FEAT-077 AC: "Then `guidance_schema` is 3 and every advisory carries ..." FEAT-068's is a MEASUREMENT RECORD being read as a live claim. The requirement was always that the feed DECLARES a version, not that the number equals 3; the number was the observed value. Reworded to say so, and to record that its oracle parses the declared integer structurally rather than comparing it against GUIDANCE_SCHEMA_VERSION (which is tautological — the feed is emitted from that constant). FEAT-077's is an AC that would now FAIL. Reworded to "at least 3 — exactly 3 when this shipped, 4 since FEAT-087". Also promotes FEAT-077 implemented -> accepted. `implemented` counts as NOT-yet-verified in the release gate, so a shipped, green feature left there blocks its release indefinitely — v3.4.0 has been carrying it. Evidence: all six FEAT-077 oracles green now (unique-stripped-ident survival, the two collision cases, exact-disambiguator-shape, and both byte-identical v3.2.5 regression pins), plus the five mutants recorded in the artifact. v3.4.0 not-ready 4 -> 3 of the pre-existing set. tests=0 clippy=0 fmt=0 rivet=0 claim-check=0 gate-coverage=0. Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
📐 rivet artifact deltaPR: #162 Base SHA: Validationhead — `rivet validate` resultbase — `rivet validate` result (for comparison)Artifact stats
full stats — headDiff (base → head)AADL model — headPosted by the |
avrabe
added a commit
that referenced
this pull request
Aug 27, 2026
… 7 -> 4 `implemented`/`proposed` count as NOT-yet-verified in the release gate, so a shipped, green feature left there blocks its release indefinitely. These three have shipped AND been verified, so leaving them proposed understates the release just as promoting them early would overstate it. Evidence for each, grounded rather than remembered: FEAT-087 (#162, 11/11 CI green) -- 3 oracles re-run on main just now: the tier-discrimination test, the tier-2 independence pin, and the module-scoped decision. Mutation-checked both directions when landed. FEAT-088 (#163, 11/11 CI green) -- the gate's --self-test PASSES and the real check PASSES on main, and it is wired into ci.yml (self-test before the real check). Mutation-checked against the real repo when landed. FEAT-090 (#166, 11/11 CI green) -- 5 oracles re-run on main just now, including the polarity test that dies only under the `&=` -> `|=` mutant. NOT promoted, deliberately: FEAT-089 -- FILED, not built. The non-zero-fact work does not exist yet; its own AC#1 requires a red test that is still red by design. FEAT-064 -- AC3 closed by measurement in #164, but AC1 remains FALSIFIED (repaired by FEAT-077 only for uniquely-named functions). Closing one AC does not clear the artifact, and REQ-020 stays blocked behind it. FEAT-057, FEAT-065, REQ-021 -- unbuilt. rivet=0 claim-check=0 fmt=0. Refs: FEAT-087 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
… 7 -> 4 `implemented`/`proposed` count as NOT-yet-verified in the release gate, so a shipped, green feature left there blocks its release indefinitely. These three have shipped AND been verified, so leaving them proposed understates the release just as promoting them early would overstate it. Evidence for each, grounded rather than remembered: FEAT-087 (#162, 11/11 CI green) -- 3 oracles re-run on main just now: the tier-discrimination test, the tier-2 independence pin, and the module-scoped decision. Mutation-checked both directions when landed. FEAT-088 (#163, 11/11 CI green) -- the gate's --self-test PASSES and the real check PASSES on main, and it is wired into ci.yml (self-test before the real check). Mutation-checked against the real repo when landed. FEAT-090 (#166, 11/11 CI green) -- 5 oracles re-run on main just now, including the polarity test that dies only under the `&=` -> `|=` mutant. NOT promoted, deliberately: FEAT-089 -- FILED, not built. The non-zero-fact work does not exist yet; its own AC#1 requires a red test that is still red by design. FEAT-064 -- AC3 closed by measurement in #164, but AC1 remains FALSIFIED (repaired by FEAT-077 only for uniquely-named functions). Closing one AC does not clear the artifact, and REQ-020 stays blocked behind it. FEAT-057, FEAT-065, REQ-021 -- unbuilt. rivet=0 claim-check=0 fmt=0. Refs: FEAT-087 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
… 7 -> 4 `implemented`/`proposed` count as NOT-yet-verified in the release gate, so a shipped, green feature left there blocks its release indefinitely. These three have shipped AND been verified, so leaving them proposed understates the release just as promoting them early would overstate it. Evidence for each, grounded rather than remembered: FEAT-087 (#162, 11/11 CI green) -- 3 oracles re-run on main just now: the tier-discrimination test, the tier-2 independence pin, and the module-scoped decision. Mutation-checked both directions when landed. FEAT-088 (#163, 11/11 CI green) -- the gate's --self-test PASSES and the real check PASSES on main, and it is wired into ci.yml (self-test before the real check). Mutation-checked against the real repo when landed. FEAT-090 (#166, 11/11 CI green) -- 5 oracles re-run on main just now, including the polarity test that dies only under the `&=` -> `|=` mutant. NOT promoted, deliberately: FEAT-089 -- FILED, not built. The non-zero-fact work does not exist yet; its own AC#1 requires a red test that is still red by design. FEAT-064 -- AC3 closed by measurement in #164, but AC1 remains FALSIFIED (repaired by FEAT-077 only for uniquely-named functions). Closing one AC does not clear the artifact, and REQ-020 stays blocked behind it. FEAT-057, FEAT-065, REQ-021 -- unbuilt. rivet=0 claim-check=0 fmt=0. Refs: FEAT-087 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
… 7 -> 4 (#173) `implemented`/`proposed` count as NOT-yet-verified in the release gate, so a shipped, green feature left there blocks its release indefinitely. These three have shipped AND been verified, so leaving them proposed understates the release just as promoting them early would overstate it. Evidence for each, grounded rather than remembered: FEAT-087 (#162, 11/11 CI green) -- 3 oracles re-run on main just now: the tier-discrimination test, the tier-2 independence pin, and the module-scoped decision. Mutation-checked both directions when landed. FEAT-088 (#163, 11/11 CI green) -- the gate's --self-test PASSES and the real check PASSES on main, and it is wired into ci.yml (self-test before the real check). Mutation-checked against the real repo when landed. FEAT-090 (#166, 11/11 CI green) -- 5 oracles re-run on main just now, including the polarity test that dies only under the `&=` -> `|=` mutant. NOT promoted, deliberately: FEAT-089 -- FILED, not built. The non-zero-fact work does not exist yet; its own AC#1 requires a red test that is still red by design. FEAT-064 -- AC3 closed by measurement in #164, but AC1 remains FALSIFIED (repaired by FEAT-077 only for uniquely-named functions). Closing one AC does not clear the artifact, and REQ-020 stays blocked behind it. FEAT-057, FEAT-065, REQ-021 -- unbuilt. rivet=0 claim-check=0 fmt=0. Refs: FEAT-087 Claude-Session: https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes work item 2 of #122.
The finding
id_build_localis a one-bit answer to a three-way question. It correctlyanswers "are these keys comparable across builds at all?" — and cannot answer
"does this identity survive an edit to the very function being fixed?"
body_shape_hashTier 4 carried the same
falseas tiers 1/3 while failing the propertyadjudication depends on.
Measured
On a stripped build of scry's own
scry_mcdc.wasm(wasm-tools strip -a,8.2MB → 484KB, 853 functions / 32 exported):
Stripping is standard in release builds, so this is the common production shape,
not a corner case. Minimal fixture: one unexported function, one appended
local.get 0 / i32.add→site_key 8b27dcd0 → 0df9e454, survival 0 of 1.What this is NOT
Marking tier 4
id_build_local: true. A body-shape hash genuinely iscross-build comparable — same body, same hash — so that bit is correct as it
stands. Flipping it suppresses cross-build citation for 100% of every stripped
module to fix a different property, gutting REQ-020 for the common release case.
The fix
A second, independent bit
ident_survives_own_edit, named after what itlicenses rather than the mechanism that produced it (DD-022: consumers read
mechanism names as stability rankings and get it wrong).
Consumer rule — the conjunction: treat a missing key in a later build as
evidence the site is gone only when
!id_build_local && ident_survives_own_edit.Otherwise the honest verdict is
uncertain, neverdischarged(REQ-021).Surfaced end-to-end:
Advisory, guidance feed v4, and anid moves on own editHTML badge. After the change: schema 4, 10,519/10,520 markedfalse; thesingle
trueis the module-scopedunbounded-stack, ident<module>, whichgenuinely is body-independent.
Honest scope
This fixes the contract before the consumer lands. FEAT-065
(
verify_against) is stillproposed, #120 is parked, and nothing on main turnsa missing key into
discharged— so this is not a shipped false-discharge. Thereason to do it now is that the flag is already public in feed v3, so every v3
consumer inherits the ambiguity.
The 100% is scoped to stripped modules, measured on scry's own binary. Whether
avrabe's 468-module corpus (#126) is stripped is a separate measurement and is
not claimed.
NOT COVERED, stated rather than implied: the FEAT-072 delta view does not
yet carry the new bit — and that page is exactly where a consumer reads "this
site vanished". Next slice; recorded in the artifact residual.
Oracles
Red-first: seeded
trueat all five construction sites → failed atlib.rs:10823on the tier-4 assertion, with both advisories located (so the redwas the contract, not a missing fixture).
Mutation-checked both directions:
true(pre-fix)falseThe strict superset is the signature of two genuinely independent bits — a
rename of
id_build_localwould kill identical sets. The six pre-existingassert!(!a.id_build_local)assertions stay green under both mutants; they gatenothing here.
Also de-tautologised FEAT-068's schema assertion: the bump turned
contains("guidance_schema":3)red, and the obvious repair (compare againstGUIDANCE_SCHEMA_VERSION) is vacuous because the feed is emitted from thatconstant — the class that shipped
scry 0.0.0(#152). It now parses the declaredinteger structurally and floors it at 2, mutation-checked: renaming the key kills
it, regressing the version to 1 kills it.
tests=0 clippy=0 fmt=0 rivet=0 claim-check=0 gate-coverage=0— 303 tests.gh pr checksmust beverified by hand before merge.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KkNzkNYzPh7366DkNijeNc