mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 22:26:38 +03:00
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:
co-authored by
Claude Fable 5.1
parent
6c474b1c79
commit
e355ebf714
+82
-17
@@ -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
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
name: release-engine
|
||||
# Builds the engine binary for every supported target and publishes them, with
|
||||
# sha256 sidecars, as the GitHub Release `engine-v<X>` on this repo. That
|
||||
# release is what the launcher (skill/scripts/impeccable), the npm shim
|
||||
# (cli/bin/cli.js), `impeccable install`, and `bun run fetch:engine` download.
|
||||
#
|
||||
# Trigger: `bun run release:engine` (scripts/release.mjs) verifies
|
||||
# ENGINE_VERSION, the detector release it builds against, and a clean tree,
|
||||
# then pushes the tag. Third-party actions are pinned to commit SHAs so a
|
||||
# moved tag cannot swap the code this workflow runs.
|
||||
on:
|
||||
push:
|
||||
tags: ['engine-v*']
|
||||
permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { os: macos-14, target: aarch64-apple-darwin, short: darwin-arm64 }
|
||||
- { os: macos-13, target: x86_64-apple-darwin, short: darwin-x64 }
|
||||
- { os: ubuntu-latest, target: x86_64-unknown-linux-musl, short: linux-x64 }
|
||||
- { os: ubuntu-latest, target: aarch64-unknown-linux-musl, short: linux-arm64, cross: true }
|
||||
- { os: windows-latest, target: x86_64-pc-windows-msvc, short: windows-x64 }
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||
- name: Check the tag matches ENGINE_VERSION
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
want="engine-v$(tr -d '[:space:]' < ENGINE_VERSION)"
|
||||
[ "$GITHUB_REF_NAME" = "$want" ] || { echo "tag $GITHUB_REF_NAME != $want"; exit 1; }
|
||||
# rust-toolchain.toml pins the exact rustc the prebuilt detector was
|
||||
# built with; `rustup show` installs it. Never override the toolchain here.
|
||||
- name: Install the pinned toolchain
|
||||
shell: bash
|
||||
run: rustup show && rustup target add ${{ matrix.target }}
|
||||
- if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get update && sudo apt-get install -y musl-tools
|
||||
- if: matrix.cross
|
||||
run: cargo install cross --locked
|
||||
- name: Build
|
||||
shell: bash
|
||||
# build.rs in crates/core downloads the pinned detector archive for
|
||||
# this target from the detector-v<DETECTOR_VERSION> release.
|
||||
run: ${{ matrix.cross && 'cross' || 'cargo' }} build --release -p impeccable --target ${{ matrix.target }}
|
||||
- name: Smoke the binary
|
||||
if: ${{ !matrix.cross }}
|
||||
shell: bash
|
||||
run: target/${{ matrix.target }}/release/impeccable${{ runner.os == 'Windows' && '.exe' || '' }} engine-probe
|
||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: impeccable-${{ matrix.short }}
|
||||
path: target/${{ matrix.target }}/release/impeccable${{ runner.os == 'Windows' && '.exe' || '' }}
|
||||
if-no-files-found: error
|
||||
publish:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with: { path: artifacts }
|
||||
- name: Lay out release assets with checksums
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p out
|
||||
for d in artifacts/impeccable-*; do
|
||||
short=$(basename "$d" | sed 's/^impeccable-//')
|
||||
f=$(ls "$d" | head -1)
|
||||
case "$short" in windows-*) dest="out/impeccable-$short.exe" ;; *) dest="out/impeccable-$short" ;; esac
|
||||
cp "$d/$f" "$dest"
|
||||
(cd out && sha256sum "$(basename "$dest")" > "$(basename "$dest").sha256")
|
||||
done
|
||||
ls -la out
|
||||
- name: Publish the GitHub Release
|
||||
env: { GH_TOKEN: "${{ github.token }}" }
|
||||
# No --clobber: a published asset is immutable. A re-run against an
|
||||
# existing release fails on the first existing asset instead of
|
||||
# silently replacing a binary and its sidecar hash.
|
||||
run: |
|
||||
set -e
|
||||
tag="${GITHUB_REF_NAME}"
|
||||
gh release create "$tag" --repo "$GITHUB_REPOSITORY" --title "impeccable engine $tag" \
|
||||
--notes "Prebuilt impeccable engine binaries ($tag). The launcher, the npm shim and impeccable install download these on first run. Docs: https://impeccable.style" out/* || \
|
||||
gh release upload "$tag" out/* --repo "$GITHUB_REPOSITORY"
|
||||
Reference in New Issue
Block a user