From f5e490dddd58275aa27f3ee07cfbc6a538724316 Mon Sep 17 00:00:00 2001 From: forkwright Date: Wed, 22 Jul 2026 13:53:47 -0500 Subject: [PATCH 1/3] ci(gate-attestation): adopt hybrid gate mechanism (#262) --- .github/workflows/gate-attestation.yml | 100 ++++++++++++++----------- 1 file changed, 57 insertions(+), 43 deletions(-) diff --git a/.github/workflows/gate-attestation.yml b/.github/workflows/gate-attestation.yml index d2cd82e..4530657 100644 --- a/.github/workflows/gate-attestation.yml +++ b/.github/workflows/gate-attestation.yml @@ -1,3 +1,46 @@ +# WHY(#262 / kanon#2522): replaces the trailer-only passthrough +# (forkwright/.github/.github/workflows/gate-attestation.yml@57d32f7 — pure +# trailer verify, no ai-attribution, no doc-only exemption, no build at all) +# with the fleet hybrid gate. akroasis has never had a compiling/testing CI +# workflow (#262) -- full-gate-build below is the first one: a +# trailer-stamped PR takes the fast path; a trailer-less human PR falls +# through to a real fmt/check/clippy/nextest build; a docs-only PR is exempt +# from that build; ai-attribution runs unconditionally via the reusable +# workflow's own centralized job. +# +# NOTE (#262 residual gap, tracked -- not closed by this change): the +# reusable workflow's check-trailer job waives dependabot[bot] PRs from +# full-gate-build unconditionally (fleet-wide behavior, not overridable +# per-caller), and this workflow triggers on pull_request only (no +# push-to-main compile check). #262's "Done when" (a PR that fails +# `cargo check --workspace` cannot auto-merge; main compiles in CI on every +# push) is therefore only partially met: dependabot bumps still bypass the +# build, and there is no push-triggered compile check. Left as an explicit +# comment on #262 rather than silently claimed done. +# +# fmt/check/clippy/nextest command strings mirror .kanon-ci.toml's stage +# commands verbatim (the local `kanon gate --stamp` SSOT) so a Gate-Passed +# trailer and a green full-gate-build attest the identical stages, per the +# reusable workflow's own contract. --jobs 8 / --build-jobs 8 --test-threads 8 +# match .kanon-ci.toml's concurrency cap (OOM guard on the local gate box; +# harmless headroom on the hosted runner). +# +# system_packages: libusb-1.0-0-dev (rusb -> libusb1-sys) + libudev-dev +# (-> libudev-sys), the only native -sys crates in Cargo.lock that need a +# pkg-config-discoverable Linux system library on the hosted runner +# (core-foundation-sys/io-kit-sys are macOS-only; js-sys/windows-sys/ +# linux-raw-sys are pure-Rust bindings needing no apt package). No +# alsa/cpal/libasound anywhere in the Cargo.toml tree -- akroasis (ἀκρόασις, +# "attentive reception") is RF/mesh/comms, not a DSP/audio-synthesis +# pipeline. +# +# rust_toolchain input intentionally omitted (stays default ""): akroasis +# carries its own rust-toolchain.toml (channel "stable"), auto-detected by +# actions-rust-lang/setup-rust-toolchain inside the reusable workflow. +# +# needs_fleet_repo_token false: the sole git dependency (sphragis) is a +# public forkwright repo with no observed anonymous-fetch rate-limit +# flakiness -- matches the reusable workflow's own conservative default. name: Gate Attestation on: @@ -7,47 +50,18 @@ on: permissions: contents: read -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: - gate-attestation: - name: gate-attestation - runs-on: ubuntu-latest - steps: - - name: Pass trusted automation PRs - if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'release-please[bot]' }} - run: echo "Gate attestation waived for trusted automation actor." - - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6 - if: ${{ github.actor != 'dependabot[bot]' && github.actor != 'release-please[bot]' }} - with: - fetch-depth: 0 - persist-credentials: false - - - name: Verify Gate-Passed trailer - if: ${{ github.actor != 'dependabot[bot]' && github.actor != 'release-please[bot]' }} - run: | - commits=$(git log --format="%H" "origin/${{ github.base_ref }}..HEAD") - if [ -z "$commits" ]; then - echo "ERROR: No commits found in PR" - exit 1 - fi - - found=false - for sha in $commits; do - body=$(git log -1 --format="%b" "$sha") - if echo "$body" | grep -q "^Gate-Passed:"; then - version=$(echo "$body" | grep "^Gate-Passed:" | head -1) - echo "Found gate attestation: $version" - found=true - break - fi - done - - if [ "$found" = false ]; then - echo "ERROR: No Gate-Passed trailer found in any PR commit." - echo "Run the local gate and commit with the trailer." - exit 1 - fi + gate: + uses: forkwright/.github/.github/workflows/hybrid-gate.yml@main + with: + fmt_cmd: "cargo fmt --all -- --check" + check_cmd: "cargo check --workspace --all-targets --jobs 8" + clippy_cmd: "cargo clippy --workspace --all-targets --jobs 8 -- -D warnings" + nextest_cmd: "cargo nextest run --workspace --build-jobs 8 --test-threads 8" + doctest_cmd: "" + system_packages: "libusb-1.0-0-dev libudev-dev" + needs_fleet_repo_token: false + rust_cache_key: "gate-attestation" + ai_attribution_check: true + docs_only_exemption: true + secrets: inherit From d4f1897e1b3546270a723d3d4fa6031357f7a376 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 22 Jul 2026 20:27:40 -0500 Subject: [PATCH 2/3] fix(fleet): migrate Ulid::new to Ulid::generate for ulid 3.0 (#262) The ulid 1.2 -> 3.0 bump removed Ulid::new. The break went uncaught because no CI job compiled the workspace before the hybrid gate landed. Call sites: koinon id newtypes + tamper log tests, semaino alerts. Refs #262 --- crates/koinon/src/id.rs | 4 ++-- crates/koinon/src/tamper_log_tests.rs | 4 ++-- crates/semaino/src/alert.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/koinon/src/id.rs b/crates/koinon/src/id.rs index 0dee10b..2f41317 100644 --- a/crates/koinon/src/id.rs +++ b/crates/koinon/src/id.rs @@ -17,7 +17,7 @@ macro_rules! define_id { /// Generate a new ID backed by a fresh ULID. #[must_use] pub fn new() -> Self { - Self(Ulid::new()) + Self(Ulid::generate()) } /// Reconstruct an ID from an existing [`Ulid`]. @@ -69,7 +69,7 @@ mod tests { #[test] fn entity_id_from_ulid_round_trips() { - let ulid = Ulid::new(); + let ulid = Ulid::generate(); let id = EntityId::from_ulid(ulid); assert_eq!(id.as_ulid(), ulid); } diff --git a/crates/koinon/src/tamper_log_tests.rs b/crates/koinon/src/tamper_log_tests.rs index aca743f..ef02b0c 100644 --- a/crates/koinon/src/tamper_log_tests.rs +++ b/crates/koinon/src/tamper_log_tests.rs @@ -610,8 +610,8 @@ fn large_metadata_no_truncation() { #[test] fn id_types_usable_in_entry_kinds() { - let sid = SignalId::from_ulid(Ulid::new()); - let eid = EntityId::from_ulid(Ulid::new()); + let sid = SignalId::from_ulid(Ulid::generate()); + let eid = EntityId::from_ulid(Ulid::generate()); let _ = LogEntryKind::SignalObserved { signal_id: sid, kind_tag: CompactString::from("t"), diff --git a/crates/semaino/src/alert.rs b/crates/semaino/src/alert.rs index 4efad87..b1b233c 100644 --- a/crates/semaino/src/alert.rs +++ b/crates/semaino/src/alert.rs @@ -192,7 +192,7 @@ impl AlertPipeline { let summary = build_summary(&aggregated.signal.kind, &severity, convergence); let alert = Alert { - id: Ulid::new(), + id: Ulid::generate(), severity, source_signals: vec![aggregated.signal.signal_id], timestamp: Timestamp::now(), @@ -476,7 +476,7 @@ mod tests { fn tracing_sink_emit_does_not_panic() { let sink = TracingSink; let alert = Alert { - id: Ulid::new(), + id: Ulid::generate(), severity: AlertSeverity::High, source_signals: vec![], timestamp: Timestamp::now(), From 272555573795a2cabeacea155e52917992c6ea7e Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 22 Jul 2026 20:37:15 -0500 Subject: [PATCH 3/3] ci(gate-attestation): add protobuf-compiler to system packages (#262) prost-build requires protoc at build time; first compiling CI job surfaced the missing runner package. Refs #262 --- .github/workflows/gate-attestation.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gate-attestation.yml b/.github/workflows/gate-attestation.yml index 4530657..e8daade 100644 --- a/.github/workflows/gate-attestation.yml +++ b/.github/workflows/gate-attestation.yml @@ -32,7 +32,8 @@ # linux-raw-sys are pure-Rust bindings needing no apt package). No # alsa/cpal/libasound anywhere in the Cargo.toml tree -- akroasis (ἀκρόασις, # "attentive reception") is RF/mesh/comms, not a DSP/audio-synthesis -# pipeline. +# pipeline. protobuf-compiler is a build tool, not a -sys library: +# prost-build shells out to protoc at compile time. # # rust_toolchain input intentionally omitted (stays default ""): akroasis # carries its own rust-toolchain.toml (channel "stable"), auto-detected by @@ -59,7 +60,7 @@ jobs: clippy_cmd: "cargo clippy --workspace --all-targets --jobs 8 -- -D warnings" nextest_cmd: "cargo nextest run --workspace --build-jobs 8 --test-threads 8" doctest_cmd: "" - system_packages: "libusb-1.0-0-dev libudev-dev" + system_packages: "libusb-1.0-0-dev libudev-dev protobuf-compiler" needs_fleet_repo_token: false rust_cache_key: "gate-attestation" ai_attribution_check: true