@@ -357,3 +357,97 @@ discovery.
357357Everything except item 4 can start without further input. Item 4 is a
358358compatibility decision about a published contract, and the recommendation in
359359§4.2 is a recommendation rather than a conclusion.
360+
361+ ---
362+
363+ ## 7. Outcomes (2026-09-04, same day)
364+
365+ All four items were implemented, one pull request per repository. What follows
366+ records what was measured, including two places where a first attempt passed
367+ without testing anything.
368+
369+ | gap | delivered | where |
370+ | ---| ---| ---|
371+ | 1 | openarch 0.9.0: ARMv7-A backend, ` arch_pte_entry_bytes() ` | openarch #9 |
372+ | 2 | ` when = "run" ` on both boards, with the pair asserted | riscv-virt-rt #5 , aarch64-virt-rt #3 |
373+ | 3 | ` mcpp run ` reports the program's status | mcpp #555 |
374+ | 4 | mcpp kills its child; ` MCPP_NINJA_DEBUG ` ; ninja pinned by checksum | mcpp #555 , xim-pkgindex #756 |
375+
376+ ### 7.1 Gap 1: the answer is "no, and here is the missing query"
377+
378+ The width question is settled. ARMv7-A's short-descriptor entry is 32 bits and
379+ FITS in the ` arch_u64 ` the interface carries, so the carrier did not change —
380+ but nothing could ask how wide the storage is, and a kernel sizing a table from
381+ ` sizeof(arch::pte) ` builds one twice as large as the hardware walks. Nothing
382+ diagnoses that: the table is well formed, the entries are correct, and the
383+ machine reads the gaps.
384+
385+ ` arch_pte_entry_bytes() ` is the addition, implemented by all five backends. The
386+ header's own claim — "a page-table entry is 64 bits on every machine here" — was
387+ corrected rather than left standing.
388+
389+ Asserted twice, because one place cannot cover both halves: ` tests/pte_encoding `
390+ compares the encoder against a descriptor written out from the architecture
391+ manual, and a CI job boots a program on qemu ` -M virt -cpu cortex-a15 ` that
392+ reads the width back THROUGH THE ABI and exits 0 only if it is 4. Measured:
393+ ` armv7a pte width 4, entry fits 32 bits ` , exit 0.
394+
395+ ` openarch:preemption ` is withheld on this machine. The resumption address lives
396+ on the SVC stack rather than in a register, so a trap-time switch is well
397+ defined only if the resumed context was suspended the same way — a real design,
398+ and not one this backend has measured. Withholding it refuses a consumer by
399+ name at resolution, which is the mechanism Cortex-M already uses for
400+ ` openarch:address-space ` .
401+
402+ ### 7.2 Gap 2: the criterion needed an isolated home
403+
404+ The tier itself was two lines. The assertion was not: on a machine where the
405+ emulator is already installed, ` MCPP_NO_AUTO_INSTALL ` has nothing to report, so
406+ BOTH halves read empty and the step passes without testing anything. Measured in
407+ exactly that state before the step was moved to an isolated ` MCPP_HOME ` .
408+
409+ With one, the pair is decisive and needs no download: a build names the emulator
410+ zero times, and a run refuses with ` declared but not provisioned ` naming
411+ ` xim:qemu-riscv@9.2.4-1 ` . CI reports `ok build asks for no emulator, run asks
412+ for xim: qemu-riscv ` on both boards.
413+
414+ ### 7.3 Gap 3: three bands, and 2 stays where it is
415+
416+ ` mcpp run ` passes the child's status through. Spawn refusals move to 125-127,
417+ the band ` env ` , ` timeout ` and ` nice ` already use. mcpp's own refusals BEFORE a
418+ spawn — no binary target, no runner declared, a runner not on PATH — keep exit
419+ 2, which is what every other mcpp command uses, so no existing script that
420+ tests for it changes meaning. Only the case where the program never ran moved.
421+
422+ ` mcpp test ` is unchanged at 0/1: it aggregates many programs and has no single
423+ status to pass through.
424+
425+ ### 7.4 Gap 4: the fix, and what the test had to be to catch it
426+
427+ Fixing ` run_exec ` alone left the orphan in place, because a full build spawns
428+ ninja through ` capture_exec ` . The A/B caught it; reading the code had not.
429+
430+ THE TEST SIGNALS mcpp's PID ALONE. ` timeout ` and Ctrl-C both signal the process
431+ group and reached ninja even before the fix, so a test built on ` timeout ` passes
432+ either way — the first version of this test did exactly that. The second version
433+ used 200 parallel translation units and passed against a defective build because
434+ a 32-core host finished the batch inside the ten-second window. ` --jobs 1 ` makes
435+ the window deterministic by construction. The final test FAILS against the
436+ released 2026.9.4.2, naming the orphan and its ` (deleted) ` working directory.
437+
438+ The spin's cause remains unestablished and §1.3 stands. ` MCPP_NINJA_DEBUG `
439+ appends ` -d explain ` to both ninja launches so the next occurrence can be read
440+ rather than guessed at.
441+
442+ ### 7.5 A finding the ninja work turned up
443+
444+ ` xim:ninja@1.12.1 ` now carries a checksum. While computing it, a stronger fact
445+ than §1.5's appeared: this machine holds ninja binaries at THREE distinct sizes
446+ under that one version, and the twelve copies at 290152 bytes have twelve
447+ DIFFERENT SHA-256 values.
448+
449+ Same size and different content is the signature of in-place patching, which
450+ xlings does to installed binaries. So an installed ninja cannot be compared
451+ against a published checksum at all — only the downloaded archive can, which is
452+ what the checksum added here covers. A clean-home install was verified to fetch,
453+ verify and produce the 2202320-byte static binary the descriptor describes.
0 commit comments