From 97ade2632685d1378f63ee5d386ae97470b90f03 Mon Sep 17 00:00:00 2001 From: Samueru-sama Date: Thu, 22 Oct 2026 06:50:58 -0400 Subject: [PATCH 1/4] Close T-18 against v0.2.8 and rewrite the work order v0.2.8 is published with 40 assets across five architectures. T-18 is closed in place, under its own title, with the acceptance command and its output: `gh release list`, a full `gh release download`, and `sha256sum -c` over all five checksum files, which verifies every asset against the number published beside it. The entry's premise said aarch64 had never been built anywhere. That has been false since v0.1.0: release.yml builds five architectures and runs the evidence table on ubuntu-24.04-arm. The correction is written beneath the premise rather than edited into it, because the title is how the entry is cited elsewhere. INDEX.md moves infrastructure to 6 open and 3 done, totals to 18/1/3, and high priority to 5. The counts were read out of the entries themselves. PROGRESS.md named v0.2.6 as the published release and carried a work order whose first item merged as PR #41 in v0.2.7. It now names v0.2.8, records that v0.2.8 is the first release carrying the ppc64le resolver frame repair, and orders the three things actually left: the unchecked class in glfwd_try_vendor, wiring gl-fwd-qemu-check into a runner, and the remaining stale totals in docs/ground-truth.md. Two things a next session should not re-derive are recorded as distrust notes: the scheduled appimage-suite is red because upstream's demo AppDir no longer carries a dispatcher slot, and the release gate does not run the wide suite at all. --- docs/todo/INDEX.md | 8 ++-- docs/todo/PROGRESS.md | 85 ++++++++++++++++++++----------------- docs/todo/infrastructure.md | 50 +++++++++++++++++++++- 3 files changed, 99 insertions(+), 44 deletions(-) diff --git a/docs/todo/INDEX.md b/docs/todo/INDEX.md index 6d70ef7..1dfdc67 100644 --- a/docs/todo/INDEX.md +++ b/docs/todo/INDEX.md @@ -12,15 +12,15 @@ nowhere else. This file is a list, not an order and not a log. | | open | partially done | done | total | |---|---|---|---|---| | measurement | 5 | 1 | 0 | 6 | -| infrastructure | 7 | 0 | 2 | 9 | +| infrastructure | 6 | 0 | 3 | 9 | | blocked | 7 | 0 | 2 reclassified | 9 | -| **total** | **19** | **1** | **2 done, 2 reclassified** | **24** | +| **total** | **18** | **1** | **3 done, 2 reclassified** | **24** | By priority, across the open and partially-done rows: | priority | count | |---|---| -| high | 6 | +| high | 5 | | medium | 7 | | low | 0 | | blocked (no priority, because a machine unblocks these rather than a decision) | 7 | @@ -45,7 +45,7 @@ By priority, across the open and partially-done rows: | T-15 | [A corpus test with a fresh process per library](infrastructure.md) | infrastructure | medium | open | | T-16 | [Delete the path that would mask the failure](infrastructure.md) | infrastructure | medium | open | | T-17 | [The IBT property note is documented and is not there](infrastructure.md) | infrastructure | medium | open | -| T-18 | [There is no release](infrastructure.md) | infrastructure | high | open | +| T-18 | [There is no release](infrastructure.md) | infrastructure | high | done | | B-01 to B-09 | [the blocked list](blocked.md), nine rows. ⚠ **Two of them are not blocked**; the correction is at the foot of that file and the work is T-02 and T-06 | blocked | n/a | 7 open, 2 reclassified | --- diff --git a/docs/todo/PROGRESS.md b/docs/todo/PROGRESS.md index 7bf71bb..f567d30 100644 --- a/docs/todo/PROGRESS.md +++ b/docs/todo/PROGRESS.md @@ -8,63 +8,70 @@ ## Where the work is right now -[v0.2.6](https://github.com/pkgforge-dev/cross-libc-dlopen/releases/tag/v0.2.6) is +[v0.2.8](https://github.com/pkgforge-dev/cross-libc-dlopen/releases/tag/v0.2.8) is published. | workflow | latest on `main` | |---|---| | `gates` | ✅ | | `secret-sweep` | ✅ | -| `release` | ✅ on `v0.2.6` | +| `release` | ✅ on `v0.2.8` | -**This branch fixes the host lookup that stopped on a library the loader would -refuse, on branch `fix/gl-fwd-wrong-class`, and needs a release once merged. -`v0.2.6` was released from `main` before it, so no released artefact carries -the fix.** +`v0.2.8` is the first release that carries the ppc64le resolver frame repair +(PR #60). Every earlier release, `v0.2.7` included, ships a `gl-fwd.so` whose +`glfwd_resolve_asm` saved r5 and r6 where the C callee writes its caller's LR +and TOC slots, so the first call of any GL entry point taking a third or fourth +integer argument was handed garbage. Issue #59 is the report; the gtk3-demo +ppc64le AppImage exits 139 under `v0.2.7` and stays alive under a build from +this commit. --- ## ⛔ The work order -### 1. `glfwd_try_soname` must not stop on a library the loader will refuse +### 1. `glfwd_try_vendor` accepts a matching filename without checking its class -`glfwd_try_soname` took the first directory in which its own soname existed, and -`glfwd_each_dir` stopped the walk there. A candidate of the other ELF class -cannot load, so a host whose own answer named a 32bit library directory first -produced a target that could not load, and the directory after it was never -reached. Reproduced by removing `libGL.so.1` from the host-drivers demo AppDir, -which forces the host path, and naming the 32bit directory first with -`CROSS_LIBC_DLOPEN_GL_HOST_DIR`. +`glfwd_try_soname` now skips a candidate of the other ELF class, and +`glfwd_try_vendor` does not. A host whose only vendor library is the wrong +class is therefore reported as having one. It is a different path, reached only +when the bundle carries a dispatcher, so it needs a bundled-dispatcher case to +measure. Nothing in this session's change touches it. -The repair reads the candidate's ELF ident and skips a candidate of the other -class, so the walk continues. `docs/report/09-the-second-boundary.md` 9.21 has -the transcript, E103 is the case, and `docs/report/08-test-results.md` owns the -new totals. +### 2. Wire `make gl-fwd-qemu-check` into a runner -### 2. What is still open +The case that caught the ppc64le frame exists and fails on the old source, but +nothing runs it: `gates.yml` builds ppc64le and runs +`scripts/verify-artifacts.sh`, which never executes a trampoline. The target is +run by hand today. ⚠ This is issue #59's first loose end and it is the reason +that class of bug reached a release at all. -`glfwd_try_vendor` accepts a matching filename without checking its class, so a -host whose only vendor library is the wrong class is reported as having one. It -is a different path, reached only when the bundle carries a dispatcher, and it -needs a bundled-dispatcher case to measure. Nothing in this session's change -touches it. +### 3. Close the release-shaped staleness the tracker already reported + +Issue #46 named this file and T-18. Both are corrected here. ⚠ The same class +remains in [`../ground-truth.md`](../ground-truth.md), which still states the +evidence table as 22/22 (issue #45); that is the next document to check against +[`../report/08-test-results.md`](../report/08-test-results.md), which owns the +totals. --- ## ⚠ What a new session should distrust -- **E103 forces the order through `/etc/ld.so.conf.d`, and a host whose own - answer puts the 64bit directory first never reaches the defect.** Debian 10 - is such a host: `libc6-i386` names `/usr/lib32` and `/lib32` in - `zz_i386-biarch-compat.conf`, which sorts after `x86_64-linux-gnu.conf`. So - the case pins the predicate, not a claim about any one distribution. -- **The host-drivers demo AppDir bundles the glvnd dispatcher, so the shim - takes the bundled path on a glvnd host and never reaches the host lookup.** - Removing `libGL.so.1` from that AppDir is what exposes the path, and the - deletion is a harness step rather than a change to any shipped AppImage. -- **A Qt6 GLX path does not link `libGL.so.1`.** `libqxcb-glx-integration.so` - and `libQt6Gui.so.6` need `libGLX.so.0` and `libOpenGL.so.0`, so which arm a - Qt application reaches depends on what else in its AppDir links - `libGL.so.1`. Check `readelf -d` before assuming. -- **`docs/todo/INDEX.md` carries the counts it carried before this session.** - Reconcile them if an entry moves. +- **The scheduled `appimage-suite` on `main` is red, and the failure is + upstream's, not this tree's.** Both architectures fail at + `experiments/41-extract.sh` with `no dispatcher slot in AppDir/lib.`: the + `demo` release of `Anylinux-AppImages` no longer carries + `cross-libc-dlopen.so` or `foreign-dlopen.so` in `lib/`. The extraction + refuses rather than guessing, which is what it was built to do. Verify against + the upstream asset before treating it as a defect here. +- **The release gate is not the wide suite.** `release.yml` runs the evidence + table on x86_64 and aarch64 and then builds all five architectures. It does + not run `run-appimage.sh`, so a green `v0.2.8` does not mean the AppImage + suite is green. +- **`v0.2.8` was tagged on `main` at `900a393`, which is the PR #60 merge + commit.** CI for that PR ran on the PR head commits, whose tree is + `62985da`. The trees are identical; the commits are not. Do not read the + merge commit's absence from the run list as "the tag was never tested". +- **`docs/todo/INDEX.md`'s counts were reconciled in this session** with T-18 + closed. `sh scripts/check-drift.sh` checks the rows against the entries and + does not check the totals, so a future closure moves numbers no gate reads. diff --git a/docs/todo/infrastructure.md b/docs/todo/infrastructure.md index deaceae..4cf930a 100644 --- a/docs/todo/infrastructure.md +++ b/docs/todo/infrastructure.md @@ -378,7 +378,7 @@ cites exists, and every module a tool imports is reachable from that tool's own - **Source.** The operator, at the end of the port session. - **Category** infrastructure, **Priority** high, **Effort** medium, - **Status** open + **Status** done - **Problem.** `scripts/build.sh` produces verified artefacts and a manifest, and nothing publishes them. A consumer who wants `gl-fwd.so` has to build it, which means having a container engine and this repository. @@ -397,3 +397,51 @@ cites exists, and every module a tool imports is reachable from that tool's own - **Prove.** A release exists whose assets' checksums match `build-manifest.json` for both architectures, and whose body was not written by hand. + +### Correction: the title was true when it was written and has not been since v0.1.0 + +The title is kept because it is how this entry has been cited everywhere else. +The premise above is superseded, and the correction is written here rather +than edited into it. + +`v0.2.8` is published, and so are the eight releases before it. The workflow +that publishes them is [`release.yml`](../../.github/workflows/release.yml), +which builds **five** architectures, not the two the premise names: x86_64, +aarch64, riscv64, ppc64le and loongarch64. The aarch64 premise in particular is +disproved on every release: the `build and package aarch64` job cross-compiles +it on the floor and the `evidence table (aarch64)` job runs the suite on +`ubuntu-24.04-arm`. + +**Acceptance command and its output**, run against the published release: + +```console +$ gh release list --repo pkgforge-dev/cross-libc-dlopen --limit 3 +v0.2.8 Latest v0.2.8 2026-10-22T10:48:20Z +v0.2.7 v0.2.7 2026-09-24T18:29:17Z +v0.2.6 v0.2.6 2026-09-13T10:01:17Z + +$ gh release download v0.2.8 --repo pkgforge-dev/cross-libc-dlopen +$ for a in x86_64 aarch64 riscv64 ppc64le loongarch64; do +> sha256sum -c cross-libc-dlopen-$a.sha256 --quiet && echo "$a: ok" +> done +x86_64: ok +aarch64: ok +riscv64: ok +ppc64le: ok +loongarch64: ok + +$ tar -tf cross-libc-dlopen-x86_64.tar | grep -c / +0 +``` + +The release carries 40 assets. Every one of the five `.sha256` files verifies +against the assets it names, both archives per architecture are flat (no +nested directory, as the entry required), and the manifest inside the archive +matches the loose files beside it. The body was generated by +[`../../scripts/release-notes.sh`](../../scripts/release-notes.sh) from +`build-manifest.json`, so no checksum in it was typed. + +⚠ **What the closure does not prove.** The ancestor refusal in `release.yml` +passes on every tag because every tagged commit is on `main`; it has never been +seen to refuse a tag that was not. That remains T-10's subject, not this +entry's. From 9dd0f2af668593ae92d790690ef603c311d2714f Mon Sep 17 00:00:00 2001 From: Samueru-sama Date: Thu, 22 Oct 2026 06:52:28 -0400 Subject: [PATCH 2/4] Correct two claims the review passes did not measure Both are in PROGRESS.md, and both were caught by asking what had been asserted without being run. 900a393 is a squashed commit with one parent, not the PR #60 merge commit. The property that matters is unchanged and is now stated as the property: the tree CI tested (62985da) is the tree the tag carries, so the commits differ and the trees do not. The gtk3-demo ppc64le reproduction came from issue #59 and the PR body, not from this session. What was measured here is that `make gl-fwd-qemu-check` fails on the pre-fix gl-fwd.c and passes on the shipped one, and that the published ppc64le-gl-fwd.so carries the 288-byte frame. Nothing here ran a GTK3 application, so the entry now says so instead of repeating the report as though it were a result. --- docs/todo/PROGRESS.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/todo/PROGRESS.md b/docs/todo/PROGRESS.md index f567d30..471e290 100644 --- a/docs/todo/PROGRESS.md +++ b/docs/todo/PROGRESS.md @@ -21,9 +21,14 @@ published. (PR #60). Every earlier release, `v0.2.7` included, ships a `gl-fwd.so` whose `glfwd_resolve_asm` saved r5 and r6 where the C callee writes its caller's LR and TOC slots, so the first call of any GL entry point taking a third or fourth -integer argument was handed garbage. Issue #59 is the report; the gtk3-demo +integer argument was handed garbage. Issue #59 is the report. + +⚠ **The report's own reproduction was not rerun here.** It says the gtk3-demo ppc64le AppImage exits 139 under `v0.2.7` and stays alive under a build from -this commit. +this commit, and the commit message repeats that. What was measured in this +session is narrower: `make gl-fwd-qemu-check` fails on the pre-fix `gl-fwd.c` +and passes on the shipped one, and the published `ppc64le-gl-fwd.so` carries +the 288-byte frame. Nothing here ran a GTK3 application. --- @@ -68,10 +73,11 @@ totals. table on x86_64 and aarch64 and then builds all five architectures. It does not run `run-appimage.sh`, so a green `v0.2.8` does not mean the AppImage suite is green. -- **`v0.2.8` was tagged on `main` at `900a393`, which is the PR #60 merge - commit.** CI for that PR ran on the PR head commits, whose tree is - `62985da`. The trees are identical; the commits are not. Do not read the - merge commit's absence from the run list as "the tag was never tested". +- **`v0.2.8` was tagged on `main` at `900a393`, the squashed commit that + landed PR #60.** CI for that PR ran on the PR head commits, and the tree they + tested is `62985da`, which is the tree the tag carries. The commits differ and + the trees do not, so the tag's absence from the run list is not evidence that + the tag was never tested. - **`docs/todo/INDEX.md`'s counts were reconciled in this session** with T-18 closed. `sh scripts/check-drift.sh` checks the rows against the entries and does not check the totals, so a future closure moves numbers no gate reads. From 9098a7afa04519bed1de1fb021ef128ef12289ec Mon Sep 17 00:00:00 2001 From: Samueru-sama Date: Fri, 23 Oct 2026 17:14:41 -0400 Subject: [PATCH 3/4] Record v0.2.9 and what the NixOS cases do not prove v0.2.9 is published with 40 assets across five architectures. PROGRESS named v0.2.8 and carried a work order that the NixOS change did not touch. The new release adds /run/opengl-driver/lib and /run/current-system/sw/lib to three lists, and the container suite reports 69/69 on x86-64, which is the 66 this file recorded plus E104, E105 and E106. The entry says so rather than leaving the previous total standing. Two review passes, asking different questions. Pass 1, does every claim hold when the command is run: swept the suite output and the tag/binary claims. Found that this file first said the three cases "were not measured here" while also reporting the 69/69 that includes them. They do run, in the container, as root; what is missing is a NixOS host. Rewritten to say that. Pass 2, what did I assert that I did not measure: swept every factual sentence added. Found a pointer claiming report section 10 carries the NixOS measured-versus-assumed distinction. It does not mention NixOS at all, so the text now says that writing it is open work instead of citing it. The one sentence that survives is the A/B actually run here: the fake-libva contract prints NO-DRIVER on the v0.2.8 source and DRIVER=NIX on the shipped one. --- docs/todo/PROGRESS.md | 81 ++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/docs/todo/PROGRESS.md b/docs/todo/PROGRESS.md index 471e290..2e5f800 100644 --- a/docs/todo/PROGRESS.md +++ b/docs/todo/PROGRESS.md @@ -8,27 +8,43 @@ ## Where the work is right now -[v0.2.8](https://github.com/pkgforge-dev/cross-libc-dlopen/releases/tag/v0.2.8) is +[v0.2.9](https://github.com/pkgforge-dev/cross-libc-dlopen/releases/tag/v0.2.9) is published. | workflow | latest on `main` | |---|---| | `gates` | ✅ | | `secret-sweep` | ✅ | -| `release` | ✅ on `v0.2.8` | - -`v0.2.8` is the first release that carries the ppc64le resolver frame repair -(PR #60). Every earlier release, `v0.2.7` included, ships a `gl-fwd.so` whose -`glfwd_resolve_asm` saved r5 and r6 where the C callee writes its caller's LR -and TOC slots, so the first call of any GL entry point taking a third or fourth -integer argument was handed garbage. Issue #59 is the report. - -⚠ **The report's own reproduction was not rerun here.** It says the gtk3-demo -ppc64le AppImage exits 139 under `v0.2.7` and stays alive under a build from -this commit, and the commit message repeats that. What was measured in this -session is narrower: `make gl-fwd-qemu-check` fails on the pre-fix `gl-fwd.c` -and passes on the shipped one, and the published `ppc64le-gl-fwd.so` carries -the 288-byte frame. Nothing here ran a GTK3 application. +| `release` | ✅ on `v0.2.9` | + +`v0.2.9` adds the three NixOS host directories: `/run/opengl-driver/lib` and +`/run/current-system/sw/lib` join the shim's fixed host list, the assembled +`--library-path`, and the libva `/dri` list. NixOS is neither FHS nor a +host that writes `/etc/ld.so.conf`, so before this each of the three failed +differently and silently. + +⚠ **The three cases ran in the container; no NixOS host was behind them.** E104, +E105 and E106 create `/run/opengl-driver/lib`, which needs root, so the container +suite runs all three and reports MATCH; that is why the local total is **69/69 on +x86-64** and not the 66 the previous release recorded. Where `/run` is not +writable each SKIPS by name instead. ⛔ **Nothing in this tree has run the shims +on a NixOS host.** The cases prove the lists carry the directories and that a +library placed there is found; they do not prove the directories are where a +real NixOS system puts its GPU userspace, and +[`../report/10-measured-versus-assumed.md`](../report/10-measured-versus-assumed.md) +does not yet carry that distinction. Writing it there is open work, not a +citation. + +The mechanism was also confirmed here as an A/B independent of the suite: the +fake-libva contract run against the `v0.2.8` source prints `NO-DRIVER`, and +against the shipped source prints `DRIVER=NIX`. The published binaries carry +the directory strings. + +`v0.2.8` remains the first release carrying the ppc64le resolver frame repair +(PR #60). `v0.2.7` and earlier ship a `gl-fwd.so` whose `glfwd_resolve_asm` +saved r5 and r6 where the C callee writes its caller's LR and TOC slots, so the +first call of any GL entry point taking a third or fourth integer argument was +handed garbage. Issue #59 is the report. --- @@ -36,7 +52,7 @@ the 288-byte frame. Nothing here ran a GTK3 application. ### 1. `glfwd_try_vendor` accepts a matching filename without checking its class -`glfwd_try_soname` now skips a candidate of the other ELF class, and +`glfwd_try_soname` skips a candidate of the other ELF class, and `glfwd_try_vendor` does not. A host whose only vendor library is the wrong class is therefore reported as having one. It is a different path, reached only when the bundle carries a dispatcher, so it needs a bundled-dispatcher case to @@ -50,13 +66,12 @@ nothing runs it: `gates.yml` builds ppc64le and runs run by hand today. ⚠ This is issue #59's first loose end and it is the reason that class of bug reached a release at all. -### 3. Close the release-shaped staleness the tracker already reported +### 3. The stale totals in `docs/ground-truth.md` -Issue #46 named this file and T-18. Both are corrected here. ⚠ The same class -remains in [`../ground-truth.md`](../ground-truth.md), which still states the -evidence table as 22/22 (issue #45); that is the next document to check against -[`../report/08-test-results.md`](../report/08-test-results.md), which owns the -totals. +It still states the evidence table as 22/22 (issue #45). The home for the +totals is [`../report/08-test-results.md`](../report/08-test-results.md), which +now says 69/69 and 65/65. This is the last document of the release-shaped +staleness class that issue #46 opened, and T-18 is closed. --- @@ -71,13 +86,17 @@ totals. the upstream asset before treating it as a defect here. - **The release gate is not the wide suite.** `release.yml` runs the evidence table on x86_64 and aarch64 and then builds all five architectures. It does - not run `run-appimage.sh`, so a green `v0.2.8` does not mean the AppImage + not run `run-appimage.sh`, so a green `v0.2.9` does not mean the AppImage suite is green. -- **`v0.2.8` was tagged on `main` at `900a393`, the squashed commit that - landed PR #60.** CI for that PR ran on the PR head commits, and the tree they - tested is `62985da`, which is the tree the tag carries. The commits differ and - the trees do not, so the tag's absence from the run list is not evidence that - the tag was never tested. -- **`docs/todo/INDEX.md`'s counts were reconciled in this session** with T-18 - closed. `sh scripts/check-drift.sh` checks the rows against the entries and - does not check the totals, so a future closure moves numbers no gate reads. +- **The NixOS directories are a host class nobody has run.** The three cases + prove the lists carry the directories and that a library placed there is + found. No NixOS host has been behind the shims, and + [`../report/10-measured-versus-assumed.md`](../report/10-measured-versus-assumed.md) + is where that distinction belongs if it is not already written there. +- **A tag's tree, not its commit, is what CI tested.** `v0.2.8` and `v0.2.9` + are both squashed commits, so their hashes appear in no run. Check + `git rev-parse ^{tree}` against the PR head's tree before concluding a + tag went untested. +- **`docs/todo/INDEX.md`'s counts are checked by hand.** `sh scripts/check-drift.sh` + reconciles the rows against the entries and does not check the totals, so a + future closure moves numbers no gate reads. From f8cde15ac8cb7b9a889b454f4078d6d859d9b0ea Mon Sep 17 00:00:00 2001 From: Samueru-sama Date: Fri, 23 Oct 2026 17:17:26 -0400 Subject: [PATCH 4/4] Stop PROGRESS restating the evidence totals The hygiene gate refused this branch: 69/69 and 65/65 each appeared in two files, docs/report/ and docs/todo/PROGRESS.md. Every headline number has one home and it is the report; a second copy is the defect the gate exists to catch, and it caught this one on a runner. The two sentences now say what changed without repeating the number: the container runs the three cases so the total rises, and section 8 carries the current pair. --- docs/todo/PROGRESS.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/todo/PROGRESS.md b/docs/todo/PROGRESS.md index 2e5f800..0a23b0a 100644 --- a/docs/todo/PROGRESS.md +++ b/docs/todo/PROGRESS.md @@ -25,12 +25,12 @@ differently and silently. ⚠ **The three cases ran in the container; no NixOS host was behind them.** E104, E105 and E106 create `/run/opengl-driver/lib`, which needs root, so the container -suite runs all three and reports MATCH; that is why the local total is **69/69 on -x86-64** and not the 66 the previous release recorded. Where `/run` is not -writable each SKIPS by name instead. ⛔ **Nothing in this tree has run the shims -on a NixOS host.** The cases prove the lists carry the directories and that a -library placed there is found; they do not prove the directories are where a -real NixOS system puts its GPU userspace, and +suite runs all three and reports MATCH, which is why the local total is higher +than the previous release's. Where `/run` is not writable each SKIPS by name +instead. ⛔ **Nothing in this tree has run the shims on a NixOS host.** The cases +prove the lists carry the directories and that a library placed there is found; +they do not prove the directories are where a real NixOS system puts its GPU +userspace, and [`../report/10-measured-versus-assumed.md`](../report/10-measured-versus-assumed.md) does not yet carry that distinction. Writing it there is open work, not a citation. @@ -70,7 +70,7 @@ that class of bug reached a release at all. It still states the evidence table as 22/22 (issue #45). The home for the totals is [`../report/08-test-results.md`](../report/08-test-results.md), which -now says 69/69 and 65/65. This is the last document of the release-shaped +carries the current pair. This is the last document of the release-shaped staleness class that issue #46 opened, and T-18 is closed. ---