Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,26 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: run spec-check
run: cargo run -p xtask -j 2 -- spec-check

xtask-ci:
name: xtask ci
runs-on: ubuntu-latest
timeout-minutes: 45
env:
# .config/nextest.toml: retry once, run every test, write junit.
NEXTEST_PROFILE: ci
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
# rustup installs the rust-toolchain.toml pin (rustfmt and clippy included).
- name: toolchain
run: |
rustup toolchain install
rustc --version
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
shared-key: xtask-ci
# The pinned tools `cargo xtask tools` builds into .tools/.
cache-directories: .tools
cache-on-failure: true
- name: cargo xtask ci
run: cargo xtask ci
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- `cargo xtask ci` and `cargo xtask install`, with the gates `tools`, `fmt`, `fmt-check`, `clippy`, `test`, `doc-test`, `deny`, `typos` and `machete` (spec 0002, XT-1 to XT-9), and the CI job `xtask-ci`. The make and just targets stay.
- Signals framework, process supervision, and terminal hygiene (`unsigned-gg/kd`): Linux `pidfd` lifecycle management (`pidfd_open`, `pidfd_send_signal`), `PR_SET_CHILD_SUBREAPER` zombie adoption and reaping, negative PGID broadcast signaling, declarative 2-phase graceful shutdown state machine (Drain → Escalate → ForceKill), and RAII `TerminalGuard`. Dual-licensed Apache-2.0 OR MIT.
- Port the cas-substrate release follow-ups (CER-2670): drop the dead `release` trigger and the never-run `attach` job from `sbom.yml` (a release made with `GITHUB_TOKEN` starts no workflows, so neither ever fired), and set `git_release_name = "v{{ version }}"` in `release-plz.toml` so the GitHub release title matches the tag. Spec 0005 names both behaviors.

Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,27 @@ subreapers, command runners, and terminal multiplexers:
|---|---|---|
| **Domain Core** | `crates/kd-domain` | Pure signals, finite-state shutdown transitions, process status. Zero I/O. |
| **Systems Library & CLI** | `crates/kd` | Linux pidfd, subreaper, negative PGID kill, zombie harvest, 2-phase teardown, and RAII terminal hygiene. |
| **Repo Automation** | `xtask/` | Clean Rust automation (`spec-check`, `toolchain-check`, `pin-check`, `fetch-contracts`). No sloppy bash loops. |
| **Repo Automation** | `xtask/` | Clean Rust automation (`spec-check`, `toolchain-check`, `pin-check`, `fetch-contracts`, and the gates `ci` and `install`). No sloppy bash loops. |
| **Specifications** | `specs/` | LeanSpec registry. Architecture changes start as specs, not impromptu PRs. |
| **Quality Gates** | `Justfile`, `Makefile` | Modern `Justfile` with awk-parsing POSIX `Makefile` wrapper. Run `make help` or `just --list`. |
| **Tooling & CI** | `.github/`, `deny.toml`, `lefthook.yml`, `contracts.lock` | Strict git hooks, conventional commits, powerset checks, semver guards, contract pinning. |

---

## Build

```bash
cargo xtask ci # tools, toolchain-check, fmt-check, clippy, test, doc-test, deny, typos, machete
cargo xtask install # ci, then release builds of every binary
```

`cargo xtask ci` needs only cargo and rustup. rustup installs the Rust that
`rust-toolchain.toml` pins, and `cargo xtask tools` (the first step of `ci`)
installs cargo-deny, typos, cargo-machete and cargo-nextest at pinned versions
into `.tools/`. The steps are in spec 0002. The make and just targets still work.

---

## Forging a New Repository

### Option 1: GitHub Template
Expand Down
58 changes: 58 additions & 0 deletions specs/0002-verification-gates-and-evidence.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Evidence from 2026-10-08:
| `make smoke` | Builds the CLI, runs `kd --version`, greps the domain crate for I/O | Before every PR. |
| `make ci` | `fmt-check clippy test doc-test` with `NEXTEST_PROFILE=ci` | What the CI `rust` job runs. |
| `make template-check` | `check`, `spec-check`, `smoke`, then the rename probe | Template repo only. |
| `cargo xtask ci` | `tools toolchain-check fmt-check clippy test doc-test deny typos machete` (XT-7) | What the CI `xtask-ci` job runs. |
| `cargo xtask install` | `ci`, then release builds of every binary (XT-8) | Before installing the binaries. |

The CI jobs `rust` and `hygiene` call these same targets. A gate that passes on
a workstation passes in CI.
Expand Down Expand Up @@ -64,20 +66,76 @@ CPU limit of 10 and runs one job at a time. The pod is ephemeral. No other
user shares it. The `_rust.yml` workflow also sets `CARGO_BUILD_JOBS` to the
same number.

### cargo xtask gates

Operator decision, Christian, 2026-10-13: `cargo xtask` is the one build
entrypoint for every estate repo, with nothing behind it but cargo and rustup.
The xtask gates sit beside the make and just targets above. Nothing is removed.

