Skip to content

Release gate: doctor --release, generate --check, update-API keyword contract - #272

Merged
turinglambdaai merged 1 commit into
mainfrom
feat/release-gate
Oct 16, 2026
Merged

turinglambdaai merged 1 commit into
mainfrom
feat/release-gate

Conversation

@turinglambdaai

Copy link
Copy Markdown
Owner

Closes #245. Closes #255.

What

raco rivet generate --check regenerates every client file in memory and fails when the tree differs. The writer (generate-clients!) and the gate (check-generated-clients) share one regeneration (client-outputs), so they can never disagree about what a fresh tree looks like. Because regenerated content always carries the current rivet.rktd version/build stamp, a hand-edited literal or a forgotten regeneration shows up as stale — closing the taskly 8c34ed5, fulcrum 973df6b, syncpilot, and pdfgist stamp-drift class. The generator itself already rewrote files unconditionally, so issue #245's second proposal (rewrite when only the stamp changes) is satisfied by construction; the missing piece was the gate.

raco rivet doctor --release validates in one command and one exit code:

  • generated clients are fresh (the same regeneration check),
  • the committed schema baseline exists and accepts the backend,
  • hand-written host sources call fetch-update-manifest/select-update/download-update/fetch-sibling-asset only with keywords the installed rivet accepts — checked via procedure-keywords against the live functions, so the contract is read from the running rivet instead of duplicated as literals. This is the compile-time defense against the payback #:redirections class (five shipped releases whose update check failed only on user machines),
  • every rivet.git#... pin in the repository is non-empty and consistent with the installed rivet release (the autarx v0.4.1 empty-ref incident: URL# silently resolves to the default branch).

Docs: the update API keyword contract is now a documented stable surface in docs/release-and-updates.md, guarded by a documentation test that parses those bullets against the installed procedures' own contracts, so it cannot drift in either direction. docs/ci.md and docs/ci.zh-CN.md warn about the empty-ref footgun next to the pin examples.

Notes for reviewers

  • Version single-source in a Rivet project is rivet.rktd; there is no VERSION file and product-internal fallback literals (e.g. a product version.rkt) stay product-owned — the generated-file freshness check proves the generated constants equal the manifest, which is the part rivet can know.
  • installed-rivet-release-version resolves the package root by stepping one level up from the rivet sub-collection (collection-file-path only resolves sub-collection dirs); returns #f for packaged CLI copies and the check reports that explicitly.
  • Keyword scanning walks quoted data too (fail-safe), skips the #lang reader line plain read cannot parse, and prunes .rivet, compiled, dist, node_modules, stage trees.

Tests

  • rivet/tests/codegen.rkt: fresh/stale/missing/repaired round-trip on a real scaffolded project.
  • rivet/tests/doctor.rkt: green project passes all five checks; hand-edited stamp, drifted keyword, and empty pin ref each fail with cause-naming detail; the exported scanner reports the live violation.
  • rivet/tests/documentation.rkt: contract bullets must list exactly the installed keyword sets, and only scannable functions.

raco rivet generate --check regenerates all client files in memory and
fails when the tree differs, closing the hand-edited-version-stamp class
(taskly 8c34ed5, fulcrum 973df6b, syncpilot, pdfgist) — the writer and
the gate share one regeneration so they can never disagree about what a
fresh tree looks like.

raco rivet doctor --release validates in one command: generated files
are fresh, the committed schema baseline accepts the backend, hand-
written host sources call fetch-update-manifest/select-update/
download-update/fetch-sibling-asset only with keywords the installed
rivet accepts (procedure-keywords against the live functions, catching
the payback #:redirections class in CI instead of on user machines),
and every rivet.git# pin in the repository is non-empty and consistent
with the installed rivet release (the autarx empty-ref incident).

Documented the update API keyword contract as a stable surface in
docs/release-and-updates.md, guarded by a documentation test that
parses the bullets against the installed procedures so the contract
cannot drift in either direction. Warned about the empty-ref footgun
in docs/ci.md and docs/ci.zh-CN.md. Closes #245. Closes #255.
@turinglambdaai
turinglambdaai merged commit 4f9cef3 into main Oct 16, 2026
23 checks passed
@turinglambdaai
turinglambdaai deleted the feat/release-gate branch October 16, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant