docs(design): sysroot / bin / lib / files multi-version model - #409
Merged
Conversation
0.4.70 made `xlings use` switch a whole toolchain release. It did that for
programs. Headers and libraries are not actually managed by the same model:
`VData::libdir` has no writer at all, so `use` is a no-op for libraries, and
headers are not in the model, so the index grew seven ways of writing the
sysroot with two contradictory conflict policies.
The design collapses assets to two kinds -- `program` (xlings resolves at
exec time) and `files` (someone else resolves by path) -- collapses three
materialization code paths to one, and narrows `config()` to pure
declaration. Every claim in it is anchored to a code location or a
measurement from a real installation; the appendix lists both.
What it concludes is not "build this". Section 9.4 splits the work into four
stages and argues only the first two are justified today:
stage 0 doctor stops reporting 31 phantom anchors as broken payloads;
libdir written or its dead code removed; an E2E proving
provider-scoped removal replaces hand-written `xvm.remove`
stage 1 spec 3 gate, `type = "files"`, install stops materializing,
expansion computed at materialize time
stage 2 a per-payload manifest -- only once recipe drift is shown to
cause imprecise removal in practice
stage 3 a `use()` hook -- only once stale gcc/llvm configs are shown to
hurt; that is two recipes, not a class
stage 4 generation trees -- only if deep merge turns out to be required
Stages 0 and 1 fix every user-visible problem we found. The other three each
address a problem that has not yet been shown to exist, and the doc says so
rather than scheduling them.
It also records the honest counter-position (section 9.3): no official recipe
declares a header op, and only four packages populate the sysroot, so if
multi-version headers are not a real need, fixing the specific bugs is the
right answer instead. That judgement is the reviewer's, and it decides
whether the rest of the document is worth anything.
Does not affect 0.4.70 -- none of the problems it describes were introduced
there, and nothing in it ships in this release.
3 tasks
The document said 31. That was a script's count of program-typed entries with no same-named executable in the payload root -- not what `self doctor` reports. doctor resolves through `resolve_executable`, which searches `bin/` as well, so most of those 31 resolve fine and were never reported. Measured on the same 372-entry installation: doctor reports 9 broken payloads, 2 of which are release anchors (`binutils@2.42`, `cairo@1.18.0`). The fix is worth making and is already made; the number was wrong.
This was referenced Jul 26, 2026
Open
Records the ordering constraint that came out of implementation: xlings ships first, package migration follows. The index cannot adopt the new declaration until libxpkg publishes it, mcpp-index carries it, and a released xlings understands it -- migrating first would leave recipes that the shipped xlings cannot read. Also states what the layering buys: a stall in migration does not hold back the fixes users are already waiting for.
Release identity becomes compound: `(0.4.70) 2026.07.27.0`. The semantic version stays the machine-readable one -- `self update` compares it, and both indexes key entries on it, so replacing it with a date would leave already-released clients unable to decide whether an upgrade exists. The date is the human-facing label. Also expands T3 into the seven steps the publish chain actually takes, including the one that is easy to miss: mcpp-index entries carry both a GLOBAL and a CN URL, so a GitHub-only release breaks resolution for CN users.
The document first kept the semantic version as the machine-readable one and made the date a display label, on the assumption that an already-released client could not compare a date against semver. Checking rather than assuming: `self update` expands to `install xlings@latest` plus `use xlings latest`, and the latter sorts through `version_key_greater` (db.cppm:247), which splits on '.' and compares each component numerically. [2026,7,27,0] against [0,4,68] decides on the first component, so a date version is greater than every 0.x by construction, and dates order correctly among themselves. So the concern was wrong and `x.y.z` is retired outright. Months and days carry no leading zero -- the comparator parses "07" and "7" identically, and dropping the zero keeps string equality and numeric equality from disagreeing about which key names a version.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
设计文档,不含代码,不影响 0.4.70 行为。承接 #408 的讨论。
.agents/docs/2026-07-27-sysroot-files-model-design.md它解决的问题
0.4.70 让
xlings use整组切换 —— 但只对程序成立:VData::libdir无任何写入者,install_libs()零调用点 →use是 no-op可观察后果(openssl 装两个版本):装完就是头 3.1.5 / 库 3.2.0,且两个方向的
use都修不回来,还都报成功。架构
program(xlings 在 exec 时解析)/files(别人按路径查找,库是它的一种)use物化。active门禁这个概念随之消失config()收窄成纯声明 —— 查环境的能力移走,"纯函数"从要求变成结构上做不到别的rename原子替换(不做差集)但结论不是"把这些都做了"
§9.4 分四阶段,只有前两段是今天有依据的:
libdir写入或删死代码;E2E 证明 provider-scoped 卸载可替代手写xvm.removetype="files"+ install 不物化 + 展开在物化时现算use()hook +use_deps后三段各自解决一个尚未被证明存在的问题。
也写了反方案(§9.3)
没有任何官方 recipe 声明过 header op,4 个铺 sysroot 的走的都是 Lua 路径。受影响的只有"同一个包装 ≥2 版本且提供头/库"——官方索引里 4 个包。31 个 doctor 假警报可以单独修。
如果多版本头文件不是真实需求,"只修具体 bug"就是正确答案。 这个判断是评审者的,它决定整份文档值不值。
迁移
spec = "3"逐包选择加入 ——spec = "2"(arch fail-closed 门禁)已是成功先例,两代并存运转正常事实来源
每条论断都锚定到代码位置或真实安装的实测数据(附录列全)。实测包括:
~/.xlings.json107.6 KB / 372 条目、payload 顶层扇出分布(glibc 130、大多数 1–2)、31 个假警报的分类统计。顺带记录一个既有热路径问题:
shim.cppm:347每次 dispatch 解析整个版本库,无缓存。尝试量化时list --all卡在索引刷新,所以只有代码事实,没有数字 —— 建议单独立项。Review 重点
§10 列了 7 条,第 1 条最关键:多版本头文件/库是不是真实需求? 若否,§9.3 就是答案。