Skip to content

Commit 1020a97

Browse files
ci: bootstrap pin moves to 2026.9.2.1 (#546)
* ci: bootstrap pin moves to 2026.9.2.1 The release is published, mirrored and indexed: `latest` in openxlings/xim-pkgindex points at 2026.9.2.1, and its `Publish Index Artifact` run is green on that commit, which is what `xlings install` consumes. The pin is bumped only after that sequence, never before it — CI installs the pinned version from the index, so a pin ahead of the index is a job that cannot start. * design: record what the release verified, and the three axes section 8 did not state Section 13 carries the observed transcript rather than the expected one: the sandbox run on the published 2026.9.2.1, the openkal consumer built for aarch64-linux-musl and executed through the declared runner, and the release state with the checks that were recomputed rather than read from a sidecar. Its load-bearing line is a shell error. `qemu-aarch64-static` is not on PATH in that SubOS, and the two preceding sections had already run the artifact through it — which establishes the one chain no e2e covers, from [xlings] deps to the payload bin/ that runner_lookup searches first. Section 8 gains consistency, upgrading, and what a person sees. The first two were implicit in the structure and compatibility paragraphs; stating them separately is what makes 'no second derivation' and 'no cache invalidated' checkable claims rather than consequences someone has to notice. --------- Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
1 parent 8de3847 commit 1020a97

2 files changed

Lines changed: 169 additions & 1 deletion

File tree

.agents/docs/2026-09-02-runner-beyond-baremetal-design.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,34 @@ text and JSON change.
565565
`PATH`. The mechanism a user must understand is one sentence: mcpp uses the
566566
runner you declared, and tells you what the kernel said when there is none.
567567

568+
569+
**Consistency.** One key, one lookup, one set of messages, and both doors use
570+
them. `mcpp run` and `mcpp test` read the same `choose_runner`; the runner's
571+
program is located by the same `locate` on both; the not-found and unrunnable
572+
sentences are written once in `mcpp.build.runner_lookup` and printed from four
573+
call sites. The triple those messages name is the one the lookup used, because
574+
it is the same field. Where a second derivation existed it was removed rather
575+
than kept in step: the triple was parsed three times in `choose_runner` and is
576+
now parsed once.
577+
578+
**Upgrading without noticing.** No manifest key is added, so a project written
579+
for this version loads on an older mcpp; no cache is invalidated, because
580+
`.build_cache` gains an optional line that an older reader treats as the end of
581+
its data and a newer reader defaults to `false`; and `[xlings]` values that
582+
are strings keep parsing as strings. The three behaviour changes a project can
583+
notice are stated in section 8's Compatibility paragraph and in the changelog,
584+
and each is a case that was previously silent: a runner that was never
585+
consulted, a spawn failure that printed nothing, and a table value that was
586+
dropped.
587+
588+
**What a person sees.** Every failure names the thing that failed and the edit
589+
that would change it: the program and the directories searched, or the kernel's
590+
own sentence and the key to paste. Nothing reports a state it did not observe —
591+
a test that did not run is not called a failure, and a spawn that was refused
592+
is not given the child's exit code. The one flag added is the one fact the
593+
manifest cannot hold, and it prints a note when it takes effect, so a
594+
transcript shows the deviation rather than hiding it.
595+
568596
## 9. Rejected alternatives
569597

570598
**A host-capability oracle.** Deciding before spawning, from the triple plus
@@ -749,3 +777,143 @@ Listed so the change can be sized and split. Each line is one concern.
749777
each one's `docs/zh/` twin, which CI enforces.
750778
- `tests/e2e/`: one new script covering the table in section 11;
751779
`tests/unit/`: the launcher invariant.
780+
781+
## 13. Verification of the release
782+
783+
The design was implemented in PR #545 and released as 2026.9.2.1. What follows
784+
is what was observed, not what was expected: the commands, and the lines they
785+
produced.
786+
787+
### 13.1 What CI established
788+
789+
All 37 checks on the PR and all nine workflows on the merge commit
790+
(`8de3847`) are green. Two of the checks were red before commits made during
791+
the merge review and are recorded here because their failure was informative
792+
rather than incidental.
793+
794+
`tests/unit/test_process_run_exec.cpp` asserted `ENOEXEC` from a file the host
795+
cannot load. On macOS `posix_spawnp` does not answer `ENOEXEC` for such a
796+
file — it runs it through `/bin/sh` — so the assertion is Linux-only and now
797+
says so. This is open question 1 of section 10, answered in the direction the
798+
question anticipated: the platform's refusal is not the same refusal
799+
everywhere, which is why nothing in the design predicts it.
800+
801+
e2e 330 §3 failed only on macOS ARM64. `choose_runner` resolves the manifest
802+
key against the canonical triple, while the six diagnostics it feeds printed
803+
`tc.targetTriple`, the spelling the driver reports. The two strings are equal
804+
on Linux and differ on macOS (`aarch64-macos` against
805+
`arm64-apple-darwin24.6.0`). Three of the six print a `[target.<triple>]`
806+
block for the reader to paste, so on macOS the advice named a key that no
807+
lookup resolves. `RunnerChoice::tripleKey` is now derived once, beside the
808+
lookup that uses it.
809+
810+
### 13.2 The sandbox verification
811+
812+
The wiring that section 11 does not cover with an e2e — `[xlings] deps` to
813+
`BuildContext::xlingsDepBinDirs` to `runner_lookup::locate` — is established
814+
here, on the published artefacts, in a SubOS created for this purpose:
815+
816+
```
817+
xlings update
818+
xlings subos new e544-0902
819+
xlings subos use e544-0902 --sandbox --cmd '<the script below>'
820+
```
821+
822+
```sh
823+
mcpp self config --mirror CN
824+
825+
mcpp new xrun && cd xrun
826+
cat >> mcpp.toml <<'TOML'
827+
[xlings]
828+
deps = [{ linux = "qemu-user-aarch64" }]
829+
830+
[target.aarch64-linux-musl]
831+
runner = ["qemu-aarch64-static"]
832+
TOML
833+
mcpp run --target aarch64-linux-musl # A
834+
mcpp test --target aarch64-linux-musl # B
835+
command -v qemu-aarch64-static # C
836+
# then: remove the runner key, patch e_machine to 0xffff, repeat # D, E
837+
```
838+
839+
Observed, in order:
840+
841+
```
842+
=== identity ===
843+
mcpp 2026.9.2.1
844+
845+
=== A. cross build + run through the declared runner ===
846+
Downloading xim:qemu-user-aarch64@7.2.0
847+
Running `qemu-aarch64-static … target/aarch64-linux-musl/…/bin/xrun`
848+
CROSS-RAN
849+
850+
=== B. mcpp test through the runner ===
851+
test result ok. 1 passed; 0 failed; finished in 0.19s (build 0.06s + run 0.02s)
852+
853+
=== C. the payload lookup wins over the PATH shim ===
854+
sandbox_verify.sh: line 58: qemu-aarch64-static: command not found
855+
856+
=== D. no runner declared, artifact this host cannot load ===
857+
error: this host cannot execute '…/bin/xrun': Exec format error (error 8).
858+
The artifact was built for 'aarch64-linux-musl'. Declare how to run it here:
859+
860+
[target.aarch64-linux-musl]
861+
runner = ["qemu-aarch64-static"]
862+
863+
=== E. mcpp test reports not-run and exits 2 ===
864+
error: test result: NOT RUN. 0 passed; 0 failed; 1 not run (this host cannot execute
865+
aarch64-linux-musl artifacts: Exec format error (error 8); declare
866+
[target.aarch64-linux-musl].runner, or pass --no-runner on a host that can)
867+
```
868+
869+
**C is the criterion, and it reads as a failure.** `qemu-aarch64-static` is not
870+
on `PATH` in this SubOS at all, and A and B had already executed the artifact
871+
through it. The only path by which the program could have been found is the
872+
`bin/` of the payload that `deps = [{ linux = "qemu-user-aarch64" }]`
873+
provisioned, which is the chain no e2e covers. On the development host the same
874+
section reads differently and says the same thing: the bare name resolves to an
875+
xvm shim that answers `qemu-aarch64-static is not installed in this subos (_)`,
876+
while the build had just run through the payload copy.
877+
878+
D and E patch `e_machine` to `0xffff` rather than relying on the artifact's own
879+
architecture. This host registers `qemu-aarch64` in `binfmt_misc` with flags
880+
`PO`, so an unpatched `aarch64-linux-musl` binary starts here — the asymmetry
881+
section 2 measured, and the reason no criterion depends on which machine runs
882+
it. The scripts re-read the patched bytes after the run, so a rebuild between
883+
the patch and the launch fails the check rather than passing it silently.
884+
885+
### 13.3 The published ecosystem
886+
887+
The same SubOS, an `openkal-llvm-runtime` consumer built for
888+
`aarch64-linux-musl` and executed through the declared runner:
889+
890+
```
891+
Resolved llvm@22.1.8 → aarch64-linux-musl → …/xim-x-llvm/22.1.8/bin/clang++
892+
required by openkal-llvm-runtime@0.1.3 (`requires = ["mcpp:compiler=llvm"]`)
893+
Target aarch64-linux-musl → aarch64-unknown-linux-musl
894+
compiler-runtime compiler-rt (openkal-llvm-runtime@0.1.3, graph)
895+
kernel-abi openkal (openkal-linux@0.5.4, graph)
896+
c-abi musl (openkal-musl@0.3.5, graph)
897+
c++-abi libc++ (openkal-llvm-runtime@0.1.3, graph)
898+
Running `qemu-aarch64-static … target/aarch64-linux-musl/…/bin/xkal`
899+
900+
preopened directories 2
901+
902+
unwinding runs destructors yes
903+
sorted sample [1, 2, 3, 7, 8, 9] (sum 30)
904+
```
905+
906+
The unwinding row is the strictest of them: an absent unwinder links and only
907+
fails when something is thrown, so a destructor run during the unwind is what
908+
separates the two. It answers `yes` under the emulator, which means the runner
909+
carried a working C++ runtime rather than merely starting the process.
910+
911+
### 13.4 Release state
912+
913+
| | |
914+
|---|---|
915+
| Tag | `v2026.9.2.1` at `8de3847` |
916+
| GitHub release | four platform payloads, sidecars, and a sealed `mcpp-release.json` |
917+
| GitCode mirror | the eight versioned assets present; `linux-x86_64` and `linux-aarch64` re-downloaded and their SHA256 recomputed against the GitHub sidecars, equal. The versionless aliases and `mcpp-release.json` are absent there, as they are for 2026.9.1.1 — `mirror_res.sh` mirrors versioned payloads only |
918+
| Index | `openxlings/xim-pkgindex` `latest` at 2026.9.2.1 (`ff0996e`), with that commit's `Publish Index Artifact` run green — the artefact `xlings install` consumes |
919+
| Clean-room install | `xlings install mcpp@2026.9.2.1 -y` in a fresh sandbox, then `mcpp --version``mcpp 2026.9.2.1` |

.xlings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"workspace": {
3-
"mcpp": "2026.9.1.1"
3+
"mcpp": "2026.9.2.1"
44
}
55
}

0 commit comments

Comments
 (0)