Skip to content

feat(graphics): one owner for the loader tag, and two things that now say so (2026.8.10.4) - #536

Merged
Sunrisepeak merged 2 commits into
mainfrom
feat/graphics-contract
Aug 10, 2026
Merged

feat(graphics): one owner for the loader tag, and two things that now say so (2026.8.10.4)#536
Sunrisepeak merged 2 commits into
mainfrom
feat/graphics-contract

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Aug 10, 2026

Copy link
Copy Markdown
Member

落地图形栈设计的 E1b / E3a / E3b,建立在 libxpkg 0.0.57(E1a,让 elfpatch 给可执行文件打 DT_RPATH)之上。

rule E —— 把标签不变式放到载荷真正落地的地方

DT_RUNPATH 只对携带它的对象生效;DT_RPATH 对进程内任意深度的 dlopen 都生效。GL 程序要穿三层 dlopen 才够到驱动,所以决定它在不在 GPU 上渲染的是标签,不是路径

真机实测:73 个已安装可执行文件里 1 个 DT_RPATH、68 个 DT_RUNPATH,而那 68 个里有 55 个路径本来就是对的

closure_check 就是为这个动作建的模块 —— 它自己的注释写着:一条正确但"只活在仓库工作流里、用户机器永远看不到"的谓词,应该搬到载荷真正落地的地方。标签此前的处境比那还差:它活在每个 recipe 作者的脑子里;唯一做对的那个包,是它的作者独立发现了问题并在自己包里修好,而没有任何机制把这个发现带给另外 68 个。

标签是原生解析的,不是外部命令 —— 因为没有命令可用:patchelf --print-rpath 打印的是"两个标签里存在的那个"的值,不说是哪个;readelf 不保证载荷里有。

读整个 dynamic section 而不是第一个命中,这点是有分量的:两个标签同时存在时加载器忽略 DT_RPATH,而 DT_RPATH 在前是常见布局 —— 先到先得的读法会在一半样本上给出相反答案,而且在随手测试时看起来是对的。