- **XT-1 (ubiquitous):** xtask shall provide the commands `tools`,
`toolchain-check`, `fmt`, `fmt-check`, `clippy`, `test`, `doc-test`, `deny`,
`typos`, `machete`, `ci` and `install`, and keep every other command under
its name.
- **XT-2 (ubiquitous):** xtask shall keep the version of each tool it runs in
one table: cargo-deny 0.19.9, typos-cli 1.49.0, cargo-machete 0.9.1 and
cargo-nextest 0.9.104.
- **XT-3 (event-driven):** When `tools` runs, xtask shall ask each tool for its
version the way the gates run it, with `.tools/bin` first on `PATH`. Only for
a tool that is missing or at another version shall it run
`cargo install --locked --version <pin> --root .tools --force <crate>`, under
Rust 1.94.1 (`rustup run --install 1.94.1`).
- **XT-4 (unwanted behaviour):** If a tool still reports another version after
its install, then `tools` shall fail and name the tool and both versions.
- **XT-5 (unwanted behaviour):** If `rustc --version` differs from the
`channel` in `rust-toolchain.toml`, then `toolchain-check` shall fail and
name both.
- **XT-6 (ubiquitous):** Each gate shall run from the repository root with
`.tools/bin` first on `PATH`, and without the variables cargo sets for the
xtask binary itself (`CARGO_PKG_*`, `CARGO_MANIFEST_DIR`,
`CARGO_MANIFEST_PATH`, `CARGO_CRATE_NAME`, `CARGO_BIN_NAME`,
`CARGO_PRIMARY_PACKAGE`). cargo-machete reads `CARGO_PKG_NAME` to tell
whether cargo started it. N is `JOBS`, else 2.

| Gate | Runs |
|---|---|
| `fmt` | `cargo fmt --all` |
| `fmt-check` | `cargo fmt --all -- --check` |
| `clippy` | `cargo clippy --workspace --all-targets --locked -j N -- -D warnings` |
| `test` | `cargo nextest run --workspace --locked --build-jobs N`; `cargo test --workspace --locked -j N` when nextest is missing |
| `doc-test` | `cargo test --doc --workspace --locked -j N` |
| `deny` | `cargo deny check` |
| `typos` | `typos` |
| `machete` | `cargo machete` |

- **XT-7 (event-driven):** When `ci` runs, xtask shall run `tools`,
`toolchain-check`, `fmt-check`, `clippy`, `test`, `doc-test`, `deny`,
`typos` and `machete` in that order. It shall stop at the first step that
fails, print one summary line per step, and exit non-zero if a step failed.
- **XT-8 (event-driven):** When `install` runs, xtask shall run `ci`, then
`cargo build --release --locked --workspace --exclude xtask --bins -j N`.
- **XT-9 (event-driven):** When CI runs for a push or a pull request, the job
`xtask-ci` shall run `cargo xtask ci` on the runner the Rust jobs use.

nextest reads `NEXTEST_PROFILE` itself, so CI picks the `ci` profile through
the environment, as `make ci` does.

## Plan

- [x] Write the Makefile targets with exact names from the table above.
- [x] Add `.config/nextest.toml` with profiles `default`, `ci`, `pre-push`.
- [x] Add `toolchain-check` to `xtask`.
- [x] Wire `rust` and `hygiene` CI jobs to the make targets.
- [ ] Prove each gate fails on a planted fault, then passes.
- [ ] Add the xtask gates XT-1 to XT-8, with unit tests named for the clauses.
- [ ] Add the CI job `xtask-ci` (XT-9).

## Test

Run the full gate set with the workstation default.

```bash
make check && make hygiene && make smoke
cargo xtask ci
```

Passing means all three exit 0. Then plant one fault per gate. A misformatted
Expand Down
12 changes: 12 additions & 0 deletions specs/0004-dependency-and-licence-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ Pin it by version and sha256 and record it here.
The `gh` step is temporary. Remove it when the `ci-rust` image ships `gh`
(OPS-1636).

`cargo xtask tools` builds the gate tools from crates.io (spec 0002, XT-2 and
XT-3). The version table lives in `xtask/src/gates.rs`. `cargo install
--locked` builds each one from its published lock file, and crates.io checks
every crate's sha256. They go into `.tools/`, which is gitignored.

| Tool | Version | Licence | Use | Pin |
|---|---|---|---|---|
| `cargo-deny` | 0.19.9, published 2026-06-15 | MIT OR Apache-2.0 | `cargo xtask deny` | crates.io version, `--locked`. The `ci-rust` image bakes the same version. |
| `typos-cli` | 1.49.0, published 2026-08-03 | MIT OR Apache-2.0 | `cargo xtask typos` | crates.io version, `--locked`. The `ci-rust` image bakes the same version. |
| `cargo-machete` | 0.9.1, published 2025-08-15 | MIT | `cargo xtask machete` | crates.io version, `--locked`. |
| `cargo-nextest` | 0.9.104, published 2025-09-15 | Apache-2.0 OR MIT | `cargo xtask test` | crates.io version, `--locked`. |

### Vendoring & offline builds

For airgapped environments or offline reproducibility:
Expand Down
Loading
Loading