Toolchain admission matrix¶
Status: recorded admissions, current as of 2026-10-19
Purpose and limits¶
Every milestone in this roadmap carries a toolchain-admission clause: a tool a gate runs is selected through the template matrix with a pinned version before that gate runs, and installation is never admission. This page is that matrix. It records, for each tool a gate actually executes, the pinned version, the file or workflow that pins it, what it replaced if it replaced anything, and the milestone that admitted it.
The page is a record of pins, not of results. A row here says that a tool is selected and pinned; it says nothing about whether the gate that uses it passed, and it closes no blocked gate. Native build, image, boot, hardware, accessibility and release remain separate blocked gates.
Two rules follow from the clause and are applied below:
- A tool a gate runs and that nothing pins is a gap, not an admission. Those tools are listed under Not yet admitted rather than quietly inherited from whatever the runner or the workstation happens to ship.
- A pin that replaces an earlier source of the same tool cites both values, so the substitution is auditable from this page alone rather than from a shell history.
Toolchains and gate tools¶
| Tool | Pinned version | How it is pinned | Replaces | Admitted by |
|---|---|---|---|---|
| rustup | 1.29.1 | distribution package cachyos-extra-znver4/rustup 1.29.1-1.1 on the reference profile; CI uses the runner's rustup |
nothing; rustup was absent before D61 | M02 (D61) |
Rust (rustc, cargo) |
1.99.1 | rust-toolchain.toml, channel = "1.99.1", materialised by rustup |
1.99.0 until 2026-10-16; 1.98.1 until 2026-10-14; before it the distribution package rust 1:1.98.1-1.1, removed 2026-09-13 because a distribution package moves with system updates and cannot satisfy a pinned admission |
M02 (D61) |
| clippy | 0.1.99 | rust-toolchain.toml, components = ["rustfmt", "clippy"] |
0.1.98 until 2026-10-14; before it the clippy shipped inside the removed rust 1:1.98.1-1.1 package |
M02 (D61) |
| rustfmt | 1.10.0-stable | rust-toolchain.toml, same components list |
1.9.0-stable until 2026-10-14; before it the rustfmt shipped inside the removed rust 1:1.98.1-1.1 package |
M02 (D61) |
| praetorctl | source commit b0c2be3f19f729dadde197f2085fa01f3f4ccace |
.github/workflows/ci.yml, PRAETOR_REF, verified with git rev-parse before the build |
the previous pin, source commit c565cba50b57a6d6cfa628a0f424d6c9f9a9e569; the pin follows Praetor's main (see below) |
M00 |
| Go toolchain | the version Praetor's own go.mod declares |
actions/setup-go with go-version-file: praetor-src/go.mod, GOTOOLCHAIN=local |
nothing; a build input for praetorctl and, since M09, for the imago make contract-fetch builds, held to imago's own floor below |
M00; M09 for the imago build |
| lefthook | 2.1.12 | .github/workflows/ci.yml, LEFTHOOK_VERSION plus the LEFTHOOK_SHA256 checksum of the downloaded binary |
nothing | M00 |
| reuse | 6.2.0 | .github/workflows/ci.yml, REUSE_VERSION, read by tools/ci_lints.py, run through pipx run by make verify-lints, a prerequisite of make verify-all |
nothing | M00 |
| markdownlint-cli2 | 0.23.2 | .github/workflows/ci.yml, MARKDOWNLINT_VERSION, read by tools/ci_lints.py, run through npx --yes by make verify-lints; separately locked by Praetor's tools/markdownlint/package-lock.json for make docs-lint, which praetorctl audit requires byte-for-byte |
nothing | M00; the Praetor gate with the 7e7746a pin |
| yamllint | 1.38.0 | .github/workflows/ci.yml, YAMLLINT_VERSION, read by tools/ci_lints.py, run through pipx run by make verify-lints, a prerequisite of make verify-all |
nothing | M00 |
| flake8 | 7.3.0 | .github/workflows/ci.yml, FLAKE8_VERSION, read by tools/ci_lints.py, run through pipx run by make verify-lints, a prerequisite of make verify-all |
nothing | M00 |
| black | 26.5.1 | .github/workflows/ci.yml, BLACK_VERSION, read by tools/ci_lints.py, run through pipx run by make verify-lints, a prerequisite of make verify-all |
nothing | M00 |
| shfmt | 3.14.1, as the PyPI wheel shfmt-py 4.2.0 (MIT; shfmt BSD-3-Clause), read on 2026-10-18 | .github/workflows/ci.yml, SHFMT_VERSION, read by tools/ci_lints.py, run through pipx run by tools/shfmt_scope.py in make verify-lints, a prerequisite of make verify-all; style from .editorconfig |
nothing | M00 |
| codespell | 2.4.3, from PyPI (GPL-2.0-only), read on 2026-10-19 | .github/workflows/ci.yml, CODESPELL_VERSION, read by tools/ci_lints.py, run through pipx run over every tracked file by make verify-lints, a prerequisite of make verify-all; skips and the reviewed ignore list in .codespellrc |
nothing | M00 |
| gitleaks | 8.30.1 | .github/workflows/ci.yml, GITLEAKS_VERSION plus the GITLEAKS_SHA256 checksum of the release archive; scans every commit, reviewed false positives in .gitleaksignore |
the dated declared-linters exception the 3bbde07 adoption wrote |
the 3bbde07 pin, 2026-10-13 |
| semgrep | 1.180.0 | .github/workflows/ci.yml, SEMGREP_VERSION, run through pipx run with the local rules in .config/semgrep/hiss.yml only and --metrics=off |
the same exception | the 3bbde07 pin, 2026-10-13 |
| trivy | 0.75.0 | .github/workflows/ci.yml, TRIVY_VERSION plus the TRIVY_SHA256 checksum of the release archive; the binary, not aquasecurity/trivy-action, whose tags the March 2026 compromise rewrote (CVE-2026-33634) |
the same exception | the 3bbde07 pin, 2026-10-13 |
systemd (systemd-repart, systemd-sysupdate) |
floor 261; reference profile systemd 261 (261.3-1-arch), the value the outcomes were recorded on; the reference profile reads systemd 262 (262-1-arch) since 2026-09-25 |
tools/verify_systemd_definitions.py, SYSTEMD_FLOOR = 261 and REFERENCE_PROFILE_SYSTEMD; each tool is taken from PATH, else from /usr/lib/systemd, printed, and held to the floor by its own --version before the gate runs (systemctl --version is printed as a cross-check only); CI runs the gate inside the image pinned below, at systemd 262-1, and again inside the floor image, at systemd 261.3-1 |
nothing | M03 |
| mkosi | 27; distribution package extra/mkosi 27-1 on the reference profile |
build/mkosi.conf, MinimumVersion=27, which mkosi itself enforces, and tools/verify_mkosi_definitions.py, MKOSI_FLOOR = 27 and REFERENCE_PROFILE_MKOSI, read back from mkosi --version before the gate runs; CI runs the gate inside the image pinned below, at mkosi 27.1-1 |
the M01 register's inherited mkosi v24+ floor from export-007, which was a range rather than a pin and which no gate enforced |
M18 (D14, D56) |
| Linux source | none since D112 (2026-10-17); M26 pinned linux-7.2.5, sha256 55ddf0df8325d9dad96fcff7bd93977d22e3f50af06527572af59b77c7632b78 |
retired: build/kernel/source.pin.json and its gate were removed; the kernel the gates boot is the Nucleus release pinned in build/kernel/nucleus-artifact.pin.json |
nothing | M26 (D70), retired by D112 |
| Kernel base configuration | none since D112; M26 applied the two tracked fragments to x86_64_defconfig |
retired with the source pin; the fragments stay, bound to the schema by crates/aegis-fabrica-defs/tests/kernel_fragment.rs |
nothing | M26 (D70), retired by D112 |
| clang (BPF target) | floor 19.0.0; reference profile clang version 22.1.8, distribution package extra/clang 22.1.8-2 |
tools/verify_bpf_objects.py, CLANG_FLOOR and REFERENCE_PROFILE_CLANG, read back from clang --version and clang -print-targets before anything is compiled |
the M26 row recording clang as installed and not admitted, because no gate ran it; M19 runs it | M19 |
| bpftool | floor 7.4.0; reference profile bpftool v7.8.0, distribution package core/bpf 7.2.5-1 |
tools/verify_bpf_objects.py, BPFTOOL_FLOOR and REFERENCE_PROFILE_BPFTOOL, read back from bpftool version |
nothing | M19 |
| libbpf (linked by the loader) | floor 1.5; reference profile 1.7.0, distribution package core/libbpf 1.7.0-1.1 |
tools/verify_bpf_objects.py, LIBBPF_FLOOR and REFERENCE_PROFILE_LIBBPF, read back from pkg-config --modversion libbpf and again at runtime from libbpf_version_string() |
the M01 register's libbpf v1.8, which was a reading of the wrong artefact (see below) |
M19 |
| llvm-strip | floor 19.0.0; reference profile LLVM 22.1.8, same extra/clang 22.1.8-2 toolchain |
tools/verify_bpf_objects.py, LLVM_STRIP_FLOOR, read back from llvm-strip --version |
nothing | M19 |
rt-tests (cyclictest) |
floor 2.10; reference profile cyclictest V 2.10, distribution package rt-tests 2.10-1.1 from cachyos-extra-znver4 |
tools/verify_latency_fixture.py, TOOLCHAIN, read back from cyclictest --help before anything is measured |
nothing; no latency tool was admitted before, and none was installed | M23 |
| Realtime kernel | Nucleus release v7.2.8-realtime-lusoris2: image vmlinuz-7.2.8-lusoris2-realtime, kernel.release 7.2.8-lusoris2-realtime, CONFIG_PREEMPT_RT=y |
build/kernel/nucleus-artifact.pin.json, the pin the M10 gate uses; the gate hashes the image against the pin's sha256 and size before every boot, and the guest reports the release and the option back from inside itself |
M26's linux-7.2.5 build (D70, retired by D112), and the distribution linux-rt package D57 recommended, which is not downloaded, installed or booted here |
M23 (D57, D112) |
| Firecracker | 1.17.0, release archive firecracker-v1.17.0-x86_64.tgz sha256 06094a1108ae9e82aa4c23a775aa92758f53f1175d422270d9d6162cb9ade558, binary sha256 99ad0f5cd0514a88aad0e9ae8cfdb3cc3b4ab9d190e1194602406c786b5de7a5, Apache-2.0 |
build/sandbox/firecracker.pin.json; fetched by make workstation-fetch, hashed again and read back with --version before every run; the jailer is not used |
the distribution package firecracker 1.17.0-1.1 at /usr/bin/firecracker, which M06 probed and no gate runs |
M21 (D58) |
| Guest kernel for Firecracker | vmlinux-6.18.44 from Firecracker's CI artifacts, sha256 d8ced68bd61e27b6813e2c993cc53a4029c59e13210672180591c84109684fe4, configuration sha256 9fb2be18303d2f6e8ec35b3a20ecf1209f54a4ece10114a893cb37beabee7030 |
build/sandbox/firecracker.pin.json; the gate hashes both and requires five configuration options before every run |
nothing; no Firecracker guest was pinned before | M21 |
| swtpm | 0.10.2; reference profile TPM emulator version 0.10.2, distribution package extra/swtpm 0.10.2-1 |
tools/verify_boot_harness.py (M24); tools/verify_attestation.py (M20), read back from swtpm --version before the gate runs |
nothing | M24 (boot harness); M20 (verify-attestation) |
| tpm2-tools | 5.8; reference profile version="5.8", distribution package extra/tpm2-tools 5.8-1 |
tools/verify_attestation.py (M20), read back from tpm2_quote --version before the gate runs |
nothing | M20 (verify-attestation) |
The pinned Rust toolchain is materialised explicitly before the first cargo
gate, because a runner image that ships rustup does not thereby ship the pinned
channel or its components. make verify-rust reports
rustup show active-toolchain and rustup which rustc before the gates run, so
the evidence names the compiler that actually executed rather than a version
string copied from this page.
The praetorctl pin follows Praetor's main branch. The maintainer's standing
rule, which this paragraph records, is that PRAETOR_REF in
.github/workflows/ci.yml moves to the head of Praetor's main whenever main
moves. Between two bumps the pin lags main, so the praetorctl CI builds can
be older than a workstation build of the current head.
Bumps are automated. tools/praetor_bump.py, run on the maintainer's
workstation by the systemd user units make install-praetor-bump installs,
moves the pin whenever Praetor's main has a new head; see
Praetor pin auto-bump. Each bump lands as a pull
request from the one rolling branch chore/praetor-pin-auto and updates the
praetorctl row above, where the previous pin becomes the "Replaces" value. It
runs praetorctl adopt --force from the new commit and puts every
hand-maintained file adopt rewrites back to its content on main: the hook and
editor settings, lefthook.yml and the evasion interceptor. It restores
AGENTS.md, whose rule table carries corrections that apply to this
repository, and recompiles only its text-register block and the projections.
Of the remaining changes it keeps only those that praetorctl audit,
praetorctl compile-context --verify and praetorctl flavor audit fail
without, and the pull request lists each kept and each reverted file. The
bump's own local gate decides only whether a pull request is proposed: it runs
the workstation's linters and Go toolchain, listed under
Not yet admitted, and only the pull request's
Verification gate runs the versions pinned above. The bumps to 7e7746a (#122)
and 7325896 (#130) were made by hand under the same rule.
Crates the workspace pins¶
Direct dependencies are declared once in [workspace.dependencies] in the root
Cargo.toml and referenced by the crate manifest, so a member cannot introduce
a second version of the same crate. Cargo.lock (lock format 4) is committed,
and every gate runs --locked, so a resolution change is a refused build rather
than a silent upgrade. No dependency here replaces an earlier one: the crate is
new at M02, and the MD5 hashing the imported sketch used was dropped for the
SHA-256 trait boundary (D02) rather than substituted crate for crate.
The versions this section names are the versions each crate had when it was
admitted, and they stay as that record. Lock-file maintenance later moves a
resolution inside the requirement Cargo.toml declares without a new
admission, so Cargo.lock holds the current resolution.
tools/test_admission_history.py keeps this table's header and requires every
crate it admits to still be in the lock.
| Crate | Version at admission | How it is pinned | Role | Admitted by |
|---|---|---|---|---|
| base16ct | 1.0.0 | [workspace.dependencies], default-features = false |
lower-case hexadecimal digest rendering and parsing | M02 |
| sha2 | 0.11.0 | [workspace.dependencies], default-features = false |
the single LedgerHasher implementation (D02); since M25 the sha256 of the DMA-BUF read-back in crates/aegis-vulcan-gpu |
M02 |
| thiserror | 2.0.20 | [workspace.dependencies], features = ["std"] |
typed error enums at every boundary | M02 |
| serde | 1.0.229 | [workspace.dependencies], optional, behind the jsonl feature |
JSON Lines rendering, off the hashing path | M02 |
| serde_json | 1.0.151 | [workspace.dependencies], optional, behind the jsonl feature |
JSON Lines rendering, off the hashing path | M02 |
| schemars | 1.2.2 | [workspace.dependencies], default-features = false, features = ["derive"]; used by crates/aegis-fabrica-defs only |
generates the JSON Schemas of both M18 contracts from their Rust types, committed under build/ (D105) |
D105, 2026-09-29 |
| accesskit | 0.25.1 (MIT OR Apache-2.0), crate checksum ad442f58ee04714aaa0ba0a2768c1ea1935b29507bb22ddece8cbbc76db02932 |
[workspace.dependencies], default-features = false, used only by crates/aegis-forum-shell |
the accessibility tree's data model: the P05 canvas model is exported as an accesskit::TreeUpdate; no platform adapter |
M16 (D101) |
| gpui | git revision 56934ec0560bce8929025497411de7f5322fb6ca of zed-industries/zed (package 0.2.2, Apache-2.0), the head of main read on 2026-10-18, committed 2026-10-17 |
[workspace.dependencies], git with rev =, default-features = false, features = ["wayland"]; locked as git+https://github.com/zed-industries/zed?rev=56934ec0...#56934ec0...; used only by crates/aegis-forum-shell-gpui |
the toolkit: the layer-shell surface, canvas painting and the AccessKit integration (ADR-0004) | M28 (D102); licences admitted by D113, table below |
| gpui_linux | the same revision (package 0.1.0, Apache-2.0) | as gpui, features = ["wayland"], no X11 |
the Linux platform gpui runs on, a crate of its own at this revision | M28 (D102) |
| cros-libva | git revision 59384456ac2ae78c0c3e5515f41ef1efd9b802cf of chromeos/cros-libva (package 0.0.13, BSD-3-Clause), the merge of #37 on 2026-09-01 and the head of main on 2026-09-29 |
[workspace.dependencies], git with rev =; locked as git+https://github.com/chromeos/cros-libva?rev=59384456...#59384456...; used only by crates/aegis-scaena |
VA-API decode and DMA-BUF export through Surface::export_prime (D80) |
M27 (D80) |
| smithay-client-toolkit | 0.21.1 (MIT), crate checksum 74dc9ee14b0fdcb535f9556141bacac070c994a977d2240ee455d7438a617f00 |
[workspace.dependencies], default-features = false; used only by crates/aegis-scaena |
the layer surface and the zwp_linux_dmabuf_v1 client over wayland-client's pure-Rust backend; libwayland is neither linked nor loaded |
M27 (D75) |
| rustix | 1.1.5 (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT), crate checksum 891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d |
[workspace.dependencies], features = ["net", "fs", "event"]; used by crates/aegis-scaena; since M21 by crates/aegis-vesta-sandbox, which adds the system feature; since M25 by crates/aegis-vulcan-gpu, which adds mm and param and is the one crate allowed unsafe code (tools/verify_unsafe_home.py) |
sendmsg and recvmsg with SCM_RIGHTS and MSG_CMSG_CLOEXEC, SO_RCVTIMEO and SO_SNDTIMEO, fstatfs, fstat, lseek, poll on the Wayland connection fd under a deadline, and in tests memfd_create (M27); reboot(RebootCommand::Restart), with which the M21 guest init ends its microVM (M21); memfd_create, fcntl_add_seals, mmap and munmap, page_size, and the ioctl calls UDMABUF_CREATE, DRM_IOCTL_PRIME_FD_TO_HANDLE, DRM_IOCTL_PRIME_HANDLE_TO_FD, DRM_IOCTL_GEM_CLOSE and DMA_BUF_IOCTL_SYNC behind SAFETY proofs (M25) |
M27 (D77); the system feature M21; mm and param M25 |
| socket2 | 0.6.5 (MIT OR Apache-2.0), crate checksum c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4 |
transitive since 2026-10-16: no longer in [workspace.dependencies]; it arrives through saeptum-microvm, whose own manifest pins it with default-features = false, features = ["all"] |
the guest's AF_VSOCK listener: SockAddr::vsock is a safe constructor of a sockaddr_vm, which rustix 1.1.5 does not offer and the workspace's unsafe_code = "forbid" would otherwise require |
M21 |
| saeptum-capsule | git revision 997a1b34f0a2912de8bf67231846b3af512ff041 of plurano/saeptum (package 0.1.0, EUPL-1.2), the squash merge of saeptum#16 on 2026-10-17 |
[workspace.dependencies], git with rev =; used only by crates/aegis-vesta |
the capsule registry, ring, microVM and VMM controllers and the wire form of their bounded values, cut from aegis-vesta (cut unit CUT-1632-03) |
CUT-1632-03, 2026-10-16 |
| saeptum-microvm | git revision 997a1b34f0a2912de8bf67231846b3af512ff041 of plurano/saeptum (package 0.1.0, EUPL-1.2) |
[workspace.dependencies], git with rev =; used only by crates/aegis-vesta-sandbox |
the Firecracker configuration, the hybrid-vsock line framing, the VM process, the guest listener and the guest's boot-complete signal, cut from aegis-vesta-sandbox (cut unit CUT-1632-04); carries socket2 and libc |
CUT-1632-04, 2026-10-16 |
| tornus-geometry | git revision df214e113701297d995cd3d14ffd877bd0cf8d27 of plurano/tornus (package 0.1.0, EUPL-1.2), the head of main read on 2026-10-18; since the cut commit b2710c8ef386275db352bab06bfa4b8eb6859411 only repository governance files changed, not the crate source |
[workspace.dependencies], git with rev =; used only by crates/aegis-hephaestus |
the geometry and meshing bounds, the STEP source name, the solver admission and the wire form of the bounded values, cut from aegis-hephaestus (cut unit CUT-1632-01) |
CUT-1632-01, 2026-10-16 |
At admission, Cargo.lock resolved the graph the first seven pull in to: block-buffer
0.12.1, cfg-if 1.0.4, cpufeatures 0.3.1, crypto-common 0.2.2, digest 0.11.3,
dyn-clone 1.0.20, hybrid-array 0.4.15, itoa 1.0.18, libc 0.2.189, memchr 2.8.3,
proc-macro2 1.0.107, quote 1.0.47, ref-cast 1.0.27, ref-cast-impl 1.0.27,
schemars_derive 1.2.2, serde_core 1.0.229, serde_derive 1.0.229,
serde_derive_internals 0.30.0, syn 3.0.5, thiserror-impl 2.0.20, typenum 1.20.1,
unicode-ident 1.0.24, uuid 1.26.1 and zmij 1.0.23.
crates/aegis-justitia/tests/manifest_hygiene.rs asserts that the lock
contains the SHA-256 implementation and no MD5 implementation under any
spelling.
schemars was admitted on 2026-09-29 against the crates.io API, read with a
User-Agent: 1.2.2 of 2026-07-27 is its newest stable release (D69), licensed
MIT, and the lock's checksum 687274d293b6... is the one crates.io publishes.
It adds five crates, each at its newest release and each with the checksum
crates.io publishes: schemars_derive 1.2.2 (MIT) and dyn-clone 1.0.20, ref-cast
1.0.27, ref-cast-impl 1.0.27 and serde_derive_internals 0.30.0 (each MIT OR
Apache-2.0). Every one is a permissive licence a EUPL-1.2 work may depend on,
none is vendored into the repository, so REUSE is unchanged, and all of them
resolve on the syn 3.0.5 already in the lock. default-features = false drops
schemars' std feature, which implements schemas for standard-library
collections these types do not use.
accesskit 0.25.1, admitted by M16 on 2026-09-29, was the newest release on the
crates.io API that day, published 2026-09-25. With its features off it
resolves one crate more, uuid 1.26.1 (Apache-2.0 OR MIT, the newest release,
published 2026-09-10), with no feature and no dependency of its own. Its
rust-version is 1.87, above the 1.85 the workspace declared when it was
admitted; the pinned toolchain is 1.99.1, so every gate compiles it, and
Cargo's MSRV-aware resolver picks it only because 0.25.1 is the lowest
version the requirement admits. Since D111 the workspace declares the pinned
toolchain, 1.99.1 (see below).
crates/aegis-forum-shell/tests/manifest_hygiene.rs asserts the
declaration, the lock entry, and that the crate's own dependency closure
(D78) holds no gpui, winit, wayland-client, zbus, atspi, accesskit_unix or
tokio.
gpui and gpui_linux were admitted for M28 on 2026-10-17 at the zed commit
322cd509dcccaee1f6bc44725d270598ae8171ad, the head of main that day
(read with the forge API), and moved together on 2026-10-18 to
56934ec0560bce8929025497411de7f5322fb6ca, the head of main that day.
The two commits between them add an optional hot-reload feature to gpui,
which the workspace does not enable, and change zed's agent crates, which it
does not take; the lock gained no package.
Both are declared once, with rev = and Wayland only, and are used only by
crates/aegis-forum-shell-gpui, the member gpui enters through, so
aegis-forum-shell keeps its toolkit-free closure.
crates/aegis-forum-shell-gpui/tests/admission.rs reads the declaration and
the lock source back, refuses a branch, a tag or another rev, and refuses any
licence expression in the member's closure (D78: every platform, every
dependency kind) that it does not record. Every expression it records is
permissive or offers a permissive arm, except MPL-2.0, which it records for
two packages only. D113 admitted the set on 2026-10-17 on these terms:
| Package | Version | Expression | Arm taken | Terms |
|---|---|---|---|---|
| option-ext | 0.2.0 | MPL-2.0 |
MPL-2.0 | unmodified, from crates.io, reached through zed-font-kit, dirs 6 and dirs-sys; the test holds its lock entry to the index checksum 04744f49…6e7d |
| dwrote | 0.11.5 | MPL-2.0 |
MPL-2.0 | unmodified, from crates.io, reached through zed-font-kit on Windows only; the test holds its lock entry to the index checksum 9e1b3553…4d02 |
| self_cell | 1.3.0 | Apache-2.0 OR GPL-2.0-only |
Apache-2.0 | as published |
| FreeType (system library) | as the host provides | FTL OR GPL-2.0 |
FTL | linked through freetype-sys 0.20.1 (MIT) |
| zed-font-kit | 0.14.1-zed at 94b0f28166665e8fd2f53ff6d268a14955c82269 |
MIT OR Apache-2.0 |
either | second git source, zed-industries/font-kit, at the revision the zed commit locks |
MPL-2.0 is file-level copyleft, so a third MPL-2.0 package, or a patch to
either of the two, is a new decision first; the test fails on the third and on
a changed, doubled or overridden lock entry of the two.
gpui renders through wgpu on Wayland: gpui_linux's wayland feature
requires gpui_wgpu, so wgpu 30.0.0 (a gfx-rs/wgpu git revision) is in
Cargo.lock. ADR-0003 keeps wgpu out of P17's first slice, so
aegis-scaena's closure sweep still refuses it, and its lock-wide check
now refuses wgpu in every member's closure but aegis-forum-shell-gpui's
(Servo, WebRender, mozjs and iceoryx2 stay refused anywhere in the lock).
At this commit gpui resolves accesskit_unix 0.22.1, two minor versions behind
the newest release, 0.24.0 of 2026-09-25; that is D69 drift, kept because the
version is the one the pinned zed commit resolves. Its zbus is 5.19.0 and its
atspi 0.29.0. It also resolves accesskit 0.24.1, beside the 0.25.1 M16
admitted: zed main still declares accesskit 0.24.0, and 0.25.1 is not
source-compatible with 0.24.1 for aegis-forum-shell (TreeInfo and TreeId
do not exist there, measured on 2026-10-17), so the two versions coexist in the
lock and the conversion between them is M28's to write and test (criterion 1's
second branch). aegis-forum-shell's own closure still holds exactly one
accesskit, 0.25.1, which its manifest-hygiene test now reads from its closure
rather than counting lock entries.
Admitting gpui changes the features Cargo unifies over a whole-workspace build:
serde_json gains preserve_order, among others. aegis_fabrica_defs::schema
therefore sorts every object's keys before it renders the D105 schemas, so the
committed files are the same bytes whether or not gpui is in the build; the
JSON values are unchanged.
The three M27 crates were admitted on 2026-09-29, each read that day from the
crates.io API or with git ls-remote: smithay-client-toolkit 0.21.1
(published 2026-07-23) and rustix 1.1.5 (2026-09-16) are the newest releases,
and each lock checksum is the one crates.io publishes; cros-libva's newest
release is still 0.0.13 of 2024-12-06, which fails to compile against libva
2.24.1, so the git revision D80 names is pinned and is the head of main.
With Cargo's MSRV fallback off (CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS=allow,
D69), the three resolve 46 crates more, each at the newest release its
dependents' requirements admit: aho-corasick 1.1.5, bindgen 0.70.1, bitflags
2.13.2, cc 1.5.1, cexpr 0.6.0, clang-sys 1.9.1, cursor-icon 1.2.0, downcast-rs
1.2.1, either 1.18.0, errno 0.3.14, find-msvc-tools 0.1.14, glob 0.3.4,
itertools 0.13.0, libloading 0.8.9, linux-raw-sys 0.12.1, log 0.4.34, memmap2
0.9.11, minimal-lexical 0.2.1, nom 7.1.3, pkg-config 0.3.34, prettyplease
0.2.37, quick-xml 0.41.0, regex 1.13.1, regex-automata 0.4.18, regex-syntax
0.8.11, rustc-hash 1.1.0, shlex 1.3.0 and 2.0.1, smallvec 1.16.2, syn 2.0.119,
thiserror 1.0.69, thiserror-impl 1.0.69, wayland-backend 0.3.17,
wayland-client 0.31.15, wayland-csd-frame 0.3.0, wayland-cursor 0.31.14,
wayland-protocols 0.32.13, wayland-protocols-experimental 20251230.0.3,
wayland-protocols-misc 0.3.12, wayland-protocols-wlr 0.3.12, wayland-scanner
0.31.11, wayland-sys 0.31.11, windows-link 0.2.1, windows-sys 0.61.2, xcursor
0.3.11 and xkeysym 0.2.1. Their licences, read from cargo metadata --locked,
are MIT, Apache-2.0, BSD-3-Clause, ISC, or a choice among MIT, Apache-2.0,
Zlib and the Unlicense; every one is permissive and none is vendored into the
repository, so REUSE is unchanged. No existing lock entry changed version.
Two crates resolve a second major version beside the workspace's own:
thiserror 1.0.69 through cros-libva beside thiserror 2.0.20, and syn 2.0.119
through bindgen, prettyplease and thiserror-impl 1.0.69 beside syn 3.0.5.
Since two thiserror versions are locked, Cargo writes every thiserror 2
dependency line version-qualified ("thiserror 2.0.20"), and the lock-entry
tests of crates/aegis-athena and crates/aegis-tellus strip that suffix
before they compare their exact name lists.
socket2 was admitted on 2026-09-29 against the crates.io API, read with a
User-Agent: 0.6.5 of 2026-07-13 is its newest stable release (D69), licensed
MIT OR Apache-2.0, and the lock's checksum is the one crates.io publishes. It
resolves no crate the lock did not already carry: its dependencies are libc
0.2.189 on Unix and windows-sys 0.61.2 on Windows, both locked before M21. The
lock gained exactly three packages, socket2 and the two new members, and no
existing entry changed version. socket2 declares rust-version 1.70, below the
pinned toolchain. rustix's system feature enables linux-raw-sys's system
module and adds no package; Cargo does not lock features.
On 2026-10-16 the code that used socket2 moved to saeptum-microvm, and
the workspace table stopped declaring it; the lock still carries socket2
0.6.5 with the same checksum. The three cut crates are public repositories
of the plurano organisation, pinned by rev = so the lock records the exact
commit. Their manifests declare serde, serde_json and thiserror at the
versions this workspace already locks, and the lock gained exactly the three
packages saeptum-capsule, saeptum-microvm and tornus-geometry.
On 2026-10-17 both saeptum crates moved together from dd67f6e to
92b57ed and tornus-geometry from ad996c1 to b2710c8. Between those
revisions the crates' public items are unchanged: saeptum split the guest
accept loop into a crate-private function and added tests, CI, REUSE and
cargo-deny configuration; tornus added tests and the same configuration.
The lock changed only the three source revisions. Renovate groups the two
saeptum crates, since one revision each would lock saeptum-capsule twice.
Later on 2026-10-17 both saeptum crates moved from 92b57ed to 24eef8c
for M22's footprint. That revision touches only saeptum-microvm: it adds
RunningVm::pid, an opt-in Firecracker boot timer
(LaunchOptions::with_boot_timer, RunningVm::start_with) and their
tests; RunningVm::start is unchanged. The lock changed only the two
source revisions.
Later still on 2026-10-17 both saeptum crates moved from 24eef8c to
d5e6b94 for M22's boot time. That revision again touches only
saeptum-microvm: it adds guest::signal_boot_complete and its constants,
the guest's write of the boot-complete byte through /dev/mem, under one
dated unsafe exception (category D, expires 2027-02-14) that
tests/unsafe_exception.rs enforces; the crate's lint tables are restated
with unsafe_code = "deny", and it now depends on libc. libc 0.2.190 was
already in the lock; the lock changed the two source revisions and added
libc to saeptum-microvm's dependencies.
Last on 2026-10-17 both saeptum crates moved from d5e6b94 to
997a1b3 for M22's measured figures. That revision touches only
saeptum-capsule: it adds Measured, replaces SCAFFOLD_BOOT_TIME_MS with
MEASURED_BOOT_TIME_MS and MEASURED_FOOTPRINT_KIB, and replaces the row
field declared_boot_time_ms with measured_boot_time_ms. No crate here read
either removed name. The lock changed only the two source revisions.
The highest rust-version any resolved package declares is 1.87
(accesskit 0.25.1), above smithay-client-toolkit's and wayland-protocols' 1.86.
M27 set the workspace's rust-version to that value, and raising it from 1.85
switched on clippy's manual_is_multiple_of, whose three findings were
rewritten with is_multiple_of. The value was false: the workspace uses
let-chains, stable since 1.88, and cargo +1.87 check --workspace failed with
ten E0658 errors on 2026-10-13. D111 replaced the rule: the workspace declares
the rust-toolchain.toml pin, 1.99.1, the only toolchain any gate builds on,
and crates/aegis-scaena/tests/manifest_hygiene.rs holds the declaration to
the pin and every resolved package's rust-version at or below it.
Crates pinned by git revision¶
A crate taken from a git revision instead of a crates.io release has no
release a reader can look up, and Renovate's dashboard reports new commits
without saying why the pin exists. Each such crate therefore has one row here:
the repository it comes from, the full commit, why it is not a crates.io
release, and what makes the pin due for review (issue #224).
tools/verify_crate_pins.py runs in make verify-all and fails when this
table and the workspace disagree:
- a git dependency in
[workspace.dependencies]has no row, or a row names a crate the workspace does not take from git; - the source or commit of a row differs from the manifest's
gitandrev; - a git dependency is pinned by
branch,tagor a short revision instead of a full 40-characterrev; - a member manifest declares a
gitdependency of its own, outside the workspace table; - the
Cargo.locksource of a pinned crate is not exactlygit+<source>?rev=<commit>#<commit>, or the lock carries a git package with no row; - a reason or review trigger is empty.
A Renovate pull request that moves a revision fails this check until it also updates the row. That is intended: the row records the new commit, and the reason is re-read when it moves.
| Crate | Source | Commit | Reason | Review trigger |
|---|---|---|---|---|
cros-libva |
https://github.com/chromeos/cros-libva |
59384456ac2ae78c0c3e5515f41ef1efd9b802cf |
the newest crates.io release, 0.0.13 of 2024-12-06, fails to compile against libva 2.24.1; D80 names this revision | a crates.io release above 0.0.13 that builds against the libva floor, or a Renovate revision pull request |
saeptum-capsule |
https://github.com/plurano/saeptum |
997a1b34f0a2912de8bf67231846b3af512ff041 |
cut from aegis-vesta into a plurano repository (CUT-1632-03) and not published on crates.io |
a crates.io release, or a saeptum revision Aegis needs; moves together with saeptum-microvm |
saeptum-microvm |
https://github.com/plurano/saeptum |
997a1b34f0a2912de8bf67231846b3af512ff041 |
cut from aegis-vesta-sandbox into a plurano repository (CUT-1632-04) and not published on crates.io |
a crates.io release, or a saeptum revision Aegis needs; moves together with saeptum-capsule |
tornus-geometry |
https://github.com/plurano/tornus |
df214e113701297d995cd3d14ffd877bd0cf8d27 |
cut from aegis-hephaestus into a plurano repository (CUT-1632-01) and not published on crates.io |
a crates.io release, or a tornus revision Aegis needs |
gpui |
https://github.com/zed-industries/zed |
56934ec0560bce8929025497411de7f5322fb6ca |
M28 toolkit; D102 takes it from one zed commit, and gpui_linux, which it runs on, has no crates.io release (index checked 2026-10-17) |
a gpui crates.io release, or a zed revision M28 needs; moves together with gpui_linux |
gpui_linux |
https://github.com/zed-industries/zed |
56934ec0560bce8929025497411de7f5322fb6ca |
the Linux platform of gpui (D102), built with the wayland feature alone; no crates.io release (index checked 2026-10-17) |
moves together with gpui |
Git sources a pinned crate brings in¶
A pinned crate can itself take packages from git. Those packages appear in
Cargo.lock but in no manifest of this workspace, so the table above cannot
name them. Each such source has one row here: the commit, the pinned crate
that carries it, and every package the lock takes from it.
tools/verify_crate_pins.py fails when a carried package's lock source is not
exactly git+<source>?rev=<commit>#<commit>, when the carrier has no row in the
table above, when a package is listed twice or also pinned directly, or when a
git package in the lock is covered by neither table.
| Source | Commit | Carried by | Packages | Review trigger |
|---|---|---|---|---|
https://github.com/zed-industries/zed |
56934ec0560bce8929025497411de7f5322fb6ca |
gpui |
collections, derive_refineable, gpui_macros, gpui_shared_string, gpui_util, gpui_wgpu, http_client, refineable, scheduler, sum_tree, ztracing, ztracing_macro |
moves with the gpui row |
https://github.com/gfx-rs/wgpu |
3b3506ea31154edc04de64debda0e780cba2639c |
gpui |
naga, naga-types, wgpu, wgpu-core, wgpu-core-deps-apple, wgpu-core-deps-emscripten, wgpu-core-deps-linux-android-bsd, wgpu-core-deps-wasm, wgpu-core-deps-windows, wgpu-hal, wgpu-naga-bridge, wgpu-sync, wgpu-types |
a gpui revision that moves the wgpu commit zed's workspace names |
https://github.com/zed-industries/font-kit |
94b0f28166665e8fd2f53ff6d268a14955c82269 |
gpui |
zed-font-kit |
a gpui revision that moves the font-kit commit; licence terms recorded in D113 |
The systemd floor, and why it is a floor rather than a pin¶
The Rust rows above pin an exact toolchain because rust-toolchain.toml can
materialise it. systemd cannot be materialised that way: it is the host's init
system, and the gate runs the copy the machine already has. The admission is
therefore a floor plus a recorded reference value, and both halves are
mechanical:
SYSTEMD_FLOOR = 261intools/verify_systemd_definitions.py. Each tool the gate runs is held to it by that binary's own--version. Below it the gate prints why it did not run, naming the tool, its path, its banner and the floor, and does not report a pass.REFERENCE_PROFILE_SYSTEMD = "systemd 261 (261.3-1-arch)", the exact first line ofsystemctl --versionon the reference profile on 2026-09-13. It is the value the negative and boundary outcomes indocs/build/definitions.mdwere observed on.
tools/test_systemd_definitions.py asserts that the floor and the recorded
reference value agree, so raising one without the other fails the gate rather
than passing silently. A future floor change is then a visible diff in this
page and in that constant, not an assumption inherited from whatever the
workstation happens to ship.
The reference profile moved to systemd 262 (262-1-arch) on 2026-09-25, and
the floor and the recorded reference value were left at 261 on purpose. On
2026-09-28 the gate ran on 262, and eight of its nine cases reproduced the
outcomes recorded on 261. The ninth, the --root= case, was restaged so that it
holds on both releases. It then passed on 262 and again on the 261.3 tools
extracted from the cached package; docs/build/definitions.md records both
runs. Raising the floor to 262 would drop that 261 evidence without adding any.
Until 2026-10-17 no recurring run held the floor itself: CI ran the gate only at
262-1, so a 261 host passed the version check on the 2026-09-28 run alone (gap
audit C13-2, #231). CI now runs the gate a second time inside the floor image
described below, at systemd 261.3-1, the release the reference outcomes were
recorded on. tools/test_definitions_container.py requires that image's systemd
major to equal SYSTEMD_FLOOR and its version to be the one
REFERENCE_PROFILE_SYSTEMD names, so raising the floor without moving the image
fails the gate.
What the floor does not claim: that an older systemd cannot read these
definitions. It claims only that the exit codes and diagnostics this repository
records were observed on 261, and that a gate running below the floor would be
reporting against unobserved behaviour. The ubuntu-24.04 runner ships an older
systemd, so CI runs the gate inside a pinned image instead (see the definition
gates' container below); the definition parser crates/aegis-fabrica-defs runs
everywhere and covers the same files without systemd. Until 2026-09-28 the
stated reason on the ubuntu-24.04 runner was the wrong one: its systemd
255.4-1ubuntu8.17 ships systemd-sysupdate only in /usr/lib/systemd, and the
gate looked on PATH alone, so CI printed SKIP: systemd-sysupdate not on PATH
(read in the logs at 61f2fe1 and 020bcd5). With the libexec step the gate
finds the tool there and stops on the floor: CI run 38304569459 for #200, which
required the gate without the container, printed systemd-sysupdate at
/usr/lib/systemd/systemd-sysupdate reports 'systemd 255 (255.4-1ubuntu8.17)',
below the admitted floor systemd 261 and failed.
The mkosi pin, and why its floor enforces itself¶
mkosi is a distribution package like systemd, so it cannot be materialised from
a file in this repository the way rust-toolchain.toml materialises a Rust
toolchain. Its admission is therefore the same shape as the systemd one -- a
floor plus a recorded reference value -- with one addition that systemd has no
equivalent for:
MinimumVersion=27inbuild/mkosi.conf. mkosi reads it and refuses a configuration that asks for a newer mkosi than the one running, so the floor is enforced by the tool rather than by a document. Raising theMinimumVersionabove the installed version was observed to printmkosi 28 or newer is required by this configuration (found 27)and exit 1 on the reference profile; setting it to the floor itself exits 0. Both outcomes are cases intools/verify_mkosi_definitions.py.MKOSI_FLOOR = 27andREFERENCE_PROFILE_MKOSI = "mkosi 27"in that gate. Below the floor the gate prints why it did not run, naming the host version, the floor and the recorded package, and does not report a pass.tools/test_mkosi_definitions.pyasserts that the floor and the recorded reference value agree.
What the pin replaces is recorded in the register: export-007 carried a floor of
"version 24 or later", a range that nothing enforced and that no gate read. M03
recorded mkosi as installed and deliberately not admitted, because no gate
there ran it. M18 admits it, because decision D56 keeps image-definition
validation in Aegis while Imago is a scaffold, and make verify-mkosi now runs
mkosi summary over build/mkosi.conf.
What the row does not claim: that an image was built. mkosi summary
resolves configuration and prints it; it downloads nothing, writes nothing into
the repository and constructs no image. The image gate stays blocked.
The definition gates' container (M03, M18)¶
The systemd and mkosi rows above are floors, because both tools are
distribution packages the host provides. The ubuntu-26.04 runner provides
systemd 259 and no mkosi, below both floors, so CI cannot run either gate on
the runner's own tools. CI runs them instead inside a local image whose every
input build/definitions/toolchain.pin.json pins exactly:
| Input | Pinned value | Role |
|---|---|---|
| base image | docker.io/library/archlinux:base-20261004.0.606936@sha256:4e77cf2ea5f410e6f8be5abf93ccf17ce2436e87a138c167208356711a405dbd; linux/amd64 sha256:2fd1ae548076c67bcd41098ddd44e799058010e8d55f085d453dbb890e706860 |
pulled by digest only; its dated tag matches the snapshot, so the install upgrades and never downgrades |
| Arch Linux Archive snapshot | 2026/10/04 |
the only mirror pacman reads while the image is built |
systemd |
262-1 |
systemd-repart and systemd-sysupdate for make verify-systemd |
mkosi |
27.1-1 |
mkosi summary for make verify-mkosi |
python |
3.14.7-1 |
runs the two gate scripts |
dosfstools |
4.2-5 |
Format=vfat in build/repart.d/00-esp.conf |
mtools |
1:4.0.49-1 |
mcopy, which systemd-repart runs to copy CopyFiles= into the vfat ESP of build/repart.d/00-esp.conf |
erofs-utils |
1.9.4-1 |
Format=erofs in build/repart.d/10-root-a.conf |
btrfs-progs |
7.1-1 |
Format=btrfs in build/mkosi.extra/usr/lib/repart.d/20-var.conf |
cryptsetup |
2.8.8-1 |
Encrypt=tpm2 in build/mkosi.extra/usr/lib/repart.d/20-var.conf |
Without mtools, systemd-repart formats the ESP and then stops with
Could not find mcopy binary. as soon as the tree it copies holds a file. Before
2026-10-18 neither image carried it, and the repart cases passed only because
their scratch root had nothing under /boot or /efi, so an ESP with no UKI
went unnoticed until Imago run 39090040772 booted one. The scratch root now
holds a PE-headed EFI/BOOT/BOOTX64.EFI, and the repart gate reads each layout
case's image with build/mkosi.postoutput.d/image_layout.py: repart/positive
must hold the UKI and a root, and repart/layout-planted-empty-esp, the
committed definitions without the two CopyFiles= lines that run lacked, must
be refused as missing the UKI. LayoutCaseTests in
tools/test_systemd_definitions.py covers the cases.
make definitions-fetch is the one networked step. It pulls the base image,
installs the packages from the snapshot, and removes the image again unless
pacman -Q reports every package at exactly the version above. The pull and
the build are tried up to three times, 30 and then 60 seconds apart, so one
stalled archive mirror or registry does not fail the run; when all three fail,
the message names the image, the mirror and each attempt. A version mismatch is
not retried. FetchRetryTests in tools/test_definitions_container.py covers
both paths. A run against an unreachable mirror (127.0.0.1:9) on 2026-10-14
retried twice and then failed in 99 seconds with that message.
The archive server is a single host, and an outage of several minutes outlasts
the retries (#290: three runs failed that way on 2026-10-17). A fetch therefore
has a second source: when AEGIS_DEFINITIONS_CACHE names a directory, a fetch
that built the image saves it there with the engine's save, one archive per
pin, and a fetch whose attempts against the server all failed loads that
archive instead. The loaded image must carry the pin's tag and passes the same
pacman -Q check as a built one, so a saved image off its pin is refused; with
neither source available the fetch fails and names both. CI keeps the directory
in an Actions cache keyed by the pin file's hash, one entry for each image.
SecondSourceTests in tools/test_definitions_container.py covers the planted
outage, the refused image and both sources down. On 2026-10-17 the floor image
went through that path with podman: saved (529 MB), removed, then loaded through
a planted outage and checked at its pinned versions; without the archive the
same run failed and named both sources.
An Actions cache saved by a pull request run is scoped to that pull request's
merge ref, so the run on main after a pin change cannot restore it: run
39029749159 on main found no floor image although #291 had saved one, and failed
with both sources down. A pull request run whose cache missed therefore also
uploads the image as an artifact named after the cache key
(actions/upload-artifact v7.0.2, kept 14 days), and a run whose cache missed
first runs tools/definitions_handoff.py. It takes the newest unexpired
artifact of that name whose run came from this repository, never a fork, and
extracts only the archive the pin names into the cache directory; the fetch then
treats it as its second source, with the same version check. Finding none is a
printed skip, and the fetch still fails by name when the server is down too.
tools/test_definitions_handoff.py covers the planted double outage with only a
handed-off image present, its twin without one, and fork, expired and malformed
artifacts.
A run that sets
AEGIS_DEFINITIONS_CONTAINER=1 then runs each gate inside that image with
--pull=never, --network=none, a read-only root file system and the
repository mounted read-only, and prints the image and snapshot it used. A run
that selects the container and finds no image fails; it never falls back to the
host's tools. CI sets the variable and names both gates in
AEGIS_REQUIRED_GATES, so a gate that cannot run there fails the required
check instead of skipping.
tools/test_definitions_container.py reads this table back: each package and
version, the image reference and the snapshot must match the pin file, and the
pinned systemd and mkosi must be at or above the gates' floors.
What the container does not change: the floors and reference values above. A host with its own systemd 261 or newer and mkosi 27 or newer still runs the gates on its own tools when the variable is unset.
The systemd floor image (C13-2)¶
The container above holds systemd 262-1, above the floor. The systemd gate
admits every release from SYSTEMD_FLOOR up, so CI also runs it on the floor
release itself, inside a second local image that
build/definitions/toolchain-floor.pin.json pins exactly:
| Input | Pinned value | Role |
|---|---|---|
| base image | docker.io/library/archlinux:base-20260920.0.596911@sha256:f3691b4dde62ba4c4b6f0ae2c1fbf28e8c0c8c4b9a35c7e06dc1f70e21aa29f6; linux/amd64 sha256:917e543c9d0f1f495d70907bdf05bf53607e791b351e1b01ccd3aec2442303ed |
pulled by digest only; dated like the snapshot, so the install never downgrades |
| Arch Linux Archive snapshot | 2026/09/20 |
its core repository carries systemd 261.3-1; the only mirror pacman reads |
systemd |
261.3-1 |
systemd-repart and systemd-sysupdate at SYSTEMD_FLOOR, the reference profile's release |
python |
3.14.7-1 |
runs the gate script |
dosfstools |
4.2-5 |
Format=vfat in build/repart.d/00-esp.conf |
mtools |
1:4.0.49-1 |
mcopy, which systemd-repart runs to copy CopyFiles= into the vfat ESP of build/repart.d/00-esp.conf |
erofs-utils |
1.9.4-1 |
Format=erofs in build/repart.d/10-root-a.conf |
btrfs-progs |
7.1-1 |
Format=btrfs in build/mkosi.extra/usr/lib/repart.d/20-var.conf |
cryptsetup |
2.8.8-1 |
Encrypt=tpm2 in build/mkosi.extra/usr/lib/repart.d/20-var.conf |
make definitions-fetch-floor builds it the way make definitions-fetch builds
the main image, with the same retries and the same exact-version check. A run
that sets AEGIS_DEFINITIONS_CONTAINER=floor runs a gate inside it under the
same restrictions; CI does so for make verify-systemd with systemd in
AEGIS_REQUIRED_GATES, so a floor run that cannot execute fails the required
check. The image holds no mkosi; the mkosi gate keeps the main image.
FloorPinTests and FloorAdmissionPageTests in
tools/test_definitions_container.py read this table and the floor back.
The kernel build toolchain, and the source it builds (M26, retired by D112)¶
Retired on 2026-10-17 by D112: tools/verify_kernel_build.py and
tools/test_kernel_build.py were removed, so no gate runs these tools and no
test reads this table back. The table and the text below record the admission
M26 held; the kernel the gates boot is now the Nucleus release in the M10
section.
Every row below is a tool tools/verify_kernel_build.py runs. Its floor is the
floor the pinned source itself declares -- scripts/min-tool-version.sh and
Documentation/process/changes.rst of linux-7.2.5 -- not a number chosen
here, and its reference value was read back from the tool on the reference
profile on 2026-09-13. The gate reads each one again before it builds anything
and refuses to run below a floor, so the table cannot drift away from what
actually compiled.
tools/test_kernel_build.py reads this table back and requires it to state the
same admission as the gate's own TOOLCHAIN list. The tool names are compared
as sets, so neither side can carry a row the other does not, and each row's
reference value and its Floor cell must be the ones the gate actually enforces.
A row added here for a tool the gate never runs, or a floor edited on this page
alone, fails make verify-all.
| Tool | Reference-profile version | Floor declared by the pinned source | Role |
|---|---|---|---|
| gcc | 16.2.1 | 8.1.0 (scripts/min-tool-version.sh gcc) |
the compiler |
| ld (binutils) | 2.47 | 2.30 (scripts/min-tool-version.sh binutils) |
link |
| make | 4.4.1 | 4.0 | the build driver |
| bc | 1.08.2 | 1.06.95 | timeconst generation |
| flex | 2.6.4 | 2.5.35 | kconfig lexer |
| bison | 3.8.2 | 2.0 | kconfig parser |
| pahole | 1.31 | 1.26 | DWARF to BTF, for CONFIG_DEBUG_INFO_BTF |
| tar | 1.35 | 1.28 | source extraction |
| perl | 5.42.2 | none declared | kbuild scripts |
| cpio | 2.15 | none declared | the read-back initramfs |
| xz | 5.8.3 | none declared | tarball decompression, and signature verification |
| gzip | 1.14 | none declared | the guest reads /proc/config.gz with it |
| bash | 5.3.15 | 4.2 | merge_config.sh, and the guest's /init |
| mount (util-linux) | 2.42.3 | 2.10 | the guest mounts its own /proc |
| gpg | 2.4.9 | none declared | the pinned tarball's signature |
| qemu-system-x86_64 | 11.1.1 | none declared | the read-back guest |
clang 22.1.8 is installed on the reference profile and is not admitted by
this row: the kernel gate builds with gcc, and LLVM=1 remains unadmitted for
it. M19 admits the same clang for a different job -- -target bpf for the
objects under bpf/, and the native target for their loader -- so a later
LLVM=1 kernel build is still a visible admission rather than an inherited one.
The eBPF toolchain, and the two libbpf versions that differ (M19)¶
Every row in the M19 block above is a tool tools/verify_bpf_objects.py runs,
and every one is read back from the tool before anything is compiled. The
admissions are floors plus recorded reference values, the shape M03 set for
systemd and M18 for mkosi, for the same reason: these are distribution packages
and nothing in this repository can materialise them.
The libbpf row is the one worth reading twice, because the M01 register recorded
libbpf v1.8 and that value is a reading of a different artefact:
pkg-config --modversion libbpfprints 1.7.0 on the reference profile, and/usr/include/bpf/libbpf_version.hdeclaresLIBBPF_MAJOR_VERSION 1,LIBBPF_MINOR_VERSION 7. That is the shared librarybpf/loader/aegis_bpf_probe.clinks against, and the probe prints it again at runtime fromlibbpf_version_string(), which reportsv1.7. This is the version that matters: it is the code that fills the verifier-log buffer and creates the struct_ops link.bpftool versionprintsusing libbpf v1.8. That is the libbpf bpftool was built against, statically, insidecore/bpf 7.2.5-1. It says nothing about the shared library on the system, and on this host the two genuinely differ.
The register's row is therefore corrected rather than confirmed: the admitted
libbpf is 1.7.0, and the 1.8 reading is recorded beside it as what it actually
measures. tools/test_bpf_objects.py asserts that both values and both commands
appear on this page, so the two cannot be collapsed back into one number.
What the M19 rows do not claim: that the objects run correctly, that any
scheduling, power or policy figure was measured, or that a kernel this
repository controls accepted them. They were verified by the workstation's own
running kernel, which is a non-qualifying local fixture -- see
docs/build/bpf.md.
The latency fixture's toolchain, and the kernel it measures (M23)¶
Every row below is a tool tools/verify_latency_fixture.py runs, read back from
the tool before anything is measured, on the reference profile on 2026-09-13.
tools/test_latency_fixture.py reads this table back and requires it to state
the same admission as the gate's own TOOLCHAIN list: the tool names are
compared as sets, and each row's reference value and its Floor cell are
compared against the gate's entry, so a row added here for a tool the gate never
runs, or a floor edited on this page alone, fails make verify-all.
| Tool | Reference-profile version | Floor | Role |
|---|---|---|---|
| qemu-system-x86_64 | 11.1.2 | none declared | the guest that boots the kernel under test |
| cyclictest | 2.10 | 2.10 | the measurement itself |
| cpio | 2.15 | none declared | the guest initramfs |
| ldd | 2.44 | none declared | the guest programs' shared-library closure |
| bash | 5.3.15 | 4.2 | the guest's /init, and the host's interpreter for the shared probe |
| mount | 2.42.3 | 2.10 | the guest mounts its own /proc, /dev and /sys |
| coreutils | 9.11 | none declared | cat, sleep and uname in the guest |
| grep | 3.12 | none declared | the probe's selector, and the nonce on /proc/cmdline |
| gzip | 1.14 | none declared | the probe decompresses /proc/config.gz |
| pacman | 7.1.0 | none declared | the D57 evidence, read-only package-ownership queries |
Two rows are worth reading twice.
cyclictest's floor is its own version, and the reason is the output the gate
parses. The gate does not read the terminal summary; it reads --json, and it
refuses a payload whose resolution_in_ns is not 1, which is what --nsecs
sets. That output shape was observed on 2.10 and on nothing else, so a gate
running below the floor would be parsing unobserved output. This is the same
shape of admission M03 set for systemd: a floor plus a recorded reference value,
because a distribution package cannot be materialised from a file in this
repository. The exact installed package is rt-tests 2.10-1.1, read back with
pacman -Qi rt-tests, and cyclictest --help prints cyclictest V 2.10 --
--version is not an option it accepts, which is why the gate reads the banner
from --help.
The realtime kernel row is the Nucleus release, and it replaces two paths.
D57 recommended a distribution linux-rt package booted as a guest kernel. D70
then put kernel construction in this repository while Nucleus was a scaffold,
and M23 first booted the linux-7.2.5 kernel M26 built. D112 (2026-10-17)
retired that build: the guest now boots vmlinuz-7.2.8-lusoris2-realtime from
the Nucleus release the M10 gate pins, and the gate hashes it against
build/kernel/nucleus-artifact.pin.json before every boot. No linux-rt
package is downloaded, installed or booted, and pacman -Qq linux-rt reports it
is not installed, which the gate records. D57's actual constraint -- that the
reference host is not modified -- is therefore satisfied by construction:
the kernel is a file under AEGIS_NUCLEUS_KERNEL_DIR that no package owns, no
/lib/modules entry exists for, and nothing in this repository installs.
What these rows do not claim: that a latency figure measured here qualifies
hardware, that it bounds a worst case over anything but the run that produced
it, or that the guest measurement isolates what PREEMPT_RT buys. The guest's
virtual CPU is scheduled by a host that is not realtime, so the guest figure is
a composite; docs/build/latency.md records that and the rest of the
methodology.
How M26's pinned source was verified (retired by D112)¶
Two independent checks, both re-run by the gate on every invocation, and neither of them a claim that the digest in this page is trustworthy because it is written here:
- Signature over the source.
linux-7.2.5.tar.signis a detached signature over the uncompressed tar, so verification streamsxz --decompress --stdoutintogpg --verify. It reportsGood signature from "Greg Kroah-Hartman <gregkh@linuxfoundation.org>", primary key fingerprint647F 2865 4894 E3BD 4571 99BE 38DB BDC8 6092 693E. The gate refuses the source if that fingerprint is not the one that signed it, so a good signature by some other key is still a refusal. - Digest against the published, signed checksum list.
sha256sums.ascforv7.xis signed byB886 8C80 BA62 A1FF FAF5 FDA9 632D 3A06 589D A6B1,Kernel.org checksum autosigner <autosigner@kernel.org>, and lists55ddf0df8325d9dad96fcff7bd93977d22e3f50af06527572af59b77c7632b78forlinux-7.2.5.tar.xz. That is the valuebuild/kernel/source.pin.jsoncarries and the valuesha256sumprints for the downloaded file.
Both keys are fetched once into a keyring under the build directory, never into the developer's own keyring. Neither key is certified by a local trust path, so gpg prints its usual "not certified with a trusted signature" warning; what the pin asserts is the fingerprint, not a web of trust.
The configuration is a fragment applied to a named base, never a copied
.config. The base is x86_64_defconfig of the pinned source. The two
fragments are applied in order by the kernel's own
scripts/kconfig/merge_config.sh, followed by make olddefconfig:
build/kernel/10-base-support.config-- Kconfig prerequisites and guest-boot options only. It states no product requirement, and a crate test fails if it ever assigns a symbol the payload demands.build/kernel/50-aegis-requirement.config-- byte-identical to whatKernelRequirement::config_fragmentrenders frombuild/kernel-requirement.json. It is generated, not written.
The boot harness's toolchain, and the artifact it boots (M24)¶
Every row below is a tool or firmware image tools/verify_boot_harness.py
runs, read back before anything boots, on the reference profile on
2026-09-28. tools/test_boot_harness.py reads this table back and requires it
to state the same admission as the gate's own TOOLCHAIN and FIRMWARE lists:
the names are compared as sets, and each row's reference value and its
Floor cell are compared against the gate's entry, so a row added here for a
tool the gate never runs, or a value edited on this page alone, fails
make verify-all. The same test holds the set of programs the gate may start
at all, and requires every admitted tool to be one the gate actually runs.
The three OVMF images print no version, so they are admitted by file digest.
virt-fw-vars prints none either; the gate runs it once and reads the version
from the virt-firmware Python distribution metadata. The last-but-one column
is the D69 comparison: the newest upstream release, read on 2026-09-28 from
each project's own release listing.
| Tool | Reference-profile version | Floor | Latest upstream, read 2026-09-28 | Role |
|---|---|---|---|---|
| qemu-system-x86_64 | 11.1.2 | none declared | 11.1.2, download.qemu.org, read 2026-10-19 |
every guest, accel=kvm with no fallback |
| qemu-img | 11.1.2 | none declared | 11.1.2, read 2026-10-19 | each boot's throwaway overlay, and the read-only ESP copy |
| swtpm | 0.10.2 | none declared | 0.10.2, v0.10.2 of 2026-08-19 |
the guest's TPM 2.0, one instance per boot |
| swtpm_setup | 0.10.2 | none declared | 0.10.2, same release | manufactures each boot's TPM state: EK, sha256 bank only |
virt-firmware (virt-fw-vars) |
26.9 | none declared | 26.9, PyPI | every guest variable store, from the shipped template |
| sbsign | 0.9.5 | none declared | 0.9.5, tag v0.9.5 |
signs the artifact's UKI with the run's key |
| sbverify | 0.9.5 | none declared | 0.9.5, same tag | verifies the signed and the unsigned copy against that key |
| xorriso | 1.5.8.pl02 | none declared | 1.5.8.pl02 of 2026-05-22 | writes the NoCloud cidata seed |
| mcopy (mtools) | 4.0.49 | none declared | 4.0.49 | copies the UKI out of the ESP copy |
| openssl | 3.6.4 | none declared | 4.0.2 of 2026-08-25; the distribution ships the 3.6 series | makes the run's guest key pair |
| gpg | 2.4.9 | none declared | 2.5.24 of 2026-09-23; the distribution ships 2.4.9 of the 2.4 branch, which reached upstream end of life on 2026-06-30 | verifies the clearsigned CHECKSUM, with --no-autostart so no gpg-agent outlives the gate |
| curl | 8.22.0 | none declared | 8.22.0 of 2026-09-02 | --fetch only: the artifact, the CHECKSUM and the keys |
| OVMF_CODE.secboot.4m.fd | sha256 cc150d941d4f1d39e596dedc545384a66ccfb3c9ba5cf9bc3a54d8d427d4d88f |
none declared | edk2-stable202608 of 2026-08-21, packaged as edk2-ovmf 202608-1 | the firmware of every Secure Boot guest |
| OVMF_VARS.4m.fd | sha256 5d2ac383371b408398accee7ec27c8c09ea5b74a0de0ceea6513388b15be5d1e |
none declared | same release | the template every guest store is generated from |
| OVMF_CODE.4m.fd | sha256 2febd26c0b4cf95a636a941afa37d64a552723443ed9ac72f763f6840da98cb4 |
none declared | same release | the firmware of the contrast boot, without Secure Boot |
Two rows are behind upstream and stay as recorded: openssl and gpg are the
distribution's packages, and nothing this gate does depends on a feature of the
newer series. gpg is the one that matters most, because it is the signature
verifier: GnuPG's download page lists the 2.4 branch as past its end of life
on 2026-06-30 (read 2026-09-28), with 2.5 and 2.6 current. It stays admitted
because the distribution ships 2.4.9 and nothing newer, and the gate uses it
only to import public keys and to check one clearsigned file against a pinned
fingerprint. Moving the row to a 2.5 or 2.6 release once the distribution ships
one is a D69 refresh. xorriso's version carries its patch level, .pl02, which
the gate reads back as part of the version.
The pin is a reference value rather than a floor for every row,
the shape M23 and M26 used: no source this gate relies on declares a minimum,
so a different installed version prints beside the recorded one instead of
being refused.
The artifact is pinned by a file, not by a tool.
build/boot/artifact.pin.json names Fedora-Cloud-Base-UEFI-UKI 44-1.7 at its
compose URL under /releases/44/, sha256
2b0af3e6bf4add3695e52df5db3b2eb48d081ab38963ae48c35fca45d5c31b64, 630784000
bytes, producer-version floor 44-1.7, and the signing key of the clearsigned
Fedora-Cloud-44-1.7-x86_64-CHECKSUM: fingerprint
36F612DCF27F7D1A48A835E4DBFCF71C6D9F90A6, Fedora (44)
<fedora-44-primary@fedoraproject.org>, the value
https://fedoraproject.org/security/ lists for Fedora 44. The gate verifies the
signature by that fingerprint in gpg's VALIDSIG status line, not by a web of
trust, and hashes the cached bytes against the pin immediately before every
boot. The bytes live under AEGIS_BOOT_HARNESS_DIR, never in the repository;
*.qcow2 is ignored by .gitignore.
What these rows do not claim: that the artifact is an Aegis image, that a
boot here qualifies hardware, or that the guest's Secure Boot is the host's.
The programs inside the guest -- cat, od, systemctl and cloud-init itself
-- belong to the pinned artifact and are covered by its digest, not by a row
here. docs/build/boot-harness.md records the run.
The accessibility gate's toolchain (M04)¶
Every row below is a tool, package or image tools/verify_a11y.py runs, read
back before the suite runs, on the reference profile on 2026-09-28.
tools/test_a11y.py reads this table back and requires each version to be the
one the pin, package.json and the lockfile state, so a value edited on this
page alone fails make verify-all. The pins live in
ui/concordia-tokens/toolchain.pin.json (the image and Node),
ui/concordia-tokens/package.json (packageManager, exact engines and
devDependencies) and ui/concordia-tokens/pnpm-lock.yaml (every package's
integrity, and the pnpm binary's). The last-but-one column is the D69
comparison: the newest upstream release, read on 2026-09-28 from the npm
registry's latest tag, nodejs.org/dist/index.json or the project's release
listing.
| Tool | Pinned version | How it is pinned | Latest upstream, read 2026-09-28 | Role |
|---|---|---|---|---|
| Node.js | 26.12.0; tarball sha256 fd47865ecd6391ebb431fc815e01b9135bf83ded5cf373247e9331e196b7aded |
toolchain.pin.json and engines.node, exact, with engineStrict; the sha256 is the one in SHASUMS256.txt, signed by C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C |
26.12.0 of 2026-10-14, read 2026-10-16, the Current line, which enters Active LTS on 2026-10-28; the newest LTS is 24.22.0 of 2026-10-14 | runs vite and Playwright inside the container |
| pnpm | 12.14.0; @pnpm/exe.linux-x64 integrity sha512-F6K8e/jWxiuEYJaQtRRUG9ynBSTEHa+t7Lf86MKuOO5UA7WVVMbi+oB8nY6iKW++ncWS2yG6T9faXZGxqNsfoQ== |
packageManager and engines.pnpm; the integrity is pnpm-lock.yaml's |
12.14.0 of 2026-10-15 (latest and next-12), read 2026-10-16 |
installs from the lockfile, offline |
@playwright/test |
1.64.1 | package.json, exact; pnpm-lock.yaml |
1.64.1 of 2026-10-14, read 2026-10-16 | the test runner; the image tag must carry the same version |
chromium-headless-shell |
revision 1248, Chromium 156.0.8078.4 | toolchain.pin.json, read back from playwright-core/browsers.json and from the launched browser |
the revision @playwright/test 1.64.1 bundles, unchanged from 1.64.0 |
the browser the suite drives, baked into the image |
axe-core |
4.14.0 | package.json, exact; pnpm-lock.yaml |
4.14.0 of 2026-10-05, the version @axe-core/playwright 4.14.0 depends on (~4.14.0), read 2026-10-16 |
the engine the suite executes; a11y/suite fails when the executed version differs from this pin (run r20261014T010826-02cb) |
@axe-core/playwright |
4.14.0 | package.json, exact; pnpm-lock.yaml |
4.14.0 of 2026-10-15, read 2026-10-16 | injects axe-core into the page |
svelte |
5.57.2 | package.json, exact; pnpm-lock.yaml |
5.57.2 of 2026-10-06 | the one component |
vite |
8.3.4 | package.json, exact; pnpm-lock.yaml |
8.3.4 of 2026-10-08 | the static build and vite preview |
@sveltejs/vite-plugin-svelte |
7.3.1 | package.json, exact; pnpm-lock.yaml |
7.3.1 of 2026-09-23 | compiles the component in the build |
| Playwright image | mcr.microsoft.com/playwright:v1.64.1-noble@sha256:7852dc5a7d72f5fe458a597d690f6c42fbc8e9e26ddfa95f8e6ef552558d9bbf; linux/amd64 sha256:bdfda2a8fdf48707c5e50a49bd3e06d8d0c759153dc8ee057d8a81c3450bb3e9 |
toolchain.pin.json; pulled and run by digest only |
v1.64.1-noble, built 2026-10-14, 941 MiB compressed |
Ubuntu 24.04 with the browsers and their libraries; its own Node 24.20.0 is not used |
podman |
6.1.2 on the reference profile (podman 6.1.2-1.1), rootless |
the preferred engine when on PATH; AEGIS_A11Y_ENGINE overrides |
6.1.2 of 2026-09-16 | runs each step; the CI runner's is 4.9.3 |
docker |
29.8.1 on the reference profile (docker 1:29.8.1-1.1) |
the fallback engine, run with --user |
29.8.1 of 2026-09-15 | runs each step where podman is absent |
curl |
8.22.0 on the reference profile | recorded, not pinned; started only by --fetch (make a11y-fetch), with --proto =https and a deadline |
8.22.0 of 2026-09-02 | --fetch only: downloads the Node tarball and the pnpm binary, each kept only when it hashes to its pin |
Every row is at the newest release except the Node line's LTS status, which D65
accepts: 26.x is the latest line and becomes LTS on 2026-10-28, and D42 is
settled by D65. The engines and curl are recorded, not pinned: the gate prints
which engine ran, and a pass on either is the same claim because the image, the
Node and the lockfile are the same bytes; curl runs only in make a11y-fetch,
and a download that does not hash to its pin is discarded, so curl's version
changes no byte the gate runs. tools/test_a11y.py requires a row here for
every program the gate may start on the host. The reference profile's own Node
(v26.10.0) and pnpm (10.29.3) are not what the gate runs; the M01 drift
register's "Node 20 vs 22" row is closed with the exact Node pin above
(26.10.0 when closed, 26.11.1 from 2026-10-13, 26.12.0 since 2026-10-16), and
pnpm 12.14.0 (12.6.0 until 2026-10-14, 12.11.2 until 2026-10-16) replaces
the reference profile's 10.29.3 for this gate.
What these rows do not claim: that the host's Playwright browser cache is
pinned. ~/.cache/ms-playwright held chromium-1228 on 2026-09-13 and
chromium-1243 on 2026-09-28, written by Praetor's figure engine; the gate never
reads it. docs/build/accessibility-harness.md records the run.
The contract pair's toolchain and producer pins (M09)¶
Every row below is a program tools/verify_contract_pair.py starts, or a
producer commit it runs against, read back on the reference profile on
2026-09-28, and the nucleus and python3 rows again on 2026-09-29, when D106
moved the nucleus pin and when it was re-pinned to 82aa6b7. Both producer
rows were read again that evening, when D107 moved imago to 987b95a and
nucleus to 852be74. The nucleus row was read again on 2026-10-17, when
nucleus pull request 176 gave the verifier its single-kernel mode and the pin
moved to 677dd40.
tools/test_contract_pair.py reads this table back and
requires the Go floor, both commits and nucleus's verifier to be the ones
build/contract/producers.pin.json records, and a row for every program the
gate may start. The last-but-one column is the D69 comparison, read from
go.dev/dl, the tags of github.com/git/git and the python.org release API,
and for the producers from git ls-remote --heads.
| Tool or producer | Pinned version or commit | How it is pinned | Latest upstream, read 2026-09-28 | Role |
|---|---|---|---|---|
go |
floor 1.27.2, from imago's go.mod (go 1.27.2); reference profile go1.27.2 (go 2:1.27.2-1); CI 1.27.2 |
imago.go in the pin, checked against the cached go.mod; every go command runs with GOTOOLCHAIN=local, so a Go below the floor is refused by the fetch rather than replaced by a download. CI's Go is the M00 row above: setup-go resolves Praetor's go 1.27 to the newest 1.27 patch, 1.27.2, which meets the floor |
1.27.2 (stable), go.dev/dl |
make contract-fetch: go mod download, go mod verify and the -trimpath -buildvcs=true build; the gate: go version -m and the offline stand-in build, with GOPROXY=off |
git |
reference profile 2.55.0 (git 2.55.0-1.1) |
recorded, not pinned; no source this gate relies on declares a minimum beyond the 2.32 that GIT_CONFIG_GLOBAL needs |
2.56.0, tag v2.56.0; the distribution ships 2.55.0 |
make contract-fetch: ls-remote --heads, the depth-1 fetch and checkout; the gate: rev-parse, status --untracked-files=all --ignored, ls-files -v and log of the imago checkout, rev-parse and status of this repository, and the stand-in's commit. Every git command, and go's own git calls, run with GIT_CONFIG_NOSYSTEM=1, an empty GIT_CONFIG_GLOBAL and no inherited GIT_* variable |
cordanaLLM/imago |
commit 9394202595effca3b34a0dfd0299adb7bdac406a (was 987b95a432e5c9aac1b4885b97fa2d3ff1b9d311 until E11-7, 16f964b4dafadac2b1f0a662c7dcbb4b7bb29bee until D107) |
imago.commit in the pin; fetched by commit into a fresh directory, checked by git rev-parse HEAD, by the binary's vcs.revision, vcs.time and module version, and by the binary sha256 the fetch recorded |
main at 9394202595effca3b34a0dfd0299adb7bdac406a, read 2026-10-18 |
consumes both M18 payloads (pkg/aegis, pkg/kernel) and validates product-result (E11-7) |
cordanaLLM/nucleus |
commit 677dd401b68363b9ac3a1f2e891e6c1a1e9a0d9a (was 852be742eb173700d5ef93b0c6f867b855f9c640 from D107 until 2026-10-17, 82aa6b7a3c68a42a6330370c81ec642482014c9f from the re-pin of 2026-09-29 until D107, 0a4eac93f29fef432bfa9d892ad236568ce2f482 from D106 until that re-pin, and 8672247ff1bd22ed6b6b89d498116f20ff00c2ab until D106) |
nucleus.commit in the pin; fetched by commit into a fresh directory and checked by git rev-parse HEAD, a clean status and index, the presence of scripts/verify_kernel_requirement.py and the versions.json row that binds aegis-os to this repository's payload on realtime |
main at 852be742eb173700d5ef93b0c6f867b855f9c640, read 2026-09-29 |
verifies build/kernel-requirement.json against the kconfig fragments of its bound stream at evidence level declared (nucleus#35, D106); its --resolved-config level (nucleus#36) needs a networked kernel-source resolve and is not run |
python3 |
reference profile 3.14.7 (python3 --version); CI runs the Python of the ubuntu-26.04 image (3.14.4) |
recorded, not pinned: the gate starts nucleus's verifier with the interpreter running the gate (sys.executable, which make starts as python3), -I, which ignores every PYTHON* variable and the user site, and -B, which keeps the sibling import from writing scripts/__pycache__ into the checkout; the script and the sibling module it imports, scripts/versions_query.py, are standard-library only, and nucleus lints them for Python 3.11 (target-version = "py311") and runs the script on CPython 3.12 in its CI |
3.14.7 of 2026-08-05, python.org |
the gate: scripts/verify_kernel_requirement.py --report-json, six runs per gate run, from the nucleus checkout |
A producer's main moving past its pin is recorded by the fetch, not followed:
the gate runs the pinned commit until the pin is edited, and a pin edit leaves a
cache fetched for another pin, which the gate reports as a FAIL that names
make contract-fetch (D93: only an absent cache skips). The imago binary is
built from source to run the contract and is not a release artifact;
docs/build/contract-pair.md records the runs.
The display slice's build toolchain (M27, D80)¶
crates/aegis-scaena builds a C binding: cros-libva's build script finds libva
through pkg-config, and bindgen, its build dependency, loads libclang to
generate the bindings from the libva headers. None of those is a Cargo input,
so tools/display_toolchain.py reads every row below back before
make verify-rust builds anything, prints each value beside its floor, and
fails the crate gate on a missing tool or a value below its floor.
tools/test_display_toolchain.py reads this table back and requires it to
state the same admission as the tool's TOOLCHAIN and LOCKED lists: names
compared as sets, and each row's reference and floor compared. Each reference
value was read on the reference profile on 2026-09-29.
| Tool or crate | Reference-profile version | Floor | Role |
|---|---|---|---|
| pkgconf | 3.0.7 (pkgconf 3.0.7-1.1) |
1.8.1 | locates libva for cros-libva's build script; the floor is the Verification gate runner's pkg-config 1.8.1-2build1, the oldest any gate builds with |
| libva | 2.24.1 (libva 2.24.1-1.1), read as pkg-config --variable=libva_version libva |
2.24.1 | the VA-API loader and the headers the bindings are generated from; the floor is the version CI builds (below), never lowered |
| VA-API | 1.24.0, read as pkg-config --modversion libva |
1.24.0 | the API version those headers declare |
| clang | 22.1.8 (clang 22.1.8-2; libclang 22.1.8) |
6.0 | libclang, which bindgen loads; bindgen 0.70.1 builds clang-sys with its clang_6_0 feature, and its book at that tag asks for Clang 5.0 or later, so 6.0 is the stricter floor. The row reads the clang on PATH; clang-sys loads the newest libclang it finds, which on both hosts belongs to that same LLVM |
| bindgen | 0.70.1, read from Cargo.lock |
0.70.1 | cros-libva's build dependency at the pinned revision (bindgen = "0.70.1"), locked exactly |
| cros-libva | 0.0.13 from git revision 59384456ac2ae78c0c3e5515f41ef1efd9b802cf, read from Cargo.lock |
0.0.13 | the binding itself; the lock's source must name the pinned revision |
vainfo and wayland-info established the three display capabilities in
planning/hardware-profile.json, but they are probes, not gate tools. The iHD
driver, intel-media-driver 26.2.4-1.1 on the reference profile, is a host
driver that is recorded, not pinned: the display gate reads it back through
the VA vendor string before it decodes (M27 criterion 5;
crates/aegis-scaena/src/decode.rs, require_ihd), and the per-frame
regression pins are recorded with that string. ffmpeg n9.0.2 generated the
committed Motion-JPEG fixture once, drawing the frame-index blocks M27 reads
back; the gate never runs it, so the command is recorded as the fixture's
provenance on docs/build/display.md rather than admitted. The CRC-32 that
checks the MPEG-2 frame and pins the Motion-JPEG frames against regression is
the computation cros-libva's own test uses (crc_nv12_image in
lib/src/lib.rs at the pinned revision, through crc32fast): M27 writes it in
the crate, content::Crc32, ISO-HDLC with its check value tested, and admits
no crate for it.
The display gate's programs¶
make verify-display (tools/verify_display.py) starts only the programs in
its PROGRAMS list, and tools/test_display_slice.py holds that list, refuses
a program outside it before it starts, and requires every process to start
from one call site with a deadline. None of them is admitted here with a
version floor: the build rows above are read back through
tools/display_toolchain.py before the gate builds, and the rest are queries.
| Program | Invocation | Role |
|---|---|---|
| cargo | cargo build --locked -p aegis-scaena --bin aegis-scaena-display |
builds the run binary on the locked graph |
| rustc | rustc --version |
printed with every run |
| pkg-config | --variable=libva_version libva and --modversion libva |
libva and VA-API printed with every run |
| clang | through tools/display_toolchain.py |
the libclang row above |
| loginctl | show-session <id> -p LockedHint --value |
a locked session presents no client surface, so the gate skips |
| pacman | -Qo <compositor executable> |
names the compositor's package; the compositor binary is never executed |
| aegis-scaena-display | run and driver-probe |
the run itself, with LIBVA_DRIVER_NAME in its environment only |
libva on the Verification gate's runner¶
The runner is ubuntu-26.04, whose archive carries libva 2.23.0 (and
ubuntu-24.04 carried 2.20.0), both below the floor. As the maintainer decided on
2026-09-29 (D80), the job builds the pinned release tarball rather than
lowering the floor or changing the runner image, in
.github/workflows/ci.yml before make verify-all, and caches the installed
prefix under ~/.cache/aegis-libva/2.24.1, keyed on every pin below, on
the word werror, so that a build made before warnings became errors is not
restored, and on the runner image the job runs on (ImageOS), so that a prefix
built on one image is not restored on another;
tools/test_display_toolchain.py refuses a literal image in that key.
tools/test_display_toolchain.py holds the workflow's env: values to this
table.
| Input | Pinned value | How it is checked | Role |
|---|---|---|---|
| libva release tarball | https://github.com/intel/libva/releases/download/2.24.1/libva-2.24.1.tar.bz2, sha256 eec6050b52876f229bd35e9df17cd31a06785e18e6f7990c445b584628483d67 |
LIBVA_VERSION and LIBVA_SHA256, sha256sum -c before extraction; the digest is the one the GitHub release publishes for the asset, and on 2026-09-29 the detached libva-2.24.1.tar.bz2.asc verified against key 421E5C3C1148E3DB9372378E8B99990502A81421 (Intel Media Stack Release) |
the headers and the libva and libva-drm libraries the crate builds and runs its tests against |
| meson | 1.12.1, wheel sha256 930bc7542cbd9f57009e182fd014eba48cf1a0180a7b9006d2d32d8f168d8b02 |
MESON_VERSION and MESON_WHEEL_SHA256, pip install --require-hashes --only-binary=:all: --no-deps into a throwaway virtual environment |
configures the libva build; the newest release on PyPI on 2026-09-29 |
| ninja | 1.13.2, wheel sha256 65a24341b5ac09fcadcc37082660be40a94174e51a937fabf6e2cae26225fa2c (manylinux x86_64) |
NINJA_VERSION and NINJA_WHEEL_SHA256, the same install |
runs the libva build; the newest release on PyPI on 2026-09-29 |
| libdrm headers | unpinned: the runner's libdrm-dev from its signed Ubuntu archive |
pkg-config --atleast-version=2.4.75 libdrm, the floor libva's meson.build requires for libva-drm, printed and held before the build |
libva-drm, which cros-libva links; the image ships no libdrm headers |
The build runs meson setup --werror with
--prefix=$HOME/.cache/aegis-libva/2.24.1 --libdir=lib --buildtype=release
-Dwith_x11=no -Dwith_glx=no -Dwith_wayland=no -Dwith_win32=no
-Denable_docs=false, then meson compile and meson install; only the DRM
backend, which cros-libva links, is built. --werror turns a compiler warning
into a failed step (HISS-10); a libva release that warns under the runner's
compiler therefore stops the gate until the pin or the build changes. The step
after it
exports PKG_CONFIG_PATH, so cros-libva's build script finds the prefix, and
LD_LIBRARY_PATH, because Cargo adds a build script's search path to the
loader path only inside the target directory, and it reads the installed
libva_version back and requires it to equal LIBVA_VERSION.
What these rows establish and what they do not. On the reference profile,
cargo build --locked built the crate against libva 2.24.1 with clang 22.1.8
and pkgconf 3.0.7. The workflow's three libva steps were run, extracted from
ci.yml and unmodified, in an ubuntu:24.04 container with the runner's
pkg-config 1.8.1 and clang 18.1.3 on 2026-09-29: libva 2.24.1 built, the
read-back printed VA-API 1.24.0, tools/display_toolchain.py passed and
cargo build --locked -p aegis-scaena succeeded against the built prefix. A
container is not the runner; the first Verification gate run on this change is
the runner's own evidence. That the pinned revision compiles against apt's
libva 2.20.0 was not tried, because the floor is not lowered. No frame is
decoded by any of this; decoding is the display gate's.
Proposed for M16 and M28: the native shell's crates (D101, D102)¶
These rows are proposals, not admissions, in the shape M27's rows had until M27 admitted them. M16 admitted accesskit on 2026-09-29 and M28 admitted gpui, gpui_linux and the accesskit_unix they resolve on 2026-10-17, and their rows moved to Crates the workspace pins; M28 admits the rest, each when its gate reads the row back before it runs; until then no gate may cite them. They are recorded now because decision D101 makes the P05 shell native Rust and D102 names its toolkit, gpui, git-pinned (ADR-0004), and because none of these crates is named anywhere else on this page. Each value was read on 2026-09-29 from the crates.io API, from zed-industries/zed or from the reference profile's package manager.
| Tool or crate | Reference version, read 2026-09-29 | Proposed pin or floor | Role |
|---|---|---|---|
| zbus, atspi | 5.19.0 (MIT) and 0.29.0 (Apache-2.0 OR MIT), the versions accesskit_unix 0.22.1 resolves; the reader in crates/aegis-forum-shell-gpui/src/readback.rs uses atspi 0.29.0 (proxies only) and zbus 5.19.0 (async-io) |
as the pinned accesskit_unix 0.22.1 resolves them, so the lock gains no package; atspi also for the tests that read the tree back (M28) | pure-Rust D-Bus and AT-SPI below accesskit_unix and for readback verification |
| async-io, futures-lite | 2.6.0 and 2.6.1 (both Apache-2.0 OR MIT), resolved by zbus and accesskit_unix | as pinned in Cargo.lock, so the lock gains no package | asynchronous I/O and future combinators for readback with deadlines |
| libxkbcommon | 1.13.2 (libxkbcommon 1.13.2-1.1) |
the floor the pinned xkbcommon crate (0.8.0 at zed main) needs, read at admission (M28) |
the C keymap library gpui links for Linux keyboard input |
| libwayland-client | 1.26.0 (wayland 1.26.0-1.1) |
read at admission (M28) | loaded by wayland-backend through dlopen |
| at-spi2-core | 2.60.7 (at-spi2-core 2.60.7-1.1), with dbus-run-session from dbus 1.16.2-1.1 |
recorded and read back before the AT-SPI cases run (M28) | the bus launcher and registry of the private AT-SPI session M28's tests start |
What these rows do not claim: that any zed commit is chosen, that gpui builds on the Verification gate's runner, that the accesskit gpui resolves and the 0.25.1 M16 exports can share one tree without a conversion, or that any frame was painted. The zed repository holds crates other than gpui; the build graph takes only what the pin resolves, and M28 records the licence of every package it resolves. xdg-desktop-portal and the guest session M29 runs are M29's admission, not this page's yet.
The D100 lint's packages, eslint, eslint-plugin-svelte and svelte-eslint-parser, are M16's admission as well; M16 admitted them on 2026-09-29, and they are recorded in the next section.
The ui/ HISS lint's toolchain (M16, D100)¶
praetorctl audit scans Go, Python and Rust for the HISS invariants and no
JavaScript, TypeScript or Svelte (cordanaLLM/praetor#589, filed 2026-09-29: a
planted recursion, an eval and a 73-line function all pass it). Until a
scanner ships there, ESLint enforces HISS-01, HISS-04 and HISS-08 on the
JavaScript and Svelte under ui/, which is ui/concordia-tokens today,
offline, inside the accessibility gate's pinned container:
ui/concordia-tokens/eslint.config.js sets max-lines-per-function 60,
complexity 10, max-statements 50, no-eval, no-implied-eval,
no-new-func and the local rule
ui/concordia-tokens/hiss-lint/no-self-recursion.js, switches inline
configuration off, and the gate runs it with --max-warnings 0. The local
rule reports a function that calls itself by name, directly or from a closure
inside it, and this.name() inside the method name. It does not detect
mutual recursion, a cycle through two or more functions, because there is no
call-graph check.
The three packages are devDependencies of ui/concordia-tokens/package.json,
exact, beside M04's six, and are locked in ui/concordia-tokens/pnpm-lock.yaml,
which M04's pnpm 12.6.0 regenerated with --lockfile-only: every package
M04 had locked kept its version and integrity, and the lint's closure was
added. D99, the one pnpm workspace under ui/, was withdrawn by D101, so the
lint has no workspace root of its own. tools/test_a11y.py reads this table
back against the manifest, and the gate reads each version back from inside
the container before it lints. The last-but-one column is the D69
comparison, the npm registry's latest on 2026-10-18. The three were first
admitted on 2026-09-29 as eslint 10.11.0, eslint-plugin-svelte 3.23.0 and
svelte-eslint-parser 1.8.1, and moved together to 10.12.0, 3.23.1 and 1.9.0
on 2026-10-13; eslint alone moved to 10.13.0 on 2026-10-18.
| Tool | Pinned version | How it is pinned | Latest upstream, read 2026-10-18 | Role |
|---|---|---|---|---|
eslint |
10.13.0 (MIT) | package.json, exact; pnpm-lock.yaml |
10.13.0 of 2026-10-16 (latest); maintenance is 9.39.5 |
runs the rules below over every .js, .mjs, .cjs and .svelte file of the package |
eslint-plugin-svelte |
3.23.1 (MIT) | package.json, exact; pnpm-lock.yaml |
3.23.1 of 2026-10-09 | its base configuration hands .svelte files to the parser and turns on only its two bookkeeping rules, svelte/comment-directive and svelte/system |
svelte-eslint-parser |
1.9.0 (MIT) | package.json, exact; pnpm-lock.yaml |
1.9.0 of 2026-10-09 | parses a Svelte component's script for the rules; its manifest declares engines.pnpm 10.34.6, which pnpm 12.6.0 does not enforce for a dependency, so engineStrict does not refuse it |
The parser loads the svelte compiler M04 already admitted, 5.57.2, so no
second Svelte enters the lockfile. Each rule family has a planted violation
under ui/concordia-tokens/hiss-lint/plants/ that the gate lints on its own
and requires to produce exactly its findings, and at-the-limits.js sits
exactly on the 60-line, complexity-10 and 50-statement limits and must lint
clean, while function-length.js holds a 61-line function that must not. The
first run over M04's suite found ui/concordia-tokens/tests/probe.js wrapped
in a 170-line immediately invoked function; it is now a strict-mode block,
with no change to what it measures.
The Nucleus kernel gate's toolchain, and the kernel it boots (M10)¶
Every row below is a tool tools/verify_nucleus_kernel.py runs, read back
from the tool before anything boots, on the reference profile on 2026-09-29.
tools/test_nucleus_kernel.py reads this table back and requires it to state
the same admission as the gate's own TOOLCHAIN list: the names are compared
as a set, and each row's reference value and Floor cell against the gate's
entry, so a row added here for a tool the gate never runs, or a value edited on
this page alone, fails make verify-all. The same test holds the set of
programs the gate may start at all.
Eight rows are M23's admissions reused unchanged, because M10 boots its guest
through M23's boot() and builds its initramfs through M23's helpers (the
criterion that no second harness is built): the gate reads them from
tools/verify_latency_fixture.py's own list, and their reference values are
the ones M23 recorded on 2026-09-13. A newer installed version prints beside
the recorded one instead of being refused. The four eBPF rows reuse M19's
floors from tools/verify_bpf_objects.py. QEMU is the version M24 admitted as
well, so criterion 3's pinned emulator is shared rather than admitted twice.
| Tool | Reference-profile version | Floor | Latest upstream, read 2026-09-29 | Role |
|---|---|---|---|---|
| qemu-system-x86_64 | 11.1.2 | none declared | 11.1.2, as M24 records | both guests, -enable-kvm; the gate skips without a read-write /dev/kvm |
| cpio | 2.15 | none declared | as M23 records | the two initramfs archives, through M23's archive_tree |
| ldd | 2.44 | none declared | as M23 records | the guest userspace's library closure |
| bash | 5.3.15 | 4.2 | as M23 records | the guest's PID 1 and the host half of the probe |
| mount | 2.42.3 | 2.10 | as M23 records | proc, sysfs, securityfs, tracefs and cgroup2 in the guest |
| coreutils | 9.11 | none declared | as M23 records | cat, sha256sum, stat, mkdir, base64, sleep and the marker binary in the guest |
| grep | 3.12 | none declared | as M23 records | the probe and the attach poll in the guest |
| gzip | 1.14 | none declared | as M23 records | /proc/config.gz and the retained verifier logs in the guest |
| setpriv | 2.42.4 | none declared | 2.42.4, tag v2.42.4 |
every guest load, as uid 65534 with CAP_BPF and CAP_PERFMON only |
| cosign | 2.6.3 | 2.6.3 | 3.1.3 of 2026-08-06; the 2.6 series is at 2.6.5 of the same day | verifies SHA256SUMS against the pinned keyless identity, tag commit and tag ref, --offline in the gate; admitted below 3, so the reference profile's second copy, 3.1.3, is refused |
| clang | 22.1.8 | 19.0.0 | as M19 records | the objects and the loader, against the Nucleus kernel's own BTF |
| bpftool | 7.8.0 | 7.4.0 | as M19 records | btf dump of the kernel image's own BTF into vmlinux.h |
| llvm-strip | 22.1.8 | 19.0.0 | as M19 records | drops DWARF from each object and keeps BTF |
| libbpf | 1.7.0 | 1.5 | as M19 records | the loader links it; the guest runs this host's copy |
curl 8.22.0, M24's admission, runs only in make nucleus-kernel-fetch, and
cosign runs there once without --offline, so its trust root may refresh. The
gate itself never touches the network. cosign is behind upstream on two counts:
the installed binary is 2.6.3 from go install, the 2.6 series has reached
2.6.5, and upstream's current line is 3.x. Nothing here depends on a feature of
either newer release; moving the row is a D69 refresh.
The cosign row is the only one with a ceiling. The reference profile carries
two copies, and a bare cosign names 2.6.3 only because ~/go/bin precedes
/usr/bin in the developer account's PATH
(planning/hardware-profile.json). The other copy, the distribution's 3.1.3,
prints Flag --offline has been deprecated for the flag the gate passes. The
gate and the fetch therefore read the version back and refuse anything below
2.6.3 or at 3 and above, with a printed reason, rather than trust the order of
PATH. tools/test_nucleus_kernel.py holds the ceiling to this row.
The kernel is pinned by a file, not by a tool.
build/kernel/nucleus-artifact.pin.json names cordanaLLM/nucleus release
v7.2.8-realtime-lusoris2, tag commit
852be742eb173700d5ef93b0c6f867b855f9c640, the
imago.nucleus.kernel-artifact.v1 manifest by sha256
c27a42e85205ef684d90d12fd17c13b048eae4d93d624e5d14785138eb932938, every
asset by sha256 and size, kernel.release 7.2.8-lusoris2-realtime,
kernel.config_digest
sha256:5dec07f61567f046e923fd862f434f056943ced8dedeb963a7f483c761b24ae8, and
the keyless signer
https://github.com/cordanaLLM/nucleus/.github/workflows/publish-release.yml@refs/tags/v7.2.8-realtime-lusoris2
with issuer https://token.actions.githubusercontent.com. Until 2026-10-11
the file named revision 1, v7.2.8-realtime-lusoris1 at tag commit
9e050cf8fc2fb62de943229f22ab104dce455e92, the kernel of the runs of
2026-09-29. The tool rows above keep the values read then; the run of
2026-10-11 printed newer installed versions beside seven of them
(the gate page).
imago is the binary
M09's make contract-fetch built at the commit M09 pins: it was
16f964b4dafadac2b1f0a662c7dcbb4b7bb29bee for the runs of 2026-09-29 and is
987b95a432e5c9aac1b4885b97fa2d3ff1b9d311 since D107, which changed only
imago's vendored copy of the kernel requirement and two of its test files. The
gate checks its sha256 against the fetch's identity record before running it,
and passes imago's own versions.json from that checkout.
The workstation gate's toolchain, and the bytes it boots (M21)¶
make verify-workstation (tools/verify_workstation.py) boots Firecracker
microVMs and reads the RAPL counter; make workstation-fetch is its one
networked step. Every value below was read on the reference profile on
2026-09-29.
Firecracker is pinned by a file. build/sandbox/firecracker.pin.json
names the v1.17.0 GitHub release of 2026-09-10, the newest release on the
GitHub API that day and the version D58 names. Its x86_64 archive,
firecracker-v1.17.0-x86_64.tgz, is 7464385 bytes with sha256
06094a1108ae9e82aa4c23a775aa92758f53f1175d422270d9d6162cb9ade558: the value
the GitHub API reports as the asset's digest and the one the release's own
firecracker-v1.17.0-x86_64.tgz.sha256.txt publishes, which the fetch
re-reads and compares. Inside it, firecracker-v1.17.0-x86_64 hashes to
99ad0f5cd0514a88aad0e9ae8cfdb3cc3b4ab9d190e1194602406c786b5de7a5, the value
the archive's own SHA256SUMS lists; it is a static-pie executable and prints
Firecracker v1.17.0. The licence is the archive's LICENSE, Apache-2.0,
sha256 cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30; its
NOTICE adds that libseccomp, LGPL-2.1, is used in the build to produce the
seccomp filters shipped beside the binary. Only the binary and the licence are
extracted; nothing is vendored into the repository. The jailer is not
used: it needs root to chroot and change user, and the maintainer's decision
of 2026-09-29 admits no privilege beyond one scoped counter read. The
distribution package firecracker 1.17.0-1.1 on the reference profile is the
same version and is not run by any gate.
The guest kernel is pinned by a file. Firecracker supports 6.18 guests
from v1.16.1 until 2028-06-01 and 6.1 guests only to 2026-09-02
(docs/kernel-policy.md at v1.17.0), so the guest is the 6.18 build from the
CI artifact set current when v1.17.0 was published,
firecracker-ci/20260909-a8e1c3830545-0/x86_64/vmlinux-6.18.44, 27846248
bytes, sha256
d8ced68bd61e27b6813e2c993cc53a4029c59e13210672180591c84109684fe4, and its
configuration vmlinux-6.18.44.config, sha256
9fb2be18303d2f6e8ec35b3a20ecf1209f54a4ece10114a893cb37beabee7030. The bucket
publishes no digest, so each is the sha256 computed at admission. The gate
requires CONFIG_BLK_DEV_INITRD=y, CONFIG_KVM_GUEST=y,
CONFIG_SERIAL_8250_CONSOLE=y, CONFIG_VIRTIO_MMIO=y and
CONFIG_VIRTIO_VSOCKETS=y in that configuration. The kernel is GPL-2.0 and is
downloaded, never vendored.
The guest init is built, not fetched. aegis-vesta-guest is built by the
pinned Rust toolchain with --release --target x86_64-unknown-linux-gnu and
RUSTFLAGS=-C target-feature=+crt-static, which links the workstation's glibc
statically: glibc 2.44 (glibc 2.44+r24+g16be1518495f-1 on the reference
profile). That archive is recorded, not pinned, like the iHD driver M27
records: the gate refuses a guest whose ELF program headers name an
interpreter, and the initramfs it packs is a local run artifact that is never
distributed. The initramfs digest is printed with every run; every run of
2026-09-29 packed the same bytes.
The workstation gate's programs¶
tools/test_workstation_slices.py holds the gate's PROGRAMS list, refuses a
program outside it before it starts, and requires every process to start from
one of two call sites, each with a deadline.
| Program | Invocation | Role |
|---|---|---|
| sudo | exactly sudo -n cat /sys/class/powercap/intel-rapl:0/energy_uj, under a 10 s deadline |
the one privileged read; any other argument vector, sudo named bare or by path, is refused before it starts |
| cargo | cargo build --locked -p aegis-tellus-rapl, -p aegis-vesta-sandbox, and the static guest build above |
builds the three binaries on the locked graph |
| rustc | rustc --version |
printed with every run and kept in its host.json |
| firecracker-v1.17.0-x86_64 | --version from the gate; --no-api --config-file from aegis-vesta-sandbox |
the pinned monitor |
| aegis-tellus-rapl | run <readings document> |
the RAPL cases |
| aegis-vesta-sandbox | run <firecracker> <kernel> <initramfs> <run-dir>, in its own session |
the sandbox cases |
| curl | in make workstation-fetch only |
M24's admission (8.22.0); the gate itself never touches the network |
The attestation gate's toolchain (M20)¶
make verify-attestation (tools/verify_attestation.py) drives a private
software TPM instance and tpm2-tools to verify attestation quotes against
canonical audit-record digests from crates/aegis-justitia. Every value below
was read on the reference profile on 2026-10-18.
| Tool | Reference-profile version | Floor | Latest upstream, read 2026-10-18 | Role |
|---|---|---|---|---|
| swtpm | 0.10.2 | none declared | 0.10.2, v0.10.2 of 2026-08-19 |
private TPM 2.0 instance in ephemeral directory |
| tpm2-tools | 5.8 | none declared | 5.8, tag 5.8 of 2026-06-25 |
EK/AK creation, PCR extension, quote and checkquote |
The attestation gate's programs¶
tools/test_verify_attestation.py holds the gate's REQUIRED_PROGRAMS list,
verifies missing capabilities with unit test doubles, and requires every process
to run under a deadline.
| Program | Invocation | Role |
|---|---|---|
| swtpm | socket --tpm2 --tpmstate ... --server ... --ctrl ... --flags not-need-init,startup-clear |
private software TPM 2.0 emulator |
| tpm2_createek | -c ek.ctx -G rsa |
creates Endorsement Key |
| tpm2_createak | -C ek.ctx -c ak.ctx -G ecc -g sha256 -s ecdsa -u ak.pub -f pem -n ak.name |
creates Attestation Key |
| tpm2_pcrextend | <pcr>:sha256=<digest> |
extends PCRs 0, 4, 7, 11 |
| tpm2_quote | -c ak.ctx -l sha256:<pcrs> -q <digest> -m ... -s ... -o ... -g sha256 |
generates quote over selected PCRs and qualifying data |
| tpm2_checkquote | -u ak.pub -m ... -s ... -f ... -g sha256 -q <digest> |
verifies cryptographic quote and PCR digest |
| tpm2_print | -t TPMS_ATTEST <msg> |
extracts pcrSelect for client selection enforcement |
| tpm2_flushcontext | -t or -s |
flushes transient and session contexts to avoid 0x902 memory exhaustion |
| cargo | cargo run --locked --offline -q -p aegis-justitia --example record_digest [other] |
computes canonical audit-record digests |
The live session gate's toolchain (M29)¶
make verify-session (E29-4) admits no tool of its own. It runs four of M24's
rows above -- qemu-system-x86_64, xorriso, gpg and curl -- read back through
tools/verify_boot_harness.py's own TOOLCHAIN list under the same rule: a
floor refuses an older tool, and a version other than the recorded one prints
beside it. The guest image it boots is pinned in build/session/guest.pin.json
and described in docs/build/live-session.md.
QEMU's rows moved from 11.1.1 to 11.1.2 on 2026-10-19 in M23's, M24's and
M10's tables together, since M10 and M29 reuse M23's and M24's rows; 11.1.2 is
the version the reference profile prints and the newest release
download.qemu.org lists on that day.
Not yet admitted¶
These are run by a gate but pinned by nothing, so they are gaps recorded here rather than admissions:
shellcheck, run bymake verify-lints, comes from the runner image in CI and from the workstation distribution locally. No version is pinned and none is asserted; a missingshellcheckfails the target.- The glibc static archive M21's guest init links comes from the workstation's glibc package, recorded above and not pinned.
python3, which runs the preparation validator and its unit tests, comes from the runner image and from the workstation distribution.npxandpipxare the delivery mechanism for five pinned linters; the Node.js and Python runtimes behind them are the runner's. A missing launcher failsmake verify-lints.libdrm-devon the Verification gate's runner, which the pinned libva build compileslibva-drmagainst, comes from the runner's Ubuntu archive at whatever version it carries; only the libdrm floor of 2.4.75 that libva'smeson.buildrequires is held, read back withpkg-configbefore the build.node, whichmake docs-lint(part ofmake verify-all) runs directly, is the runner's or the workstation's;.github/workflows/praetor-docs.ymlasksactions/setup-nodefor major version 24. Praetor supplies both files. The accessibility gate's Node is a different one, admitted above: 26.12.0 by sha256, inside the container.- The praetor pin auto-bump (
tools/praetor_bump.py) runs the linters only throughmake verify-all, so at the versions above, and builds the documentation portal with the workstation's Python. It buildspraetorctlwith the workstation'sgounder its ownGOTOOLCHAINsetting, whereas CI installs the Go version Praetor'sgo.moddeclares and setsGOTOOLCHAIN=local. These versions decide only whether a bump pull request is proposed; its CI re-runs the pinned tools.
Pinning them is a separate decision, not an implicit part of M02. Until it is taken, no milestone may cite them as admitted toolchain.
How to read a row back¶
- The Rust rows are checked by
crates/aegis-justitia/tests/manifest_hygiene.rs, which fails ifrust-toolchain.tomlnames a moving channel such asstable, if the channel is not an exact three-component version, or if therustfmtandclippycomponents are missing. - The workflow rows are the
env:block of.github/workflows/ci.yml; each version appears exactly once and is interpolated into the command that runs. - The crate rows are
[workspace.dependencies]in the rootCargo.tomland the committedCargo.lock. The rows for crates pinned by git revision are read back bytools/verify_crate_pins.pyagainst both files. - The replaced distribution package is recorded in the local package-manager log
as
removed rust (1:1.98.1-1.1)immediately beforeinstalled rustup (1.29.1-1.1)on 2026-09-13. - The systemd row is checked by
tools/test_systemd_definitions.py, which reads the floor and the reference banner back through the same parser the gate uses, and by the gate itself, which refuses to run below the floor. - The mkosi row is checked by
tools/test_mkosi_definitions.pythe same way, and additionally by mkosi itself:MinimumVersion=inbuild/mkosi.confis read by the tool, so the floor cannot drift away from what the tool accepts without the gate failing. - The M26 kernel build rows were checked by
tools/test_kernel_build.pyandmake verify-kerneluntil D112 removed both; they now record a retired admission and nothing reads them back. - The M23 rows are checked by
tools/test_latency_fixture.pythe same way, and that test additionally holds the set of programs the latency gate is allowed to invoke at all. That set is the D57 statement in mechanical form: it contains no installer, no bootloader tool and nothing that writes outside the build directory, so adding one failsmake verify-allrather than being noticed in review. - The M27 display-toolchain rows are checked by
tools/test_display_toolchain.py, which holds this page's table to theTOOLCHAINandLOCKEDlists oftools/display_toolchain.pyand the libva pins to theenv:block of.github/workflows/ci.yml.make verify-rustrunstools/display_toolchain.pybefore it builds, so the evidence names the pkgconf, libva and clang the crate was built with. - The M10 rows are checked by
tools/test_nucleus_kernel.pythe same way, and that test also holds the programs the Nucleus kernel gate may start: cosign, imago, bash, bpftool and, in the fetch only, curl. The emulator is not among them, because the gate starts it only through M23'sboot().make verify-nucleus-kernelthen reads each version back before it boots anything. - The M21 rows are checked by
tools/test_workstation_slices.py, which holds every digest inbuild/sandbox/firecracker.pin.jsonagainst an independent copy, the one sudo command and the programs the gate may start.make verify-workstationhashes the fetched binary, licence, kernel and configuration against the pin and readsfirecracker --versionback before anything boots; the socket2 and saeptum-microvm rows are held bycrates/aegis-vesta-sandbox/tests/manifest_hygiene.rs, and the tornus-geometry row bycrates/aegis-hephaestus/tests/manifest_hygiene.rs. - The M24 rows are checked by
tools/test_boot_harness.pythe same way, with the three OVMF images compared by digest. That test also holds the programs the boot harness may start, which contain nothing that writes a firmware variable or a boot entry, and it requires every admitted tool to be one the gate runs.make verify-bootthen reads each version and digest back before it boots anything.