Skip to content

feat(release): release-kind acceptance bound to the publish gate (#58 slice 1) - #61

Merged
turinglambdaai merged 3 commits into
mainfrom
feat/release-acceptance-kind
Oct 23, 2026
Merged

turinglambdaai merged 3 commits into
mainfrom
feat/release-acceptance-kind

Conversation

@turinglambdaai

Copy link
Copy Markdown
Owner

Refs #58 (slice 1 per the claimed plan). Closes nothing yet — the issue tracks five slices.

What

  • rivet-acceptance.rktd: release requirement + release-update suite — the update chain joins the executable definition of done (the pinned rivet's acceptance-kinds already carries release).
  • racket/tests/release-update-test.rkt (new): N→N+1 lifecycle at the backend boundary over a loopback feed — plain-http and non-HTTPS-artifact feeds rejected, foreign key/key-id fails closed, semver + rollout gates, real download worker with SHA-256 verification, cancellation and sha-mismatch never land an artifact, Linux AppImage in-place swap end to end, and tasks.db byte-identical with the seeded task surviving throughout.
  • release.yml publish job runs the suite on the exact tree before signing: no update evidence, no release.
  • UPDATE.md: release-evidence section (what the suite proves, where host-side arms get their coverage).

Verification

  • Local: 5/5 suite pass on the macOS leg (raco test racket/ — 215 tests, full core suite green).
  • Linux leg exercises the AppImage arm in CI; three-platform CI + packaged acceptance run on this PR.

The acceptance contract had no release kind, so the update chain's
health — the thing every release actually rides on — had no place in
the executable definition of done. Slice 1 of #58:

- rivet-acceptance.rktd gains the `release` requirement plus a
  release-update suite (racket/tests/release-update-test.rkt); the
  pinned rivet's acceptance-kinds already includes `release`.
- The suite drives the N→N+1 lifecycle at the backend boundary every
  host shares, over a loopback feed signed with a throwaway key:
  plain-http feeds can never yield a candidate; artifacts must be
  HTTPS at the sign/parse layers; foreign keys and key-ids fail
  closed; semver refuses downgrades; rollout 0 gates every bucket;
  the real download worker verifies SHA-256 against the signed
  manifest; cancellation and sha-mismatch never land an artifact;
  and tasks.db stays byte-identical with the seeded task alive
  through all of it. The Linux AppImage in-place swap — the one
  install arm the backend owns end to end — replaces the running
  image for real on the Linux leg.
- release.yml's publish job runs the suite on the tree being
  published, before signing: no update evidence, no release.
- UPDATE.md documents what the suite proves and where each install
  arm's evidence lives.

A loopback-feed subtlety worth keeping: the feed server must close
only the output half — close-input-port waits on the peer's EOF while
the client waits for the response, deadlocking the suite.
Rivet requires native-ui/package/release suites to declare at least one
evidence file under .rivet/acceptance/ — CI caught the missing
declaration on the Windows acceptance leg. Mirror the package runner:
scripts/acceptance/release-update.rkt runs the suite with raco test and
writes .rivet/acceptance/<platform>/release-update.json on success; the
rktd command and evidence declaration follow.
The suite passed on the Windows leg (exit 0) but the runner judged it
failed: the rktd declares .rivet/acceptance/release-update.json and the
runner wrote it under the platform subdirectory. Each platform's
acceptance run executes on its own runner, so the single declared path
carries that run's record.
@turinglambdaai
turinglambdaai merged commit bf5b942 into main Oct 23, 2026
12 checks passed
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