docs: contract admission design (index + package floor) + pin fresh-install mcpp to 0.0.102#268
Merged
Merged
Conversation
… pin fresh-install mcpp
Design only — no engine changes.
The contract mechanism ("is this index/descriptor newer than I can
trust?") is specified as two levels: the existing index.toml floor, and
a future `mcpp = { min_mcpp = ... }` descriptor floor. The document
fixes the shape both must share:
- contract evaluation splits into pure predicate / idempotent decision /
the one stateful reporter — fusing them makes the decision itself
non-idempotent
- the contract is a candidate-set filter, not a check on the read path
- I7: a contract miss must never be a reason to try another candidate.
Only at the source layer (index trees, interchangeable) does it show
up as filtering; once identity is fixed, it is terminal for that entity
- a refused index is excluded, never fatal — a too-new private index
must not take down `mcpp toolchain install` or the upgrade path
- the package-level key must enter the client vocabulary BEFORE any
index uses it: unknown mcpp-segment keys are skipped today, so an
early rollout would be silently ignored by exactly the clients it
addresses
#265 is filed as the empirical input (appendix), not as a defect to fix
separately: it is only observable in the out-of-contract state this
mechanism redefines, and the red CI was a version skew.
CI: ci-fresh-install now installs an explicit `mcpp@${MCPP_PIN}` (0.0.102)
instead of "newest in the runner's index copy". On 2026-07-21 the
wait-index guard reported "index tracks 0.0.102" and the jobs installed
0.0.100 ten seconds later — the guard polls raw.githubusercontent.com
while the runner resolves through its own index copy. Pinning turns a
silent downgrade into an explicit `version not found`. Bump with the
.xlings.json workspace pin at release. ci-aarch64-fresh-install stays
unpinned by design (it simulates a brand-new user).
…x job Critical path was max(ci-windows 20.4m, ci-linux 18.2m) on a warm PR run. Both were single sequential jobs; everything below is wall-clock, not work. - .github/actions/bootstrap-mcpp: composite action for the cache lineage (mcpp sandbox + xlings + target/) and the xlings bootstrap, so the split jobs share ONE definition instead of a 40-line copy-pasted preamble each. Target cache is now keyed per job — the toolchain legs `clean` and rebuild, so a shared key had them clobbering each other's lineage. - .github/actions/setup-macos-llvm: same idea for the macOS-specific setup (xlings LLVM + sandbox wired to that exact package). - ci-linux.yml: one job -> four independent jobs (build+unit, cold gcc self-host, musl+llvm, xlings integration). No `needs:` — each pays one warm `mcpp build` (~2.5m), which is cheaper than serialising behind an artifact. Dropped the duplicate `mcpp test` in the gcc leg: same suite, same toolchain, same driver binary as build-test, differing only in incremental state. ~18m -> ~7-8m. - ci-windows.yml: e2e moved out (9.7m of 20.4m); remainder split into build+test+package and toolchains+regressions. Integration keeps its original position before the llvm rebuild that invalidates $MCPP_SELF. ~20m -> ~8m. - ci-windows-e2e.yml, ci-macos-e2e.yml: new, mirroring ci-linux-e2e.yml. macOS is not sharded — 3.5m is under this workflow's setup+build floor. - ci-macos.yml: e2e step removed, setup replaced by the composite; the clang probe/module validation steps stay here. - run_all.sh: E2E_SHARD="<index>/<total>" runs a round-robin slice. Round robin rather than contiguous ranges because per-test durations are wildly uneven (the existing timing report exists for exactly that reason). The slice is computed on the full file list before capability filtering, so a test's shard does not move with host capabilities. Linux and Windows e2e run 2 shards; 147 tests split 74/73. Expected critical path: ~20.4m -> ~8m.
Sunrisepeak
force-pushed
the
docs/contract-admission-design
branch
from
July 22, 2026 09:38
a07cb40 to
9cd0cfe
Compare
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.
Summary
Design document only — no engine changes. Plus one CI fix.
.agents/docs/2026-07-22-contract-admission-design.mdspecifies the shape the index→client version contract should have, covering both the existing index-level floor (index.toml min_mcpp) and the future descriptor-level one (mcpp = { min_mcpp = ... }).Key positions:
optional<string>(today'scheck_index_floor) makes the decision non-idempotent — the dedup set silently turns the second and later calls into "no violation".mcpp toolchain installor the upgrade path.mcpp index update, which cannot fix it.mcpp-segment keys are skipped today (xpkg.cppm:1519-1528), so if an index adoptsmin_mcppbefore clients know the key, it is silently ignored by exactly the clients it addresses. Client support must ship and propagate first.#265 is filed as the empirical input (appendix §6), not as a defect fixed here. It is only observable in the out-of-contract state ("client older than index") that this mechanism redefines, and the red CI was a version skew. The residual — an out-of-contract client silently using descriptors it cannot read on the dependency path — is recorded and gets removed with the mechanism.
CI change
ci-fresh-installnow installs an explicitmcpp@${MCPP_PIN}(workflow-level env,0.0.102) at all four install sites instead of "newest in the runner's index copy".Why: in run 29873685262 the
wait-indexguard reportedindex tracks 0.0.102at 22:30:02 and the jobs installedxim:mcpp@0.0.100ten seconds later — the guard pollsraw.githubusercontent.comwhile the runner resolves through its own index copy, so a green guard does not mean the version is installable. That 0.0.100 then met an index whose floor was 0.0.101, which is how #265 surfaced. Pinning turns a silent downgrade into an explicitversion not found.Bump
MCPP_PINtogether with the.xlings.jsonworkspace pin at each release.ci-aarch64-fresh-installis deliberately left unpinned — its stated purpose is to simulate a brand-new user running barexlings install mcpp.Test plan
env.MCPP_PINvisible to all five jobs (bash${MCPP_PIN}×3, pwsh$env:MCPP_PIN×1)ci-fresh-installon the next release / manual dispatch — expectmcpp 0.0.102in the "Install mcpp and config mirror" stepFollow-ups (not here)
index_contracthas no unit coverage, and the floor has no e2e at all).min_mcpp.index.toml min_mcppbefore the release channel can serve a client that satisfies it.CI restructuring (second commit)
Warm-cache PR runs before this change: ci-windows 20.4 min, ci-linux 18.2 min, both single sequential jobs. Everything below is wall-clock, not work.
Shared setup, extracted
.github/actions/bootstrap-mcpp— the cache lineage (mcpp sandbox + xlings +target/) and the xlings bootstrap, so split jobs share one definition instead of a 40-line copy-pasted preamble each. Thetarget/cache is now keyed per job: the toolchain legscleanand rebuild, so a shared key had them overwriting each other's lineage (todayci-linuxsaves an LLVM-builttarget/under the key everything else restores from)..github/actions/setup-macos-llvm— same for the macOS-specific setup (xlings LLVM + a sandbox wired to that exact package).Splits
ci-linuxbuild-test,toolchain-gcc,toolchain-cross(musl+llvm),integration-xlings→ ~7–8 minci-windowsbuild-test(+package) andtoolchains(+regressions) → ~8 min; e2e moved toci-windows-e2eci-windows-e2eci-macosci-macos-e2eci-linux-e2eNo
needs:between the split jobs — each pays one warmmcpp build(~2.5 min), which is cheaper than serialising them behind an uploaded artifact would be.e2e sharding
tests/e2e/run_all.shgainsE2E_SHARD="<index>/<total>"(1-based), a round-robin slice of the suite. Round-robin rather than contiguous ranges because per-test durations are wildly uneven — the runner's existing "slowest first" timing report exists for exactly that reason. The slice is computed on the full file list before capability filtering, so a test's shard does not move when host capabilities differ. 147 tests split 74/73.Coverage changes (deliberate, call them out in review)
mcpp testin the Linux GCC leg: same suite, same toolchain, same driver binary asbuild-test, differing only in incremental state. The cold-build assurance lives in themcpp buildhalf, which is kept.$MCPP_SELF.Test plan