Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/tools
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Fimeg bde961c6f2 saf: one spine — device, state, and work under the index
PAF becomes saf/device (history kept), STATE.md dissolves
into saf/state.md with the dated era archived, the substrate
SAF moves up from souveraine, and every agreement points at
saf/INDEX.md and nowhere else. one map, nothing to remember
2026-08-18 09:47:30 -04:00
..
__pycache__ saf: one spine — device, state, and work under the index 2026-08-18 09:47:30 -04:00
ci-status.sh tools: read CI outcomes from the API, and do it automatically 2026-07-28 17:38:44 -04:00
claude-hook-push-ci.sh tools: read CI outcomes from the API, and do it automatically 2026-07-28 17:38:44 -04:00
README.md tools: read CI outcomes from the API, and do it automatically 2026-07-28 17:38:44 -04:00
validate-distribution.py distribution: admit the blueline kernel packages 2026-08-13 14:31:19 -04:00

tools

Cross-repo operational tooling. Lives here rather than in a component repo because it reaches across all of them.

ci-status.sh — what did CI actually do

./ci-status.sh                 # infer the repo from the cwd's git remote
./ci-status.sh souveraine      # name it
./ci-status.sh souveraine 10   # last 10 runs instead of 3
./ci-status.sh --all           # newest run for every repo we own

Exits 0 when the newest run is green or still going, 1 when it failed, so it works as a gate as well as a report. On a failure it drills down by itself: the run, then which job, then the tail of that job's log with the docker noise stripped.

Token comes from $GITEA_TOKEN, else ~/.git-credentials, else the Pixel3Arch remote URL. No new copy of a secret in the tree.

Read this before trusting anything else for build status

journalctl -u gitea-runner is not a status source. It logs task pickup and never outcome, so a run that died thirty seconds in still shows as activity. That habit produced three confident wrong diagnoses in a row on 2026-07-28 while the correct answer sat in the API untouched.

The failure that prompted all this: a pinned action SHA rotted, rust-test died before compiling, and so aarch64-artifact was skipped — not failed. The run looked unremarkable, edge silently stopped publishing, and the phone kept installing a build from days earlier for a working day. Full write-up and the three-layer fix in ../docs/tasks/42-build-outcomes-are-invisible.md.

claude-hook-push-ci.sh — the same thing, without having to remember

A Claude Code PostToolUse hook on Bash. It ignores everything that is not a git push, and after one it prints that repo's CI status.

Wired in ~/.claude/settings.json:

"hooks": {
  "PostToolUse": [
    { "matcher": "Bash",
      "hooks": [ { "type": "command",
        "command": "/home/casey/Projects/SouveraineOS/tools/claude-hook-push-ci.sh" } ] }
  ]
}

It always exits 0 — a status reporter that can block a push is a worse problem than the one it solves.

What it cannot do. A cross build takes ~20 minutes, so straight after a push the honest answer is usually "running". It reliably catches the fail-fast class — pin rot, lint, attribution, a broken workflow edit — which is what actually bites. Catching "publishing quietly stopped" needs the staleness comparison in TASK-42 layer 2, which belongs to souveraine-updater, not to a longer sleep in a hook.

Pinning actions, since this is where it cost us

  • A tag's SHA is immutable. actions/checkout@34e1148 (v4) survived untouched.
  • A branch tip's SHA is not. dtolnay/rust-toolchain force-moves stable every Rust release, which orphaned the pin — the commit still exists as a GitHub object but is reachable from no ref, so act cannot resolve it.
  • If an action must track a branch, pin to a commit on an append-only branch and say in a comment why that branch was chosen.