fix: #278 package identity convergence — index side + dependency side (0.0.105)#279
Merged
Merged
Conversation
Design/proposal doc for entering the embedded Linux ecosystem, restructured as decisions-first (with rationale) then supporting detail. Positioning: mcpp brings its own matched-libc cross compiler (latest GCC) and consumes an external device sysroot — it is NOT a distro builder and never adapts per-vendor SDK. The single core change is opening the sysroot seam (L2); the CLibMode::Sysroot mechanism and the hermetic allow-list already accept tc.sysroot, so it's a minimal insertion. pkg-config and qemu cross test-run are xlings provisioning + thin wiring. Locks the maintainer decision register (16 decisions + rationale), incl.: - C++ source-only; binary interop C-ABI only + wrapper; vendor C++-only libs via a user-built C-bridge .so (built in vendor ABI, pure-C boundary) - glibc baseline pinned low when building payloads (GCC version x glibc decoupled); payloads use the latest GCC (16), GCC 15 is only the import-std capability floor - dropped: L4 backend mode, sysroot pinning/mgmt, .pc synthesis, and the "compiler doesn't support C++23" diagnostic (config II makes that case architecturally impossible) Beachhead: Raspberry Pi aarch64. Net work: P0 sysroot seam + matched-libc low-glibc GCC 16 payloads (+ one glibc-floor validation); P1 pkg-config + qemu test-run. Supersedes the earlier issue-276 analysis note (renamed to a proper design doc).
… (0.0.105)
mcpp-index changed `chriskohlhoff.asio`'s `name` from "chriskohlhoff.asio" to
"asio" (namespace untouched). Lint went green; all three platform workspace
jobs died after 20-58 minutes with E_NOT_FOUND. The descriptor parsed, passed
mcpp's own identity gate, and no consumer spelling could install it.
Root cause is a split in how package identity is spoken on the two sides:
index side — identity normalization treats (ns="a", name="b") and
(ns="a", name="a.b") as equivalent, while install-target
construction hard-assumes the latter. The index is a FLAT key
space keyed by the LITERAL package.name (libxpkg: build_index
is called with no namespace, lookup is exact entries.find),
so the two never meet.
dependency side — the bare-name candidate ladder's discovery rung was
specified as "match by name across the precedence path" but
implemented as "try two more filenames", and a total miss fell
through to candidates.front() SILENTLY, so mcpp continued with
a namespace it had invented.
Both contracts existed only as prose comments. They are now predicates.
INV-NAME (index side): package.name must BE the fully-qualified name whenever
package.namespace is declared. One predicate, two call sites — `mcpp xpkg
parse` (index CI, seconds) and the install path (catches descriptors that
never passed through lint, zero extra I/O since the descriptor is already in
memory). The predicate is deliberately narrow: written as the general
"literal != derived fqname" comparison it would flag the working compat-alias
path and break every bare dependency. CompatAliasIsClean locks that.
INV-RESOLVE (dependency side): a bare name resolves in exactly three places —
mcpplibs, compat, and no-namespace upstream packages. Everything else must be
written out. Global short-name search is rejected: it makes resolution depend
on which indices happen to be present, so adding an index could silently
retarget an existing dependency.
BREAKING: bare names no longer reach third-party namespaces. The index-wide
scan survives only as a did-you-mean on the already-failed path — result goes
into error text, never back into resolution.
Also fixes the generator that produced these descriptors: `mcpp emit xpkg`
wrote a bare name and no namespace at all, so filing a package into a
namespaced index meant hand-adding `namespace = "<org>"` — and that edit is
what created the split form. aimol.tensorvia-cpu was born exactly this way.
Prescribed in 2026-06-26 design §4.5; never landed until now.
Design: .agents/docs/2026-07-25-issue278-descriptor-name-form-canonicalization-design.md
Fixes #278
A custom git index is cloned by xlings during install, so at candidate- selection time its descriptors may legitimately not be on disk yet. "Not found" is not conclusive there, and turning it into a hard error would reject a package that materializes a moment later. Builtin and local path indices are both readable at selection time, so they keep the strict rule.
mcpp.toml and src/toolchain/fingerprint.cppm are two independent version sources; bumping only the manifest left `mcpp --version` reporting the old number, which 01_help_and_version.sh cross-checks against mcpp.toml.
…ation-time corrections
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.
Fixes #278
The incident
mcpp-index changed
chriskohlhoff.asio'snamefrom"chriskohlhoff.asio"to"asio"(namespace untouched). Lint went green; all three platform workspace jobs died after 20–58 minutes withE_NOT_FOUND. The descriptor parsed, passed mcpp's own identity gate, and no consumer spelling could install it.Root cause — one split, two sides
Index side. Identity normalization treats
(ns="a", name="b")and(ns="a", name="a.b")as equivalent; install-target construction hard-assumes the latter. Verified against libxpkg:build_indexis called with no namespace, so the index is a flat key space keyed by the literalpackage.name, looked up with exactentries.find(). mcpp addresses packages as<ns>.<short>. The two never meet.Dependency side. The bare-name ladder's discovery rung was specified as "match by name across the precedence path" but implemented as "try two more filenames" — and a total miss fell through to
candidates.front()silently, so mcpp continued with a namespace it had invented and the user met the failure much later, wrapped around that invented name.Both contracts existed only as prose comments (
prepare.cppm:1714,:1456, and the gate's "the caller derives the namespace"). They are now predicates.What this changes
INV-NAME (index side) —
package.namemust BE the fully-qualified name wheneverpackage.namespaceis declared. One predicate, two call sites:mcpp xpkg parse(index CI, seconds) and the install path (catches descriptors that never passed lint; zero extra I/O — the descriptor is already in memory). Lint and runtime cannot drift.The predicate is deliberately narrow. Written as the general "literal name != derived fqname" comparison it would flag the working compat-alias path — a bare
gtestrequest derivesgtestwhile the literal iscompat.gtest— and break every bare dependency.CompatAliasIsCleanlocks that.INV-RESOLVE (dependency side) — a bare name resolves in exactly three places:
mcpplibs,compat, no-namespace upstream. Everything else must be written out.Global short-name search was considered and rejected: it makes resolution depend on which indices happen to be present, so adding an index could silently retarget an existing dependency; same-short-name collisions would be settled by an index ordering that has no total order across user
[indices]. Reproducibility beats convenience.The index-wide scan survives only as a did-you-mean on the already-failed path — result goes into error text, never back into resolution (three constraints documented at
Fetcher::scan_fqns_with_short_name).Generator fix —
mcpp emit xpkgwrote a bare name and no namespace at all, so filing a package into a namespaced index meant hand-addingnamespace = "<org>", and that edit is what created the split form.aimol.tensorvia-cpuwas born exactly this way (still carries the "AUTO-GENERATED, do not edit by hand" banner). Prescribed in the 2026-06-26 design §4.5; never landed until now.Bare names no longer reach third-party namespaces. Migration needs no docs — the failure prints the two lines to write:
Verified: the suggested spelling downloads and compiles asio end-to-end.
Scope correction found during implementation
The design's "2 violations in 62 descriptors" figure covered only the mcpplibs index. Running the predicate over the full registry (200+) surfaced 30 split-form descriptors — and all 28 extra ones are legitimate: in xlings-native indices (
xim-pkgindex,-scode)package.namespaceis an install-dir category (config,scode,awesome), the index is keyed by the bare name, and the split spelling is correct there. All 30 lack anmcppsegment and never reach mcpp's dependency path.Hence
mcpp xpkg parse --allow-split-namefor xlings-native trees. No xim repo runsmcpp xpkg parsetoday (checked their.github/), and mcpp-index's CI does — so enforce-by-default is right.Verification
XpkgNameFormcases incl. theCompatAliasIsCleanregression lock; 37/37 unit binaries green.--jsoncarries it,--allow-split-nameopts out, runtime fail-fast fires before any download.gtest→compat.gteststill works.gtestbuilds;"chriskohlhoff.asio"downloads + compiles.Ecosystem
mcpp-index already carries both fixes upstream (
chriskohlhoff.asioandaimol.tensorvia-cpuare FQN; #116'scheck_package_name.lualanded) — that guard is now redundant withmcpp xpkg parsebut harmless.Design:
.agents/docs/2026-07-25-issue278-descriptor-name-form-canonicalization-design.mdPlan:
.agents/docs/2026-07-25-issue278-implementation-plan.md