feat: SPEC-001 package identity — name is one segment, wire key is the literal (0.0.106)#280
Merged
Merged
Conversation
…e literal (0.0.106) 0.0.105 fixed #278 by REQUIRING `package.name` to be the fully-qualified `<namespace>.<name>`. That rule was an encoding constraint dressed up as a design rule. Its only cause: mcpp threw away the literal `package.name` it had already read and re-rendered `<ns>.<short>` to address the package, so the two only matched when the descriptor repeated its namespace inside `name`. Use the literal instead and the constraint disappears. The canonical form goes back to what the identity model always said: `namespace` carries the hierarchy, `name` is a single atomic segment. Paired with xlings 0.4.69 (openxlings/xlings#381), which keys its index by (namespace, name) so two packages sharing a short name in ONE index are both addressable. mcpp's part is sending `<namespace>:<literal name>` rather than a reconstructed string. Three subtractions, one addition: - identity normalization no longer splits on the last dot. It used to infer a namespace nobody declared — `ns="a"` + `name="a.b.c"` silently became `(a.b, c)`. Identity is now exactly the two declared fields; a leftover dot is rejected rather than reinterpreted. - the install target is the descriptor's literal `package.name`, prefixed with the package NAMESPACE (xlings' effective namespace), not the index name. Namespace-less upstream packages keep their bare name. - the store dir formula `{ns}-x-{name}` is first-class for both spellings instead of buried among six guesses. - discovery no longer stops at a fixed candidate-filename list. Recommended names stay the fast path; when they all miss, mcpp scans by declared identity. This finally delivers the "filename is not a key" half that identity-first resolution only ever promised — verification was implemented, discovery was not. Compatibility: the legacy fully-qualified spelling is still accepted (the prefix is stripped before judging), so every published descriptor keeps working unchanged. A full-registry sweep — 245 descriptors, mcpp indices and xlings-native ones alike — reports zero form violations. Notably this includes all 30 descriptors that needed `--allow-split-name` under 0.0.105; that flag is now obsolete and kept accepted only so 0.0.105-era index CI keeps running. Adds docs/spec/ for normative documents, with SPEC-001 covering identity, the four [dependencies] spellings and their candidate ladders, the matching pipeline, derived-value formulas and worked examples — each rule tagged with its implementation status. Verified: 37/37 unit binaries; e2e 161 inverted; new e2e 163 covers short-name install, legacy FQN install, arbitrary filename discovery, and two same-short-name packages in one index resolving to alpha-x-widget / beta-x-widget. Spec: docs/spec/package-identity.md Plan: .agents/docs/2026-07-25-spec001-implementation-plan.md
…xlings 0.4.69 Two CI failures from PR #280, both real and both worth fixing rather than working around. 1. Windows e2e ran the PREVIOUS release's binary. `MCPP_SELF=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1)` `target/` is restored from cache and keeps one directory per build fingerprint. A version bump changes the fingerprint, so the freshly built 0.0.106 binary landed next to the cached 0.0.105 one and `head -1` returned whichever the directory walk hit first — hence `Version mismatch: mcpp.toml=0.0.106, --version='mcpp 0.0.105'`. Latent all along; the version bump is just what made two candidates exist. The Linux workflows already sort by mtime and take the newest — this brings the five Windows/release sites in line with them. 2. e2e 163 step 4 asserted a capability the sandbox cannot have yet. That step covers two same-short-name packages in ONE index, which needs xlings >= 0.4.69 (openxlings/xlings#381). The sandbox xlings comes from bootstrapping the PREVIOUS mcpp release, so CI runs 0.4.68 until 0.0.106 ships bundling 0.4.69 — a genuine chicken-and-egg, not a defect. Step 4 now detects the sandbox xlings version and skips with a stated reason when it is older. Properties 1-3 (short-name install, legacy FQN install, arbitrary-filename discovery) are what this change is responsible for and stay asserted unconditionally. Verified both branches locally by swapping the sandbox xlings: 0.4.69 runs step 4, 0.4.68 skips it with the reason printed.
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.
Why
0.0.105 fixed #278 by requiring
package.nameto be the fully-qualified<namespace>.<name>. That rule was an encoding constraint dressed up as a design rule.Its only cause: mcpp threw away the literal
package.nameit had already read, and re-rendered<ns>.<short>to address the package. The two only matched when the descriptor repeated its namespace insidename.Use the literal instead and the constraint disappears — the canonical form goes back to what the identity model always said:
namespacecarries the hierarchy,nameis a single atomic segment.Paired with xlings 0.4.69 (openxlings/xlings#381), which keys its index by
(namespace, name)so two packages sharing a short name in ONE index are both addressable. mcpp's part is sending<namespace>:<literal name>rather than a reconstructed string.What changed — three subtractions, one addition
Identity normalization no longer splits on the last dot. It used to infer a namespace nobody declared:
ns="a"+name="a.b.c"silently became(a.b, c). Identity is now exactly the two declared fields; a leftover dot is rejected rather than reinterpreted.The install target is the literal
package.name, prefixed with the package namespace (xlings' effective namespace) — not the index name. That prefix is what disambiguates two same-short-name packages in one index. Namespace-less upstream packages keep their bare name, no prefix.The store dir formula
{ns}-x-{name}is first-class for both spellings instead of buried among six guesses.Discovery no longer stops at a fixed candidate-filename list. Recommended names stay the fast path; when they all miss, mcpp scans by declared identity. This finally delivers the "filename is not a key" half that identity-first resolution only ever promised — verification was implemented, discovery was not. Conforming indices pay zero scan cost.
Compatibility
The legacy fully-qualified spelling is still accepted (the prefix is stripped before judging), so every published descriptor keeps working unchanged.
A full-registry sweep — 245 descriptors, mcpp indices and xlings-native ones alike — reports zero form violations. Notably that includes all 30 descriptors that needed
--allow-split-nameunder 0.0.105: the short-name rule is what the wider ecosystem already does, and 0.0.105's FQN requirement was the odd one out. That flag is now obsolete, kept accepted only so 0.0.105-era index CI keeps running.E_NOT_FOUNDOnly one broken cell, so indices migrate package by package; an index adopting short names raises its
min_mcppto 0.0.106.New:
docs/spec/A home for normative documents — semantics, constraints, matching rules — distinct from usage docs (
docs/*.md) and per-change design docs (.agents/docs/*.md). Each rule carries an implementation-status tag, so it doubles as "can I write this today?".SPEC-001 covers identity, the four
[dependencies]spellings and their candidate ladders, the full matching pipeline, derived-value formulas, and worked end-to-end examples.Verification
XpkgNameForm+CanonicalIdentitycases rewritten for the new semantics.acme-x-widget; legacy FQN install →acme-x-acme.widget; descriptor atpkgs/z/totally-unrelated-name.luastill discovered; two same-short-name packages in ONE index installing toalpha-x-widget/beta-x-widget.xpkg parsesweep: 231 pass / 0 violations; the 14 non-zero exits are byte-identical on 0.0.104 (pre-existing, mostly xlings' own test fixtures).kXlingsVersion,release.yml,ci-linux-e2e.yml,cross-build-test.yml.Spec:
docs/spec/package-identity.mdPlan:
.agents/docs/2026-07-25-spec001-implementation-plan.md