Repository navigation
feat(ci-baton): capability-routed, attested CI-check Baton + sweep tool - #2
Merged
Merged
Conversation
…ss the mesh The first CI-check Baton: an estate CI check that runs on owned compute (zero GitHub Actions minutes), is routed only to a node with the required capability, and whose verdict is frozen + HMAC-attested into a portable envelope that other nodes verify without re-execution. This is the bag-of-actions answer to the Actions billing wall — the check GitHub would refuse to start runs anyway. Wired across all three layers (per the "always wire first" rule): - Idris (source of truth): add Zig/Rust/Cargo/Deno toolchain capabilities to Protocol.capToTag and mirror them in the Estate manifest. Fix three pre-existing build breaks so `idris2 --build bag.ipkg` is green again (List.find -> import Data.List; with-clause shorthand; non-linear patterns in handoffPreservesLinearity) — mechanical, no change to what the proofs assert. - Zig host: CheckBaton with freeze/thaw + HMAC-SHA256 attestation; check / thaw / nodes subcommands; fail-safe match (an unknown/unprovable capability never matches). - Elixir: Bag.CiBaton, Executor.run_check/thaw_check/list_nodes, Bag.Mesh .submit_check (routes through the orchestrator to a capability-matched node, reading the node list from the single mirrored manifest), Bag.CiSweep batch emitter (the entry point hypatia/ci-health will call). Tests: 6 Zig (incl. tamper-detection) + 11 Elixir (incl. mesh routing + sweep), all green; Idris package builds. Demo: scripts/ci-baton-demo.sh. Design doc: docs/ci-check-baton.adoc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… local half) Wire Bag.CiSweep into a real, invocable tool — `mix bag.sweep [manifest.exs]` — so the emitter has an actual entry point (not just a library function). It runs estate CI checks as Batons on owned compute (zero GitHub Actions minutes) and: - emits ci-health-compatible TSV on stdout: check_id<TAB>BATON-<VERDICT><TAB>node - prints a human summary on stderr - exits 0 if every check passed, 1 otherwise (a CI gate) ci-checks.exs is the dogfood manifest: bag-of-actions runs its OWN checks (zig fmt, zig build test) as Batons — proven green by ci_sweep_manifest_test. This is the bag-of-actions end of the hypatia/ci-health bridge. The hypatia-side caller (a script that invokes this tool and folds Baton verdicts into the estate report) is a separate, push-gated change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
Jun 13, 2026
…ine fix (#3) ## Why PR #2 (`feat/ci-check-baton` → `main`) merged at 16:36 as `c45590f`, but it captured only the CI-baton + sweep work. **Two commits were pushed to that branch *after* it had already merged**, so they landed nowhere: - `1eb58b7` — route Mesh operational logs to stderr (keep `mix bag.sweep` stdout pure TSV) - `7f0db1e` — the **entire typed-budget planner** increment This PR recovers both onto `main` (cherry-picked, re-signed), plus a small follow-up. ## What lands 1. **`fix(ci-baton)`** — Mesh operational logs → `:stderr`. `mix bag.sweep`'s documented contract is "stdout = one TSV line per check"; previously the CI path printed `Mesh: …` lines to stdout, mixing with the TSV. Now stdout is pure machine output. 2. **`feat(ci-baton)`** — typed-budget planner: - Node carries a tropical (min-plus) money `cost` grade, mirrored across the three layers — `Estate.idr` (`cheapestCapable`, the formal objective) → `estate.zig` (`nodes` emits `name<TAB>cost`) → `Executor.node_costs/0`. - `Bag.Budget` — **non-fungible** typed budgets (money / mutation / human_review / repair); exhausting one dimension removes a route. - `Bag.Planner` — cheapest capable node the budget can afford; reserve the paid route for work only it can do; gate mutating/irreversible work on a verifier. - `Bag.ActionResult` — structured residue (echo): a relegated pass still owes the GitHub required-status-check; a dirty partial yields a repair obligation. - `Bag.Mesh.submit_planned` wires Planner → execute → residue. 3. **`chore(ci-baton)`** — drop the unused `MATCH: TRUE/FALSE` debug prints from the Zig `match` subcommand (the Elixir executor reads only its exit code). ## Verification All three layers green on the recovered tree: - **Idris** — `idris2 --build bag.ipkg` → 4/4 ✓ - **Zig** — `zig build test` → rc=0 ✓ - **Elixir** — `mix test` → 19 tests + 1 doctest, 0 failures ✓ Cherry-pick applied with zero conflicts; no build artifacts in the diff. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CI-check Baton — estate CI on owned compute
First implementation of the bag-of-actions thesis: run estate CI checks as Batons on owned compute with zero GitHub Actions minutes, routed only to capability-matched nodes, with frozen + attested verdicts. The check GitHub would refuse to start (billing wall / allow-list) runs anyway.
Wired across Idris ↔ Zig ↔ Elixir
Protocol.capToTag+ Estate manifest. Fixed 3 pre-existing build breaks soidris2 --build bag.ipkgis green (List.find→Data.List,with-clause shorthand, non-linear patterns).CheckBaton(freeze/thaw + HMAC-SHA256 attestation);check/thaw/nodessubcommands; fail-safe capability match (unknown capability never matches).Bag.CiBaton,Executor.run_check/thaw_check/list_nodes,Bag.Mesh.submit_check(routes through the orchestrator to a capability-matched node),Bag.CiSweep+mix bag.sweeptool + dogfoodci-checks.exs.Verification (all green, all local)
idris2 --build bag.ipkgbuilds; 6 Zig tests (incl. tamper-detection); 11 Elixir tests + 1 doctest../scripts/ci-baton-demo.shandmix bag.sweepdemonstrate pass / fail / suspend / thaw / tamper-reject.Notes
482d52e(security: TruffleHog) becauseorigin/maindid not have it yet.🤖 Generated with Claude Code