feat(v0.55.0): validate by default on shared memory; stop publishing empty releases - #399
Merged
Conversation
jess caught v0.53.0 sitting public with ONE asset — the compliance report — and fetched it in that state. The assets arrived later, so the symptom cleared on its own; the cause did not. ## Cause: the documented process races its own pipeline `release.yml` creates the GitHub release itself when it does not already exist. AGENTS.md told a human to run `gh release create` immediately after the tag push, which PUBLISHES right away — so the release goes public empty and the pipeline fills it minutes later. `compliance.yml` triggers on `release: published`, so it fired at once and uploaded its report while `release.yml` was still queued behind a busy runner fleet. That is exactly the state she saw: one asset, and it was not one of the ones anybody wants. ## Fix - **Process**: create the release as a DRAFT, let the pipeline upload into it, verify checksums AND the cosign signature (each with a negative control), and only then `gh release edit --draft=false`. Nothing is public until it is complete and verified. - **Gate**: `release-assets-gate.yml` runs on publish and fails if the four platform tarballs, SHA256SUMS or the cosign bundle are missing. The gate reports rather than prevents — GitHub offers no pre-publish hook — and that limit is written into the workflow rather than left for someone to discover. A documented step nobody verifies is the same class of inert gate this repo has now found three times; the process fix alone would have been a fourth. Refs: #395 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WrmMqf1iuTS1UBEes5TmdC
) jess's ask, deferred from #390 because it was a behaviour change rather than the defect. She declined to open it unilaterally, so it went on #391 with her reasoning attached; this implements it. The single-address-space paths now run the fused module through wasmparser before writing it. `--no-validate` opts out; `--validate` still forces it anywhere. That is where meld rewrites most invasively — rebasing absolute addresses and bridging calling conventions inside one address space — and where both recent defects surfaced: #390 emitted invalid wasm at exit 0, #393 emitted a module that validated and returned the wrong number. Her words: she would have caught the first months earlier had this been the default. The cost is one wasmparser pass over an artifact already in memory. A module that fails validation is NOT written. Previously the invalid artifact reached disk and failed later, in whatever consumed it. ## Potency, established by making it fire Routing verified across five cases (implied on shared; --no-validate opts out; multi unchanged; --validate forces on multi; the two flags conflict). Then the control that matters: reintroducing #390 and disabling the v0.53.0 wiring backstop — so an invalid module is actually produced and validation is the only thing left standing — gives Validating output (implied by --memory shared; --no-validate to skip)... Error: Validation failed Caused by: type mismatch: expected f32, found i32 (at offset 0xea) with no file on disk. Worth recording that the FIRST attempt at this control never reached validation: the wiring backstop caught the defect earlier. Defense in depth behaving correctly, and a reminder that a control which passes for the wrong reason proves nothing. 877 tests (--workspace), exit 0. Refs: #390, #391 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WrmMqf1iuTS1UBEes5TmdC
Extracted the decision into `validation_is_implied`, a total function over its two inputs, so it can be enumerated rather than reasoned about: three strategies x two opt-out states is six cases, all written down. meld#397 argues meld's own decision seams deserve exactly this, and this is a small enough one to demonstrate it on. Also asserts the opt-out wins on every strategy — otherwise `--no-validate` silently does nothing on exactly the path someone would reach for it. SR-73 + SWV-85, advanced by `rivet verify` with evidence rather than by editing the status field. Note the release-readiness gate did its job here: `rivet release status v0.55.0` exited 1 with "no artifacts scoped", which is what forced this requirement to exist for a change small enough to have skipped it. 879 (--workspace) / 878 (--all-features), both exit 0. Refs: #390, #391 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WrmMqf1iuTS1UBEes5TmdC
LS-N verification gate✅ 59/59 approved LS entries verified
Approved Failed LS entries(none) Missing regression tests(none) Updated automatically by |
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.
Two things jess reported that I had not acted on, plus her deferred ask.
1.
--memory sharedvalidates its own output by default (#390, #391)Her ask, deferred from #390 because it was a behaviour change rather than the defect. She declined to open it unilaterally, so it went onto #391 with her reasoning attached; this implements it.
The single-address-space paths now run the fused module through
wasmparserbefore writing it.--no-validateopts out;--validatestill forces it anywhere; the two conflict rather than resolving silently.That is where meld rewrites most invasively, and where both recent defects surfaced — #390 emitted invalid wasm at exit 0, #393 emitted a module that validated and returned the wrong number. In her words: she would have caught the first months earlier had this been the default. Cost is one
wasmparserpass over an artifact already in memory.A module that fails validation is not written. Previously the invalid artifact reached disk and failed later, in whatever consumed it.
Potency, established by making it fire
Routing verified across five invocations. Then the control that matters — reintroduce #390 and disable the v0.53.0 wiring backstop, so an invalid module is actually produced and validation is the only guard left:
Worth recording that the first attempt at that control never reached validation: the wiring backstop caught the defect earlier. Defense in depth behaving correctly — and a reminder that a control passing for the wrong reason proves nothing.
2. Releases are no longer published before their artifacts exist (#395)
She caught v0.53.0 public with one asset — the compliance report — and fetched it in that state.
Cause was the documented process racing its own pipeline.
release.ymlcreates the release itself; AGENTS.md told a human to rungh release createright after the tag push, which publishes immediately.compliance.ymltriggers onrelease: published, so it fired at once and uploaded its report whilerelease.ymlwas still queued behind a busy fleet. That is precisely the state she saw.gh release edit --draft=false. Nothing public until complete and verified.release-assets-gate.ymlfails on publish if the four platform tarballs,SHA256SUMS.txtor the cosign bundle are missing.The gate reports rather than prevents — GitHub has no pre-publish hook — and that limit is written into the workflow rather than left to be discovered. A documented step nobody verifies is the same inert-gate class this repo has now hit three times; the process fix alone would have been a fourth.
Traceability
SR-73 + SWV-85, advanced by
rivet verifywith evidence. The decision is extracted into a total function with its implication table enumerated — six cases, not a sample — which is the treatment meld#397 argues these seams deserve.Note the release-readiness gate from #394 did its job:
rivet release status v0.55.0exited 1 with "no artifacts scoped", which is what forced this requirement to exist for a change small enough to have skipped it.Gate
fmt clean, clippy
-D warningsclean, 879 (--workspace) / 878 (--all-features), both exit 0.rivet validatePASS, v0.55.0 cuttable.🤖 Generated with Claude Code
https://claude.ai/code/session_01WrmMqf1iuTS1UBEes5TmdC