Skip to content

Commit ac2a84b

Browse files
committed
chore(xlings): raise the floor to 2026.8.30.2 — the store-identity fix
openxlings/xlings#576, released as v2026.8.30.2. Below this version xlings answers "is this package already installed" from the xvm version database keyed on the bare short name, so a package skips its own `install()` whenever any other namespace holds the same `<name>@<version>`. This is a FLOOR and not a preference, which is the whole reason the pin has the shape it does. The mcpp side of #533 makes the resulting failure legible on any client — the link unit is refused by name, and `.mcpp_ok` is withheld from a directory holding nothing the package installed — but only a client at or above this version INSTALLS correctly. ⚠️ This does NOT authorise an index change. Publishing a deliberately colliding `<name>@<version>` stays unsafe until the floor is adopted, not merely released, and .agents/docs/2026-08-30-cross-repo-fix-plan-532-533-534.md §6.2 recommends not doing it at all: the fix is for the collisions people hit by accident, which is already 20 short names wide on a real store. `src/xlings/xlings.cppm` is the source of truth; the seven copies under .github/ follow it and `check_version_pins.sh` enforces the agreement. Also records what landed against the plan (§12), including two things the plan had wrong: the xlings anchor was 167 commits stale and the call site had moved, and `⚠` is CI-governed in xlings while it is merely conventional here.
1 parent f519dfb commit ac2a84b

9 files changed

Lines changed: 133 additions & 21 deletions

File tree

.agents/docs/2026-08-30-cross-repo-fix-plan-532-533-534.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,3 +835,95 @@ B3 on the produced artifact rather than a log line.
835835
- The decision to keep `Source` outputs out of `actionDefaults` (§3): reaching
836836
them two ways is how the soname aliases went missing in 0.0.104.
837837
- §7's three amendments to #532.
838+
839+
---
840+
841+
## 12. What landed, and what the plan got wrong
842+
843+
Written after implementation, against the code as merged. Everything here was
844+
measured, not inferred.
845+
846+
### 12.1 Two corrections to the plan itself
847+
848+
**The xlings anchor was 167 commits stale.** §5 located Track X at
849+
`installer.cpp:903-911` and described `xvm::match_version(db, node.name, …)` as
850+
a fallback beside a namespace-aware primary path. That reading came from a local
851+
checkout dated 8 July. Upstream `main` had since consolidated four separate
852+
"is this installed" answerers into one `install_state` module whose predicate
853+
takes a namespace — and the defective call site had moved to
854+
`installer.cpp:2628`, survived the consolidation, and become a **fifth**
855+
answerer to the question that module exists to answer alone. The fix is
856+
unchanged in shape and better motivated than the plan knew.
857+
858+
The general rule this is the second instance of: *what the implementation is*
859+
can only be read from the tracked upstream branch. A worktree at the fetched
860+
ref costs one command and is the only thing that makes an anchor trustworthy.
861+
862+
**`` is CI-enforced in xlings and merely conventional in mcpp.**
863+
`tests/e2e/tui_output_contract_test.sh` §S6 greps all of `src/**/*.{cppm,cpp}`
864+
for U+26A0 and U+24D8 and fails if either appears outside
865+
`src/core/glyph.cppm` — they are label glyphs the renderer owns, and a second
866+
spelling is how a dead icon table in `src/platform/` once drifted from the real
867+
one. Two comment headers turned an otherwise-green xlings PR red (101 passed, 1
868+
failed) for comment decoration alone. `` is not governed and is already used
869+
in that tree.
870+
871+
### 12.2 What shipped
872+
873+
| | where | note |
874+
|---|---|---|
875+
| A1 | `ninja_backend.cppm` | `cc` unconditional |
876+
| A2 | `prepare.cppm`, before `return ctx` | after all three object sources |
877+
| A3 | `check_rule_commands_name_a_program` | exported, so hand-written manifests can test it |
878+
| B1 | `BuildAction::packageName` | set in `collect()`; `qualified_package_name` exported so the two spellings cannot drift |
879+
| B2 | per-package phony, 7 call sites | via `order_only_for(cu)` |
880+
| B3 | `blocking` | reaches the graph for the first time |
881+
| B4 | `prepare_actions` | placeholder gated on `is_compilable_output` |
882+
| B5 | `check_action_ordering` | with the denominator |
883+
| C1 | `payload_is_substantive` | both the write site and the fast path |
884+
| C2 | `validate.cppm` | gated on the graph containing a module interface |
885+
| D | `docs/07-build-mcpp.md` + zh | the role table and the engine comment |
886+
| X | `installer.cpp:2628`, `owner.cppm` | `payload_path_names_another_package` |
887+
888+
### 12.3 The measurement that changed the plan's priorities
889+
890+
§A0 was added mid-review and is the most consequential single fact found:
891+
892+
```
893+
$ ar rcs libempty.a ; echo $? ; stat -c %s libempty.a
894+
0
895+
8
896+
```
897+
898+
A static library target with no sources built **successfully** — confirmed
899+
against the released binary, which printed `Finished dev` and left an 8-byte
900+
`.a`. The reported symptom (`/bin/sh: 1: -shared: not found`) was the loud half
901+
of a defect whose quiet half reported success. That is why A2 is the fix and A1
902+
is hygiene, and why the check is at plan time rather than in the linker
903+
diagnostic.
904+
905+
### 12.4 Evidence that the tests discriminate
906+
907+
Every new e2e was run against the pre-fix binary (`2026.8.28.2`) and every one
908+
fails there:
909+
910+
```
911+
314 'PROTO_ANSWER' was not declared in this scope
912+
315 a failing BLOCKING check did not stop the compile — the object exists
913+
316 /bin/sh: 1: -shared: not found
914+
```
915+
916+
The xlings unit tests were checked the other way — by reverting
917+
`payload_path_names_another_package` to its previous answer and re-running.
918+
`PayloadOwnership.SameShortNameInAnotherNamespaceIsAnotherPackage` fails.
919+
920+
Neither check is optional here. Three of these tests assert a *negative*
921+
(nothing was produced, the marker was withheld, the phony is absent), and a
922+
negative assertion against absent machinery passes by describing nothing.
923+
924+
### 12.5 Unchanged
925+
926+
§1's ordering constraint and §6.2's recommendation not to re-pin the index both
927+
survived implementation. Track X removes the accidental collision, which is the
928+
common case; publishing a deliberate one stays gated on the floor being adopted,
929+
and that gate has no green checkmark.

.github/actions/bootstrap-mcpp/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ inputs:
2525
# `package.name`, so one of the two was simply unreachable — and which one
2626
# depended on the machine, which is why CI failed on `compat:lua` on
2727
# Windows and `mcpplibs.capi:lua` on Linux. Never pin below that.
28-
default: '2026.8.27.5'
28+
default: '2026.8.30.2'
2929
cache-target:
3030
description: also restore/save target/ (build artifacts + BMIs)
3131
required: false

.github/actions/setup-macos-llvm/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ inputs:
1515
# Floor imposed by the index, not a routine bump — see
1616
# .github/actions/bootstrap-mcpp/action.yml for why 0.4.69 is required
1717
# (two packages named `lua` in one repo need openxlings/xlings#381).
18-
default: '2026.8.27.5'
18+
default: '2026.8.30.2'
1919

2020
runs:
2121
using: composite

.github/workflows/bootstrap-macos.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
# Dormant (workflow_dispatch only), but kept in step with the rest —
1818
# check_version_pins.sh holds it there. Floor: 0.4.69, below which the
1919
# index cannot resolve two packages that share a short name.
20-
XLINGS_VERSION: '2026.8.27.5'
20+
XLINGS_VERSION: '2026.8.30.2'
2121
steps:
2222
- uses: actions/checkout@v4
2323

.github/workflows/ci-fresh-install.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ jobs:
152152
env:
153153
XLINGS_NON_INTERACTIVE: '1'
154154
run: |
155-
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.27.5
155+
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.30.2
156156
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
157157
158158
- name: Install mcpp and config mirror
@@ -293,7 +293,7 @@ jobs:
293293

294294
- name: Install xlings + mcpp
295295
run: |
296-
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.27.5
296+
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.30.2
297297
# Deliberately NOT writing to $GITHUB_PATH here. On container
298298
# images that declare no PATH in their config (opensuse/
299299
# tumbleweed), appending a single dir to GITHUB_PATH makes the
@@ -364,7 +364,7 @@ jobs:
364364
# (older ones carry minos=15 and refuse to start).
365365
# v0.4.51+: in-process sha256 — this image has no sha256sum
366366
# binary, so pinned fetches failed before it.
367-
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.27.5
367+
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.30.2
368368
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
369369
370370
- name: Install mcpp and config mirror

.github/workflows/ci-linux-e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ jobs:
237237
238238
- name: Bootstrap xlings + released mcpp
239239
run: |
240-
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.27.5
240+
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.30.2
241241
export PATH="$HOME/.xlings/subos/current/bin:$PATH"
242242
xlings update
243243
xlings install mcpp -y -g

.github/workflows/cross-build-test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ jobs:
122122
# release assets were uploaded in a broken state (records present,
123123
# blobs missing → 404 on GET); re-uploaded clean. The stale-INDEX
124124
# half is handled by the marker-clear below.
125-
XLINGS_VERSION: '2026.8.27.5'
125+
XLINGS_VERSION: '2026.8.30.2'
126126
run: |
127127
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
128128
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
@@ -263,7 +263,7 @@ jobs:
263263
- name: Bootstrap mcpp via xlings
264264
env:
265265
XLINGS_NON_INTERACTIVE: '1'
266-
XLINGS_VERSION: '2026.8.27.5'
266+
XLINGS_VERSION: '2026.8.30.2'
267267
run: |
268268
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
269269
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \

.github/workflows/release.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696
# Pin xlings to a known-good version. The upstream install
9797
# script always grabs `latest` (no version override), so we
9898
# download + self-install manually to avoid broken releases.
99-
XLINGS_VERSION: '2026.8.27.5'
99+
XLINGS_VERSION: '2026.8.30.2'
100100
run: |
101101
if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then
102102
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
@@ -289,7 +289,7 @@ jobs:
289289
- name: Bootstrap mcpp via xlings
290290
env:
291291
XLINGS_NON_INTERACTIVE: '1'
292-
XLINGS_VERSION: '2026.8.27.5'
292+
XLINGS_VERSION: '2026.8.30.2'
293293
run: |
294294
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
295295
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
@@ -360,7 +360,7 @@ jobs:
360360
# below are pinned to the same version as XLINGS_VERSION; they are
361361
# NOT interpolated from it, so check_version_pins.sh scans for them
362362
# explicitly (they were absent from the old lock-step comment).
363-
XLA="xlings-2026.8.27.5-linux-aarch64.tar.gz"
363+
XLA="xlings-2026.8.30.2-linux-aarch64.tar.gz"
364364
# NOT fetch_release.sh: this asset is OPTIONAL and the `if` is the
365365
# point — an arch with no prebuilt xlings must fall through quietly,
366366
# while the helper retries a 404 five times before giving up. The one
@@ -369,9 +369,9 @@ jobs:
369369
# cover it.
370370
if curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors \
371371
--connect-timeout 20 --max-time 600 -o "/tmp/$XLA" \
372-
"https://github.com/openxlings/xlings/releases/download/v2026.8.27.5/$XLA"; then
372+
"https://github.com/openxlings/xlings/releases/download/v2026.8.30.2/$XLA"; then
373373
tar -xzf "/tmp/$XLA" -C /tmp
374-
XLBIN=$(find /tmp/xlings-2026.8.27.5-linux-aarch64 -path '*/bin/xlings' -type f | head -1)
374+
XLBIN=$(find /tmp/xlings-2026.8.30.2-linux-aarch64 -path '*/bin/xlings' -type f | head -1)
375375
if [ -n "$XLBIN" ]; then
376376
mkdir -p "$STAGING/$WRAPPER/registry/bin"
377377
cp "$XLBIN" "$STAGING/$WRAPPER/registry/bin/xlings"
@@ -449,7 +449,7 @@ jobs:
449449
- name: Bootstrap mcpp via xlings
450450
env:
451451
XLINGS_NON_INTERACTIVE: '1'
452-
XLINGS_VERSION: '2026.8.27.5'
452+
XLINGS_VERSION: '2026.8.30.2'
453453
run: |
454454
if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then
455455
WORK=$(mktemp -d)
@@ -632,7 +632,7 @@ jobs:
632632
shell: bash
633633
env:
634634
XLINGS_NON_INTERACTIVE: '1'
635-
XLINGS_VERSION: '2026.8.27.5'
635+
XLINGS_VERSION: '2026.8.30.2'
636636
run: |
637637
# Captured before the `cd` below, in POSIX form: this step never
638638
# returns to the workspace, and GITHUB_WORKSPACE is a backslash