warn-only,与 rule A/D 一致。库不在范围内:在库上强制传递标签是实测有害的(xim-pkgindex#593),传递性向下也成立。

宿主驱动漂移 —— subos info 现在会说

NVIDIA 用户态是这套栈里唯一不属于我们的部分,它与宿主内核模块锁步,发行版一升级它就在我们脚下换掉,而记录下来的接线描述的是一个已经不在的驱动。

检测器早就存在并且有效(xlings-gl-doctor)—— 它缺的是一条不依赖"用户想起来"的通道。两次普通文件读、无子进程,与接线记录同一个即时查询契约。

报在逐 vendor 行之上,因为它一旦触发,下面每一行说的都是旧驱动。任一侧未知都不算漂移:模块没加载的机器不是"换了驱动",是"没有驱动在跑"。

沙箱缺 --gpu —— 只在能被采取行动时才说

bwrap 重建的 /dev 不含 GPU 节点,所以不带 --gpu 的沙箱按构造就是软件渲染环境。这个缺省是对的,--gpu 也确实能恢复;缺的是沉默 —— 用户拿到"能跑、有画面、exit 0",与 GPU 可用时观感完全相同,只差帧率。

三个条件,窄是要点。 几行之外的 warn_storage_dormant_on_shell_ 就是一条"每次都响"的提示,变成噪音后被注释掉了。这条要求:subos 有 GL dispatch、宿主确实有 GPU 设备节点、且没传 --gpu。GPU 判据由 passthrough_args 派生而不是另立一份设备清单,两者无法漂移

真机验证(每项双向)

沙箱提示   不带 --gpu 时响;带 --gpu 时不响;无图形栈的 home 不响
漂移行     版本一致时无;伪造不一致时有;还原后又无
标签解析器 已证伪 —— 改成读第一个命中,both-tags 测试变红

37/37 测试二进制全绿。

设计:.agents/docs/2026-08-10-graphics-stack-design.md §E1b / §E3a / §E3b
上游:openxlings/libxpkg#41,mcpplibs/mcpp-index#202
关联:#532 #533 #534


追加:E1a 的端到端验证(此前只验了命令构造)

用本 PR 的二进制(内含 libxpkg 0.0.57)真实安装,删掉载荷目录强制重装(仅 remove 会留下载荷,重装是空操作 —— 已知陷阱):

可执行文件 xkbcli  : (RPATH)     ← 新
库 libxkbcommon.so : (RUNPATH)   ← 未变,正是设计要求的分界

新装的 wayland 也是 (RPATH)打包侧的写入者现在是一致的。

诚实标注一处未观察到的行为

rule E 的解析器已双向证伪(合成 ELF:改成读第一个命中,both-tags 用例变红),
但"它在真实安装中发声"这一幕没有观察到 —— 因为 0.0.57 之后正常安装不再产出
DT_RUNPATH 的可执行文件,这个场景无法按需构造(仓库里每个有 bin/ 的包都有 lib/,
所以 elfpatch 总会打标签)。

有一条反向的真实文件交叉验证成立:新装的 wayland / libxkbcommon 可执行文件经
readelf 是 RPATH,而 rule E 用我写的解析器扫同一批文件时保持沉默 —— 解析器若把
RPATH 误读为 RUNPATH,那次安装就会报警。所以真实文件上的一致性在否定方向已验证;
肯定方向缺一个真实样本

rule E 的实际作用面因此是两类:被更旧的 elfpatch 打过标签的载荷(用户升级后重装老包时),
以及自己覆盖标签的 recipe。两者都不是现在能按需制造的。

… say so (2026.8.10.4)

Implements E1b/E3a/E3b of the graphics stack design, on top of libxpkg 0.0.57
which makes elfpatch stamp DT_RPATH on executables (E1a).

RULE E — the tag invariant, evaluated where the payload lands

DT_RUNPATH is consulted only for the object carrying it; DT_RPATH is consulted
for every dlopen anywhere in the process. A GL program reaches its driver
through three levels of dlopen, so the TAG — not the path — decides whether it
renders on the GPU. Measured on a real home: 1 of 73 installed executables
carried DT_RPATH, 68 carried DT_RUNPATH, and 55 of those 68 already carried
the correct path.

closure_check is the right place and it was built for exactly this move. Its
own header says a predicate that is right but "runs in exactly one place — a
repository workflow the user's machine never sees" belongs where the payload
actually lands. The tag was in a worse place than that: it lived in each
recipe author's head, and the one package whose author found the problem fixed
it locally with nothing to carry the finding to the other 68.

The tag is parsed natively rather than shelled out, because there is nothing
to shell out to: `patchelf --print-rpath` prints the value of whichever tag
exists and does not say which, and readelf is not something a payload is
guaranteed to have. Reading the whole dynamic section rather than the first
hit matters — with both tags present the loader IGNORES DT_RPATH, and
DT_RPATH-first is the common layout, so a first-hit reading would report the
opposite and look right in casual testing.

Warn-only, matching rule A and D. Libraries are deliberately out of scope:
forcing the transitive tag on a LIBRARY is measured harmful
(xim-pkgindex#593) because transitivity runs downward too.

HOST DRIVER DRIFT — `subos info` now says it

The NVIDIA userspace driver is the one part of this stack we do not own; it is
in lockstep with the host kernel module, so a distribution update moves it
under us and the recorded wiring describes a driver that is gone. The
detector already existed and worked (`xlings-gl-doctor`) — what it lacked was
a way to reach the user without being remembered. Two plain file reads, no
subprocess, same instant-query contract as the wiring record. Reported ABOVE
the per-vendor rows, because when it fires every row under it is about the old
driver. An unknown on either side is not drift: a machine whose module is not
loaded has not changed driver.

SANDBOX WITHOUT --gpu — say it once, only where it can be acted on

bwrap's fresh /dev excludes the GPU nodes, so `--sandbox` without `--gpu` is a
software-rendering environment by construction. That default is correct and
`--gpu` genuinely restores it; the gap is silence — the user gets "runs, draws,
exits 0", indistinguishable from the GPU case except in frame rate.

Three conditions, and the narrowness is the point: `warn_storage_dormant_on_
shell_` a few lines away is a hint that fired on every entry of its kind,
became noise, and is commented out today. This one requires that the subos has
a GL dispatch, that the host actually has GPU device nodes, and that --gpu was
not passed. The GPU predicate is derived from `passthrough_args` rather than a
second list of device paths, so the two cannot drift.

Verified on real hardware, each in both directions:

  sandbox hint      fires without --gpu; silent with --gpu; silent on a home
                    with no graphics stack
  drift row         absent when versions agree, present when they disagree,
                    absent again after restoring
  tag parser        falsified — reading the first hit instead of the whole
                    dynamic section makes the both-tags test fail

37/37 test binaries pass. Design:
.agents/docs/2026-08-10-graphics-stack-design.md §E1b, §E3a, §E3b.
…lready exists

The gap I flagged in this PR's own description: rule E's parser was falsified
against synthetic ELFs, but nothing had watched it fire during an actual
install — and that case cannot be produced by installing anything today,
because since libxpkg 0.0.57 the writer is consistent and every package with a
`bin/` also has a `lib/`, so elfpatch always stamps DT_RPATH.

closure_guard_differential already builds exactly the right rig for it: a real
gcc-compiled executable, given PT_INTERP into a payload glibc so it is form X,
carried into a payload by a fixture recipe and installed for real. One
`patchelf --set-rpath` WITHOUT `--force-rpath` — which is precisely what
elfpatch wrote before 0.0.57 — turns it into a payload arriving from an older
client, which is the case rule E exists to catch.

Two assertions, because the second is the one that decides whether the message
is useful. The path in a DT_RUNPATH executable is usually correct, so a
warning that only named the tag would read as pedantry rather than as the
reason a GL program renders in software; 4b requires the message to say what
it costs.

The rig asserts its own shape before relying on it (`readelf` must show
RUNPATH), so a future patchelf that writes something else fails loudly instead
of making 4b vacuous.

Falsified: forcing the rig to DT_RPATH makes 4b fail, and restoring it passes.
@Sunrisepeak
Sunrisepeak merged commit cadcf77 into main Aug 10, 2026
8 checks passed
Sunrisepeak added a commit to openxlings/xim-pkgindex that referenced this pull request Aug 10, 2026
The loader tag now has one owner. elfpatch (libxpkg 0.0.57) stamps DT_RPATH on
executables instead of DT_RUNPATH, and closure_check gains rule E to say so at
install time on the user's machine when a payload arrives with the old tag.

DT_RUNPATH is consulted only for the object carrying it; DT_RPATH is consulted
for every dlopen anywhere in the process. A GL program reaches its driver
through three levels of dlopen, so the tag — not the path — decided whether it
rendered on the GPU. Of 73 installed executables on a real home, 1 carried
DT_RPATH and 55 of the other 68 already carried the correct path.

Also: `subos info` reports host driver drift (the detector existed as
`xlings-gl-doctor` and lacked a channel), and `subos use --sandbox` without
`--gpu` says the sandbox exposes no GPU — under three conditions, so it can
only fire where acting on it changes the outcome.

All THREE platform sections, verified by PARSING rather than reading the diff:

  linux    latest=2026.8.10.4  arch=[aarch64,x86_64]
  macosx   latest=2026.8.10.4  arch=[aarch64]
  windows  latest=2026.8.10.4  arch=[x86_64]

Hashes taken from the assets in xlings-res — what `XLINGS_RES` actually
resolves to — not from the upstream release they were mirrored from.

CN mirror uploaded from a local shell and verified by SIZE on all four
platforms; before the upload all four returned 127 bytes, so the status code
would have said 200 for assets that were not there.

Upstream: openxlings/xlings#536, openxlings/libxpkg#41, mcpplibs/mcpp-index#202

Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant