feat(xim): one resolution, referenced everywhere (2026.8.5.3) - #485
Merged
Conversation
"Which version is this dependency?" had four independent answers. They agreed
for as long as the index shipped one glibc; the second one turned the
disagreement into binaries that fault before `main` with
undefined symbol: __pointer_chk_guard, version GLIBC_PRIVATE
naming neither a package nor a version, because ld.so and libc.so.6 are two
halves of one build and GLIBC_PRIVATE is the ABI between them. Both directions
were reproducible: the resolver preferring an already-active 2.39 while a scan
took 2.44, and a transaction that installed both.
What authorised four answers was one sentence — deps_exports' contract said a
missing entry means "this dep declared nothing, fall back to convention". This
changes that contract to "missing is impossible".
* resolved_deps is TOTAL. Every runtime dep is recorded with the version the
resolver settled on, the payload directory, the libdirs, and WHY that
version. The install_dir was already being computed and discarded by a
`break` for deps that declared no exports; the break moved.
* the {lib64, lib} convention is applied by the WRITER. libxpkg 0.0.50
deletes the consumer-side re-derivation that was the second answerer.
* elfcheck asserts, after elfpatch has written, that a provider's
interpreter and its libdir come from one payload — the invariant, checked
on what shipped rather than on what was intended. Install aborts naming
both paths, instead of the user meeting a GLIBC_PRIVATE symbol later.
* `.xlings-resolution.json` next to each payload, and `xlings why <pkg>
[dep]` to read it back. A decision that has to be reproduced to be
inspected is not traceable, and reproducing this one means recreating a
store state — the thing that varies.
* doctor gains LoaderLibcSplit over existing payloads, counted toward the
exit code. It shares elfcheck::scan_payload with the installer rather than
reimplementing the rule: report and repair have drifted three times here,
and it always looks the same from outside — doctor keeps reporting what
--fix says it fixed.
Also lands `subos new --runtime <pkg>@<ver>` actually installing what it
declares. Recording a runtime and leaving the subos empty let the first
package to arrive decide the real one, so a subos declaring 2.39 ended up on
2.44 and the flag described an intention it did not hold. Only when asked:
without --runtime, `subos new` stays a local directory operation.
Tests: nine unit cases over payload_of/provider_of and the six edge cases of
the assertion (shared libraries and static binaries skip, absent provider
passes, repeated provider passes on any same-source entry, $ORIGIN and
non-store paths are not payloads); E2E-62 covers A1 and A2 with a two-version
fixture and asserts the record is written with its source field.
Design and the full acceptance list:
.agents/docs/2026-08-05-dependency-resolution-single-source.md
The key hashes mcpp.toml, so bumping libxpkg to 0.0.50 missed it exactly -- and `restore-keys` then fell back to the newest v2 entry, whose registry carries the mcpp-index snapshot from before the bump. Three build-and-test jobs reported `mcpplibs.xpkg@0.0.50 not found` while a clean home resolved it without trouble, which is the shape a stale cache always takes: the failure describes the package, not the cache. Same remedy the v1 -> v2 retirement used, and for the same reason -- an inexact restore cannot be prevented by the exact key, only by moving the prefix out from under it.
The reference is generated from the binary's own help, and the contract script compares the two. Adding a command without regenerating fails that comparison — which is the check working: the reference is documentation that cannot silently fall behind the thing it documents.
Every workflow resolved mcpp's dependencies out of whatever index snapshot the bootstrap xlings shipped with, and never refreshed it. A freshly published `mcpplibs.xpkg@0.0.50` was reported "not found" in the same run that downloaded `mcpplibs:tinyhttps@0.2.9` from the same index without trouble — older entries were there, the new one was not. The failure names the package, so it reads as an unpublished dependency. It took a clean home resolving the same version without difficulty to place it: the index was fine, the snapshot was old, and nothing in the pipeline had a reason to notice. `|| true` on POSIX and a LASTEXITCODE reset on Windows: a refresh that cannot reach the network must not fail a run whose dependencies are already cached. This is a freshness step, not a gate.
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.
"Which version is this dependency?" had four independent answers. They agreed while the index shipped one glibc; the second one turned the disagreement into binaries that fault before
mainwithundefined symbol: __pointer_chk_guard, version GLIBC_PRIVATE— naming neither package nor version, because ld.so and libc.so.6 are two halves of one build.Both directions were reproducible, and both are now regression tests (E2E-62).
break..xlings-resolution.json+xlings why— the decision as data. A decision that must be reproduced to be inspected is not traceable, and reproducing this one means recreating a store state.LoaderLibcSplitover existing payloads, counted toward the exit code, sharing one implementation with the installer.Also:
subos new --runtime <pkg>@<ver>now installs what it declares. Recording it and leaving the subos empty let the first package to arrive decide the real runtime.Design and the acceptance list:
.agents/docs/2026-08-05-dependency-resolution-single-source.md