src/xlings/xlings.cppm

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,13 @@ namespace pinned {
4646
// actions, which is how CI's sandbox sat on 0.4.30 unnoticed while
4747
// everything else had moved on. Don't reintroduce a hand-maintained list.
4848
//
49-
// ⚠️ 2026.8.27.5 is a FLOOR, not just the current pick. Below 2026.8.27.2
50-
// the bundled xlings takes a subos's runtime binding from a compiled-in
51-
// constant, so a home can declare one glibc and install another the
52-
// moment the index publishes a packaging revision -- and mcpp is the
49+
// ⚠️ THIS IS A FLOOR, not just the current pick, and it has been raised
50+
// twice for reasons that both still hold.
51+
//
52+
// First, at 2026.8.27.5. Below 2026.8.27.2 the bundled xlings takes a
53+
// subos's runtime binding from a compiled-in constant, so a home can
54+
// declare one glibc and install another the moment the index publishes a
55+
// packaging revision -- and mcpp is the
5356
// party that notices, because select_glibc_payload_lib looks up the
5457
// payload directory by the binding's exact version and refuses to fall
5558
// back:
@@ -62,7 +65,24 @@ namespace pinned {
6265
// 2026.8.27.4 and .5, which read the index, stayed consistent. .5 also
6366
// makes the declaration outrank the index during resolution, so it holds
6467
// even when `latest` is not the highest entry in the table.
65-
inline constexpr std::string_view kXlingsVersion = "2026.8.27.5";
68+
//
69+
// Second, at 2026.8.30.2 (mcpp#533). Below it, xlings answered "is this
70+
// package already installed" from the xvm version database keyed on the
71+
// BARE SHORT NAME, so a package skipped its own `install()` whenever any
72+
// other namespace held the same `<name>@<version>` —
73+
// `compat:libdrm@2.4.123` against the
74+
// `xim:libdrm@2.4.123` that Mesa pulls in. The descriptor's tree was never
75+
// built, and mcpp is again the party that notices, four layers later:
76+
//
77+
// /bin/sh: 1: -shared: not found
78+
//
79+
// mcpp now refuses that link unit by name and withholds `.mcpp_ok` from a
80+
// directory holding nothing the package installed, so the failure is
81+
// legible on any client. Only a client at or above this floor INSTALLS
82+
// correctly — which is why this is a floor and not a preference, and why
83+
// an index must still not publish a deliberately colliding
84+
// `<name>@<version>` (see .agents/docs/2026-08-30-cross-repo-fix-plan §1).
85+
inline constexpr std::string_view kXlingsVersion = "2026.8.30.2";
6686
inline constexpr std::string_view kNasmVersion = "3.02";
6787
}
6888

0 commit comments

Comments
 (0)