Skip to content

feat(ci-baton): capability-routed, attested CI-check Baton + sweep tool - #2

Merged
hyperpolymath merged 3 commits into
mainfrom
feat/ci-check-baton
Jun 13, 2026
Merged

hyperpolymath merged 3 commits into
mainfrom
feat/ci-check-baton

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

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

  • Idris (source of truth): toolchain capabilities (Zig/Rust/Cargo/Deno) added to Protocol.capToTag + Estate manifest. Fixed 3 pre-existing build breaks so idris2 --build bag.ipkg is green (List.find→Data.List, with-clause shorthand, non-linear patterns).
  • Zig host: CheckBaton (freeze/thaw + HMAC-SHA256 attestation); check/thaw/nodes subcommands; fail-safe capability match (unknown 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), Bag.CiSweep + mix bag.sweep tool + dogfood ci-checks.exs.

Verification (all green, all local)

  • idris2 --build bag.ipkg builds; 6 Zig tests (incl. tamper-detection); 11 Elixir tests + 1 doctest.
  • ./scripts/ci-baton-demo.sh and mix bag.sweep demonstrate pass / fail / suspend / thaw / tamper-reject.

Notes

  • Both commits SSH-signed with the estate signing key.
  • This branch also carries the prior unpushed commit 482d52e (security: TruffleHog) because origin/main did not have it yet.
  • Remaining (separate): hypatia/ci-health bridge (runs on owned compute), real ed25519 attestation key, WASI-compiled check bodies.

🤖 Generated with Claude Code

hyperpolymath and others added 3 commits June 11, 2026 22:16
…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
hyperpolymath merged commit c45590f into main Jun 13, 2026
@hyperpolymath
hyperpolymath deleted the feat/ci-check-baton branch June 13, 2026 16:36
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant