reorg: public plumbing for the in-repo Rust workspace and the two-release flow

The engine binaries move from the impeccable-dist channel to this repo's own
GitHub Releases (tag engine-v<ENGINE_VERSION>), and the closed detector the
engine links arrives as detector-v<DETECTOR_VERSION> releases on the same
repo. This commit wires the public side for that; the crates themselves land
in the next commit.

- Launcher (sh + cmd), npm shim, fetch-engine and check-engine-release now
  download from github.com/pbakaus/impeccable/releases/download/engine-v<X>/.
- release.mjs gains `engine`: verifies ENGINE_VERSION against the platform
  package pins and the detector release, tags, pushes; release-engine.yml
  builds the five targets and publishes. check-detector-release.mjs is the
  matching release-order guard (with tests).
- Root Cargo.toml (workspace, lto = false with the reason), rust-toolchain.toml
  (exact pin), DETECTOR_VERSION, /target ignored.
- CI: rust + rust-windows jobs and an oracle job that replays the goldens
  against a source build, warn-only until the first detector release exists;
  ci-test-plan exposes a `rust` output.
- docs/ENGINE.md (the crate map and the closed-detector mechanism) and the
  CLAUDE.md engine, release-order and rules sections.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
This commit is contained in:
Paul Bakaus
2026-09-01 14:05:39 -07:00
co-authored by Claude Fable 5.1
parent 6c474b1c79
commit e355ebf714
20 changed files with 714 additions and 58 deletions
+82 -17
View File
@@ -23,6 +23,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
core: ${{ steps.plan.outputs.core }}
rust: ${{ steps.plan.outputs.rust }}
detector: ${{ steps.plan.outputs.detector }}
live: ${{ steps.plan.outputs.live }}
framework: ${{ steps.plan.outputs.framework }}
@@ -118,25 +119,81 @@ jobs:
- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
name: impeccable-dist-node-${{ matrix.node-version }}
name: impeccable-build-node-${{ matrix.node-version }}
# Ship the packaged zips, not the unpacked Firefox staging tree.
path: |
dist/
!dist/extension-firefox/
retention-days: 7
# Behavior gate: replays the tests/oracle/ goldens against the pinned
# engine binary (ENGINE_VERSION). Without this job the oracle only ever
# The Rust workspace: the engine binary and every crate behind it.
# crates/core/build.rs downloads the prebuilt closed detector archive for
# the pinned DETECTOR_VERSION (docs/ENGINE.md), so this job needs that
# release to exist.
#
# continue-on-error is a release-time toggle: until detector-v<DETECTOR_VERSION>
# is published, the archive cannot be fetched and the job would block every
# PR. Once it is live, flip continue-on-error to false so a Rust regression
# fails CI instead of only annotating it.
rust:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.rust == 'true'
continue-on-error: true
steps:
- name: Checkout repository
uses: actions/checkout@v7
# rust-toolchain.toml pins the exact rustc the detector was built with;
# `rustup show` installs it. Never override the toolchain here.
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: Build
id: build
continue-on-error: true
run: cargo build --workspace --all-targets
- name: Test
if: steps.build.outcome == 'success'
run: cargo test --workspace
- name: Annotate missing detector release
if: steps.build.outcome != 'success'
run: |
echo "::warning title=Rust workspace not built::cargo build failed. If crates/core/build.rs could not download detector-v$(cat DETECTOR_VERSION), the detector release is not published yet; publish it (tag the private detector repo) and flip this job's continue-on-error to false. Otherwise this is a real build failure."
exit 1
# The engine ships a windows-x64 binary (release-engine.yml), so the
# workspace has to build and pass its own tests there. Tests that need a
# browser or the oracle skip when those are absent.
rust-windows:
runs-on: windows-latest
needs: changes
if: needs.changes.outputs.rust == 'true'
continue-on-error: true
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@v2
- run: cargo build --workspace --all-targets
- run: cargo test --workspace
# Behavior gate: replays the tests/oracle/ goldens against a release build
# of the engine from THIS checkout (so a PR is judged on its own source,
# not on the last published binary). Without this job the oracle only ever
# runs on developer laptops: tests/oracle.test.mjs skips cleanly when no
# binary is present, so the default suite is silent about it on CI.
#
# continue-on-error is a release-time toggle: until the first engine
# release is published to impeccable-dist, `bun run fetch:engine` 404s and
# the job would block every PR on an asset that cannot exist yet. Once
# v<ENGINE_VERSION> is live, flip `continue-on-error` to false so oracle
# regressions fail CI instead of only annotating it.
# continue-on-error: same release-time toggle as `rust` above.
oracle:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.oracle == 'true' || needs.changes.outputs.rust == 'true'
continue-on-error: true
steps:
- name: Checkout repository
@@ -155,19 +212,27 @@ jobs:
- name: Install dependencies
run: bun install
- name: Fetch pinned engine binary
id: fetch
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: Build the engine from source
id: build
continue-on-error: true
run: bun run fetch:engine
run: cargo build --release -p impeccable
- name: Replay oracle goldens
if: steps.fetch.outcome == 'success'
if: steps.build.outcome == 'success'
env:
IMPECCABLE_BIN: ${{ github.workspace }}/target/release/impeccable
run: node tests/oracle/run.mjs
- name: Annotate missing engine release
if: steps.fetch.outcome != 'success'
- name: Annotate missing detector release
if: steps.build.outcome != 'success'
run: |
echo "::warning title=Oracle not run::bun run fetch:engine could not download engine v$(cat ENGINE_VERSION) from the impeccable-dist release channel. The 762-case oracle behavior gate did NOT run. Expected until the first engine release is published; after that, publish the release assets and flip this job's continue-on-error to false."
echo "::warning title=Oracle not run::the engine did not build (see the rust job). The oracle behavior gate did NOT run. Expected until detector-v$(cat DETECTOR_VERSION) is published; after that, flip this job's continue-on-error to false."
exit 1
# Release-order guard (triage decision D4). Verifies that the engine release for
# the pinned ENGINE_VERSION is fully published — the five dist binaries + .sha256
@@ -176,7 +241,7 @@ jobs:
# `impeccable install` all dead-end without those assets.
#
# continue-on-error is a release-time toggle: until the first engine release is
# published to impeccable-dist, the assets cannot exist and this job would block
# published, the assets cannot exist and this job would block
# every PR. It emits a loud ::warning instead. Once v<ENGINE_VERSION> is live,
# flip `continue-on-error` to false so a MIS-ORDERED release (skill/CLI ahead of
# the engine) fails CI. release.mjs already hard-fails `release:skill`/`release:cli`.
@@ -200,7 +265,7 @@ jobs:
- name: Annotate missing engine release
if: steps.check.outcome != 'success'
run: |
echo "::warning title=Engine release not ready::The engine release for v$(cat ENGINE_VERSION) is not fully published to impeccable-dist and/or the @impeccable/cli-<os>-<arch> npm platform packages. Releasing the skill/CLI (or merging) now would dead-end the launcher, the npm shim, and impeccable install. Expected until the first engine release exists; after that, publish the engine + platform packages and flip this job's continue-on-error to false so a mis-ordered release fails CI."
echo "::warning title=Engine release not ready::The engine release for v$(cat ENGINE_VERSION) is not fully published (engine-v$(cat ENGINE_VERSION) release) and/or the @impeccable/cli-<os>-<arch> npm platform packages. Releasing the skill/CLI (or merging) now would dead-end the launcher, the npm shim, and impeccable install. Expected until the first engine release exists; after that, publish the engine + platform packages and flip this job's continue-on-error to false so a mis-ordered release fails CI."
test:
runs-on: ubuntu-latest