Skip to content

Navigation Menu

Sign in
Sign up
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mcpp-community/mcpp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main@{1day}
Choose a base ref
Loading
...
head repository: mcpp-community/mcpp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Loading
  • 6 commits
  • 73 files changed
  • 2 contributors

Commits on Sep 10, 2026

  1. fix(examples): follow the farms to 2026年09月11日 ( #602 )

    * fix(examples): follow the farms to 2026年09月11日
    `compat:vulkan-runtime` and `compat:opencl-runtime` no longer carry
    `libnvidia-pkcs11*` -- a PKCS#11 token module the vendor name pattern swept in
    and that no GPU driver's dispatch reaches -- and the chain that delivers them
    took new versions so an installed copy stops recording the old pin.
    Measured on this host with the driver, both examples rebuilt from an empty
    target directory:
     sycl members 49, walked 49, findings none
     vulkan members 56, walked 56, findings none
    and both compute `12 24 36 48` on an RTX 4080.
    Follows mcpplibs/mcpp-index#383.
    * fix(examples): offscreen stops naming a dependency its dependency already declares
    `compat.vulkan` declares `compat.vulkan-runtime` itself on Linux. Naming it here
    too pinned one version in two places, in two repositories, with nothing
    enforcing that they agree -- and they drifted three times in one day: the farm
    moved its key, this file moved its own, and a runner holding an installed
    `compat.vulkan` still recorded the previous one. Each time the build stopped
    with `irreconcilable versions` and each time the repair was to edit the other
    place.
    Measured after removing it: the example still receives the farm --
    `library_dirs` names `compat-x-vulkan-runtime/2026.09.11`, and the record reads
    members 56, walked 56, no findings -- because the package that needs the
    adapter is the package that says so.
    The comment that explained why the adapter exists stays, and now explains why
    this file does not name it.
    ---------
    Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
    Configuration menu
    Copy the full SHA
    95b2dc0 View commit details
    Browse the repository at this point in the history
  2. docs(596-verify): the probe follows compat:sycl-runtime to 2026年09月11日

    The farms took new keys when `libnvidia-pkcs11*` left them, and the chain that
    delivers them moved with it. The default here is the version the ecosystem now
    publishes as latest.
    speak-agent committed Sep 10, 2026
    Configuration menu
    Copy the full SHA
    2d10281 View commit details
    Browse the repository at this point in the history
  3. No distribution format lives in the engine, and the three platforms a...

    ... package cannot add (2026年9月11日.1) (#605)
    * feat(pack): `--format <name>` dispatches to a package, and no distribution format lives in the engine (2026年9月11日.1)
    `tar` and `dir` answer the same question `msi` and `appimage` answer -- what
    shape does the output take -- so they are values of one flag rather than the
    beginning of a second one. The split that keeps every other format out of the
    engine is: `mcpp pack` owns the mechanism and the one universal format, and
    every other format lives in a package that `mcpp pack` dispatches to.
    The universal format is what it already produces: an archive that extracts and
    runs, universal in the only sense that matters here -- it needs no knowledge of
    anyone else's release. Everything past it does. dpkg's control fields,
    AppImage's runtime, WiX's schema, Apple's notarisation, Android's signing
    scheme: each one bound into the engine couples an mcpp release to a release mcpp
    does not control. The project already made this argument for languages, where
    Slang is supported without being named in the engine, and a distribution format
    has less claim to a name in the engine than a language does.
    Three additions, each FORMAT-NEUTRAL, which is the test for whether something
    belongs in the engine at all:
     - A staged tree an artifact action can consume. `mcpp pack` already computes
     one -- the dependency closure after the strip policy, the debug-symbol split
     and `include`/`exclude` -- and then compressed it and the directory was
     gone, so a `.deb`, an AppImage, a `.app` and an `.msi` each had to rebuild
     it. `${mcpp.stage_dir}` exposes it.
     - The rest of `[package]` in the build program: `MCPP_PKG_VERSION` /
     `_DESCRIPTION` / `_LICENSE` / `_AUTHORS` / `_REPO` and the matching
     `mcpp::package_*()`. Every installer states a version; without these a
     project restates it in the member's own options, where the copy drifts from
     `[package]` with nothing able to detect it.
     - `--format` resolving its value through the graph. A package declares with
     `mcpp::provides_pack_format("<name>")`; `--format <name>` finds the provider
     among the resolved dependencies. The refusal for an unknown value names what
     IS available rather than a constant, and arrives before anything is
     compiled.
    DECLARE UNCONDITIONALLY, SUBMIT CONDITIONALLY. This is the load-bearing rule of
    the dispatch and the one a member author is most likely to get wrong, because a
    member that gets it wrong still works for whoever wrote it -- they always pass
    their own format. The declaration must not be gated, or the engine can never
    answer "which formats does this graph provide"; the submission must be, or a
    plain `mcpp build` grows an edge it must not have. A format nothing submitted
    for is refused by name rather than reported as a pack that produced no package.
    `mcpp pack --format <name>` PREPARES TWICE, AND NOTHING IS RE-DERIVED BETWEEN
    THE PASSES. An artifact action is a ninja edge and the staged tree is produced
    after the link, so the tree cannot be an input of the pass that built it. The
    first pass collects declarations and refuses an unknown format; the build and
    the staging follow; the second pass sets `pack_format` and `pack_stage_dir` and
    builds the submitted edge. Its triple and staged path come from what the first
    pass and `make_plan` already answered -- `stagingRoot` is a function of the
    resolved triple, and a second derivation of it before prepare is the shape where
    two answers agree on every machine the author has.
    build.ninja's header line gains a fourth field, `dist=`, and the fast paths
    require it to read `none`. The format is deliberately NOT in the fingerprint --
    putting it there would cost a full recompile to package an already-built tree --
    so the two graphs share a directory, and `target/<triple>/<fp>/build.ninja` is
    shared mutable state two fast paths replay. That is the third instance of the
    failure `graph=` and `accel=` each already record. The criterion is a unit test
    rather than an end-to-end assertion: measured on 2026年09月11日, a plain build after
    the pack pass regenerates the graph even with the field ignored, so an
    end-to-end check would pass whether or not the field works and would keep
    passing if it were deleted.
    `${mcpp.stage_dir}` REFUSES rather than expanding to nothing, in two places: a
    build that is not packaging, and a role other than `artifact`. An empty path is
    still a token the command accepts, and the tool then reads the build directory
    root, which exists -- so the mistake produces a plausible artifact instead of a
    diagnostic. The measured prototype is a valid, empty, 52 KB installer with
    nothing said about it.
    An action that names the placeholder automatically gains a dependency on
    `<staged tree>.stage-manifest` -- a sibling, never a member, so it never travels
    inside anyone's installer. The engine adds it because the use implies it:
    without it the edge is dirty only when a link output changes, and a closure that
    grew a dependency's shared library while the program's own bytes did not would
    leave the previous distributable in place, reported as up to date.
    Build-program protocol v9 (`mcpp:pack-format=`). The row carries a non-empty
    `tag`, so the declaration is replayed from the build program's cache record --
    the pass that reads the set is `mcpp pack`, which is never a project's first
    build, and an unpersisted declaration would be absent exactly when a user names
    a format.
    Tests: 6 unit tests for the staged-tree contract, the graph-shape field in both
    of its two readers, and the directive row's persistence; one e2e holding the
    four properties of the dispatch, each with the wrong answer it excludes.
    Docs: `docs/10` for the `--format` axis, `docs/30` for the three-category
    taxonomy and the new placeholders and accessors, `docs/31` for the six
    constraints a distribution member owes its consumer. Both languages.
    * fix(pack): an unsupported `--format` value writes nothing to stdout
    `mcpp pack --format bogus` must write NOTHING to stdout and exit 2. That is the
    machine-output contract, and 202_machine_output_contract.sh asserts it for
    exactly this command, because it is the path a client hits when it probes an
    mcpp for a capability -- the most common machine-facing failure, and the one
    that used to print to stdout.
    Moving the refusal from the CLI parser to after `prepare_build` broke it. It
    had to move: the set of valid values is a property of the RESOLVED GRAPH, so a
    refusal written in the parser could only compare against a constant, which is
    the coupling this whole mechanism exists to remove. But prepare narrates what
    it resolves, so the refusal now arrived after three lines on stdout.
     FAIL: unsupported value (pack) wrote to stdout: Resolving toolchain
    Measured on macos-arm64, and it would have failed on every platform -- the
    macOS shard is simply the one that reached it first.
    The fix is to be quiet until the value is validated, and only then. Nothing is
    lost when the value IS valid: the dispatch pass prepares a second time and
    prints the same lines, so a successful `pack --format <name>` narrates once
    rather than twice. `--format tar` and `--format dir` are untouched, because
    their values were never in question.
    The musl re-prepare is quieted on the same grounds: it also runs before the
    format has been validated.
    The assertion is added to 638_pack_format_dispatch.sh as well as living in 202.
    That is deliberate duplication: the tension is local to this feature -- the
    valid set needs the graph, and the graph narrates -- so the test for the
    feature should fail when the contract does, rather than only the general
    contract test noticing.
    * feat(target): Android, iOS and wasm are rows, and the object format is an axis
    Section 3 of the design record draws the boundary exactly: a package can add a
    language, a tool, an action, a payload and a generated module, and IT CANNOT ADD
    A TRIPLE. Identity is three strings and `kKnownTargets` is compiled into the
    binary, so every layer below the first -- the `.apk` step, the `.app` step, the
    `.html`+`.wasm` step, the runner, the signing, the non-C++ glue -- waits on a
    row here and on nothing else in the engine. Registering the rows is what turns
    each of those from a plugin with nowhere to attach into a plugin that can be
    written.
     aarch64-linux-android x86_64-linux-android aarch64-ios wasm32-emscripten
    ALL FOUR ARE `planned`, WHICH IS A REFUSAL AND NOT A GAP. The tier gate answers
    `tier-planned` naming the row:
     error: target 'aarch64-linux-android' is registered but not yet supported
     (planned) -- no toolchain is published for it yet
     error: target 'aarch64-linux-androideabi' (which resolves to
     'aarch64-linux-android') is registered but not yet supported
    rather than `unknown target`, which was false, or a build that resolves and
    produces nothing, which section 3.1 argues would be worse than the row's
    absence. What each row still needs is a PAYLOAD in every case and never engine
    work: `xim:android-ndk`, `xim:emsdk`, and for iOS a licence reading before a
    packaging decision.
    THE OBJECT FORMAT IS NOW ONE ANSWER, AND THAT IS WHAT #597 ACTUALLY NEEDED.
    The binary format was never a field. It was re-derived from `os` wherever it was
    needed -- `is_pe()` asked `os == "windows"`, artifact naming asked again, the
    packer asked a third time -- which is affordable only while the answer has two
    values. `wasm32` is the first target in mcpp's vocabulary whose format is
    neither, and a THIRD value turns those derivations into an addition at every
    such site. A site that is missed does not fail: it silently answers ELF,
    because ELF is what every `else` branch in the tree assumes. `ObjectFormat` is
    that addition made once, with `is_pe()` / `is_mach_o()` / `is_wasm()` reading it.
    It is deliberately NOT the same question as `is_freestanding()`. A bare-metal
    RISC-V image is ELF with no OS; a wasm module has an OS-like layer
    (Emscripten's POSIX emulation) and is not ELF. Merging the two axes is the
    mistake this replaces.
    ANDROID'S PLACEMENT IS THE MODELLING DECISION: `env = "android"` on a `linux`
    OS, not `os = "android"`. The kernel IS Linux, so ELF, the `unix` family and
    `nasm -f elf64` are already right; an OS value would have made every one of
    them wrong by default and required a new answer at each site. What differs from
    `gnu` is bionic, the loader path and the SDK -- which is what an `env` value is
    for. `androideabi` resolves to the same env: the EABI half is the ARM calling
    convention, which the arch segment already carries.
    `is_apple()` exists because a site that means "Apple" and asks "macOS" gets iOS
    wrong in the direction that still links. iOS shares the object format, the
    linker, the `arm64` spelling and `codesign` with macOS, and differs in the SDK
    and the deployment-target flag. No deployment target is baked into
    `llvm_triple()` for it, unlike the macOS branch: `-miphoneos-version-min`
    belongs to the layer that owns the SDK and the bundle, and a default here would
    be a second place that answers it.
    A DISPLAY DEFECT THE ROWS EXPOSED. `x86_64-linux-android` showed no `cross` tag,
    because that test compared arch and OS only -- and this target agrees with an
    x86_64 Linux host on both. An Android artifact needs bionic's loader at
    `/system/bin/linker64`, which no ordinary Linux host has, so it cannot run
    there. Spelled as a property rather than by adding `env != env`, which would
    have taken `x86_64-linux-musl` with it -- that one is static and does run here.
    48 new cells in tests/matrix/expected.tsv, one per (mode, host, compiler) the
    table declares, all `unsupported / tier-planned`; the declared per-host counts
    move with them, because compare.sh checks the total before it checks a cell.
    The day a row is wired, its cells go red and say so. Verified locally:
    50/50 payload and 24/24 graph on linux-x86_64.
    Docs: `docs/21`'s segment tables gain the new values, a section states the
    object-format axis and why it is not the freestanding question, and the
    host/target matrix gains four rows. Both READMEs' platform tables record what
    each row waits on. Both languages.
    * fix(pack): the distributable is what the request introduced, not what names the staged tree
    `mcpp pack --format <name>` reported as the distributable only those artifact
    actions that named `${mcpp.stage_dir}`, on the assumption that a distributable
    consumes the staged closure. NOT EVERY FORMAT DOES, and the one that does not is
    the one the guidance recommends.
    An `.msi` built from ONE NAMED PROGRAM takes `${mcpp.target_file:<name>}` and
    never looks at the tree. That is `docs/31`'s "name the input, do not harvest a
    directory", written after a bind path that resolved to nothing produced a
    valid, empty, 52 KB installer with no diagnostic. So a member following that
    guidance failed the check, and `mcpp pack --format msi` reported
     no action claimed --format 'msi'
    after a `wix build` that had succeeded. The workaround available to the member
    was to declare the placeholder as an extra, otherwise-unused input purely to
    satisfy the engine -- which also gave it a dependency on a tree its one `File`
    row never reads.
    The property actually wanted is presence in the dispatch pass. An artifact
    action present whether or not a format was asked for -- a codesign stamp, a
    size budget -- existed before anyone asked, and reporting one as the package
    would be a wrong answer that looks like a right one. So the first pass's
    artifact actions are collected, and the dispatch reports the difference.
    Identity is (package, id): an id is unique within the package that declared it
    and nothing more.
    `consumesStageDir` keeps its one real job -- the implicit dependency on the
    staged tree's manifest, so an action that reads the tree is dirty when the
    staged SET changes and not only when a link output does. Its comment now says
    what it is not.
    `638_pack_format_dispatch.sh` gains the case that pins this from both sides: a
    fixture submitting an UNGATED artifact stamp and a GATED action that names no
    staged tree at all. The gated one must be reported and the stamp must not, and
    the stamp must still have been built -- it was simply not the answer. Verified
    load-bearing by removing the guard, which reports `size.stamp` as the package
    and fails the test.
    Found while porting `mcpp.dist.wix`, which is to say by writing the second
    member. The first one consumed the staged tree and agreed with the check by
    accident.
    * fix(target): every object-format question reads the single answer, and two copies were searching for a vendor name
    An audit of the 35 sites that derived the binary format from `os`. Twelve of
    them asked "which object format" and were converted to read `object_format()`;
    the rest ask a different question -- which payload to install, which loader
    variable a platform reads, which flag spelling a compiler wants -- and are
    unchanged. The classification mattered more than the count: a site that means
    "which OS" and is converted becomes wrong in a new way.
    WHAT EACH CONVERTED SITE ANSWERED FOR `aarch64-ios` BEFORE:
     -femulated-tls, -fvisibility-hidden not passed (Mach-O needs both)
     shared_library_link_flags $ORIGIN, which ld64 rejects
     shared_soname_flag -Wl,-soname, a BFD-only flag
     exports_file_contents / exports_flag a GNU version script
     debug_info_is_in_band true; Mach-O splits to dSYM
     dist::format_for the BUILD HOST's format
    Every one of those is the ELF branch reached by falling off the end of a
    two-valued test, which is the failure `ObjectFormat` was introduced to make
    impossible. Verified for every row in `kKnownTargets` that the answer changes
    only for `aarch64-ios` and `wasm32-emscripten`, and only toward correctness.
    TWO COPIES WERE SEARCHING FOR A VENDOR NAME IN THE WRONG STRING, AND ONE OF
    THEM AFFECTS AN ALREADY-VERIFIED ROW.
    `compute_flags`'s `linkIntentFlavor` and `resolution.json`'s `format` both
    derived the object format by looking for "apple" / "darwin" / "windows" /
    "mingw" in `plan.toolchain.targetTriple`. That string is mcpp's CANONICAL
    spelling, and `aarch64-macos` contains none of those words. The words live in
    the LLVM spelling, which is a different string -- the build report prints both,
    either side of an arrow:
     Target aarch64-macos → arm64-apple-macos14.0
     ^ the identity ^ what clang is given
    So an explicit `--target aarch64-macos` linked and recorded as ELF. A NATIVE
    macOS build was right by a different branch -- an empty triple reaching the
    `needs_explicit_libcxx` rescue -- which is why nothing caught it: two paths
    through one function disagreed and only the exercised one was correct. Both now
    ask the parsed triple, and the substring test survives only for a spelling
    `parse` REJECTS, which is the `[target.<triple>]` escape hatch where an
    LLVM-shaped string is what an author actually wrote.
    `test_toolchain_triple.cpp` states this as a fact about the vocabulary rather
    than as a comment elsewhere: for `aarch64-macos`, `x86_64-macos` and
    `aarch64-ios` it asserts the canonical spelling contains neither "apple" nor
    "darwin", that the format is Mach-O anyway because it is asked of the fields,
    and that the LLVM spelling is where the vendor name lives. A second test takes
    its denominator from the table, so a row added without an answer cannot be
    covered by a test whose name says every row is.
    TWO GAPS ARE NAMED RATHER THAN GUESSED. `dist::Format` and `LinkIntentFlavor`
    have no `Wasm` member, so `wasm32-emscripten` still resolves to `Elf` in both.
    What "self-contained" and "link_lib" mean for an Emscripten link is a
    distribution-contract decision and the open half of #597, not a rename; the
    switch names the case so the gap is visible instead of reached by falling
    through. `mcpp::pack::run` now refuses a file that is neither ELF, PE nor
    Mach-O by name, where it previously handed anything not-PE-not-Mach-O to
    `LD_TRACE_LOADED_OBJECTS`.
    Docs: the design record's section 3.1 is corrected twice, because two of its
    guesses were measured wrong in the same direction -- a vendor had already done
    the work and nobody looked. NDK r30 ships the 133-file module surface itself
    (r27 shipped none), so for Android there is nothing to derive; and Apple's
    libc++ IS a build of a public revision (210106 -> llvmorg-21.1.6), the SDK
    ships no surface, and an `import std` Mach-O arm64 binary was linked from a
    Linux host. Section 8 names the pattern rather than only listing the facts.
    109 unit tests pass.
    ---------
    Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
    Configuration menu
    Copy the full SHA
    51dff99 View commit details
    Browse the repository at this point in the history
  4. docs(record): three vendors measured at current versions, and Android...

    ... execution is conditional
    Documentation only. The design record's section 3.1 measured NDK r27,
    Emscripten 4.0.19 and guessed about Apple. All three were re-measured while
    the payloads were built, and none of the three guesses held.
    TWO OF THE THREE VENDORS NOW SHIP THE `import std` SURFACE THEMSELVES.
     NDK r30 133 files ships it _LIBCPP_VERSION 210000
     Emscripten 6.0.9 134 files ships it 220108
     iPhoneOS 26.5 0 files does not 210106
    So the generation machinery the section describes at length is needed for one
    target rather than three, and what a recipe owes instead is narrower: pin the
    value measured and refuse a change. For Android that is all it can be -- r30's
    libc++ comes from an AOSP mirror revision (`r574158c`) with no upstream tag to
    compare against. Emscripten's numbers in the record were two releases stale;
    the lesson it drew from them -- match the LIBRARY, not the compiler -- is
    right, which is why the correction is to the numbers and not to the argument.
    APPLE WAS THE LARGEST CORRECTION AND WAS RECORDED SEPARATELY: iOS CAN be
    measured from a Linux host, Apple's libc++ IS a build of a public revision, and
    the surface is absent but derivable. An `import std` Mach-O arm64 binary was
    linked here.
    ANDROID EXECUTION IS CONDITIONAL, AND THE CONDITION DECIDES THE TIER.
     x86_64-linux-android static: runs directly dynamic: does not
     aarch64-linux-android static: runs under qemu dynamic: does not
    Dynamic fails for two independent reasons and neither is a missing flag. The
    artifact's `PT_INTERP` names `/system/bin/linker64`, which exists nowhere in
    the 2.3 GB NDK -- `-L` and `QEMU_LD_PREFIX` affect library SEARCH, not the
    interpreter path. And bionic's `libc.so` is inert: 1147 exported functions in
    9176 bytes of `.text`, every one inspected disassembling to `bti c; ret`. That
    is the documented stub shape; the bodies come from the device. For contrast
    `libc++_shared.so` is real code at 724 KB, because it is the one runtime the
    NDK owns.
    So the honest claim is "runnable only when statically linked", and the tier
    follows from the DEFAULT configuration rather than from the best case. The rows
    carry `defaultStatic = false` and that is correct about the platform: a real
    Android application links dynamically against the device's bionic. Setting the
    flag true to make an execution check pass would misdescribe the platform to
    flatter the measurement.
    A `--no-default-config` finding is recorded with the Apple work because that is
    where it surfaced, but it is a property of the `xim:llvm` payload and applies to
    any non-Linux cross target driven through it: `bin/clang++.cfg` injects the
    host's glibc and libc++ unconditionally, `-nostdinc++` does not displace them,
    and the criterion is `clang -v`'s search list rather than whether the compile
    succeeds.
    Section 8 names the pattern the corrections share rather than only listing
    them: every wrong guess was about what a vendor had done, and every one was
    cheap to check and was not checked.
    speak-agent committed Sep 10, 2026
    Configuration menu
    Copy the full SHA
    01f40c7 View commit details
    Browse the repository at this point in the history
  5. docs(triage): six open issues, and where three of the reports are wro...

    ...ng about the cause
    #564, #597, #599, #603, #604, #606 read against the code and measured where a
    claim was checkable. Every report is accurate about its symptom; three are
    wrong about the cause, and two of those describe a smaller defect than the one
    present:
     #606 the scanner has never had block-comment state -- `git log -S` returns
     no such commit -- so the bisect dates when the defect became audible,
     not when it was introduced. The refusal added at 2026年9月9日.1 is correct.
     The unreported form is worse and was measured: `export module y;`
     inside a block comment makes a plain `.cpp` the recorded producer of a
     BMI the compiler never writes, and a real importer of `y` is then told
     `imports must be built before being imported`.
     #604 cause read rather than guessed: the host-module flag de-duplicator is
     per token and was written for GCC's one-token `-fmodules`. MSVC's
     reference is two tokens whose first legitimately repeats, so the pair
     loses its `/reference` and cl reads `<name>=<path>` as a source file.
     #599 three defects, not two: the hub path is stale (and the report's
     replacement path is also wrong), the `uninit` branch prints a note that
     cannot turn a job red, and there is no bench workflow at all -- so the
     check has run in zero CI jobs since it was written.
    #603's suggested fix needs one correction: the existing probe reads
    `tc.version`, which is clang's on that path, against an MSVC threshold. #564's
    two dead keys want opposite answers. #597 is largely implemented on the #605
    line; its remaining two items reuse existing mechanism.
    speak-agent committed Sep 10, 2026
    Configuration menu
    Copy the full SHA
    3f63100 View commit details
    Browse the repository at this point in the history

Commits on Sep 11, 2026

  1. Five open issues, three of them misdiagnosed by their reports, and st...

    ...aging as a service (2026年9月11日.2) (#607)
    * fix(pack): staging is a service to the provider, not a precondition for dispatch (2026年9月11日.2)
    `mcpp pack --format <name>` staged unconditionally before dispatching, and a
    staging failure failed the whole command. For `--format tar` and `--format dir`
    that is right -- the staged tree IS the product. For a DISPATCHED format it is
    an input the provider may or may not want, and treating it as a precondition
    made EVERY dispatched format unreachable on any target whose built-in bundling
    is refused.
    Measured on macos-15 with 2026年9月11日.1: `mcpp pack --format app` never reached
    the dispatch at all, because `pack::run` refuses a Mach-O PROGRAM outright --
    the built-in closure walk is `LD_TRACE_LOADED_OBJECTS`, which is glibc's, and
    dyld ignores it and simply runs the program. That refusal is correct about the
    built-in archive and says nothing about whether a `.app` bundler can work: a
    bundler that names one program needs no closure walk. THE ENGINE WAS ANSWERING
    A QUESTION THE PROVIDER HAD NOT BEEN ASKED.
    The failure is now reported and CARRIED rather than fatal or swallowed. The
    reason is printed as a warning, `pack_stage_dir` stays empty, and
    `${mcpp.stage_dir}` refuses at expansion naming that reason. A provider that
    reads the tree gets a precise diagnostic; one that does not proceeds. Nothing
    is silently degraded -- what changes is who decides.
    `BuildOverrides::pack_stage_reason` is that channel. Without it a build that is
    plainly packaging would read "this build is not packaging", which sends a member
    author looking in the wrong place -- the refusal has to distinguish "you did not
    ask for a format" from "no tree could be staged for this target".
    `638_pack_format_dispatch.sh` gains the case macOS found, held on every
    platform. Linux cannot reproduce the Mach-O refusal, so the leg asserts the
    property the fix rests on instead: a provider that reads no staged tree is
    dispatched and reported, and gains no dependency on the stage manifest. Nine
    cases now, each paired with the wrong answer it excludes.
    WHAT FOUND THIS IS WORTH RECORDING. `dist-apple` had only plan-level assertions
    behind it until CI ran it on a real macOS runner for the first time. A
    plan-level assertion says the gate is right and says nothing about whether the
    tool accepts what the member renders -- which is why the two platform-specific
    CI steps were added, and why the first thing they did was fail.
    109 unit tests pass. `266_pack_refuses_a_macho_program` still fails on this
    machine and was A/B'd against released 2026年9月10日.2: byte-identical logs, so
    this change does not touch it. Plain `mcpp pack` keeps the fatal refusal, since
    `opts.format != Dispatched` there.
    * docs(record): the implemented result read from nine angles
    Section 9 reviewed the proposal on its own terms; section 11 reviews what
    shipped, from the nine angles a reviewer applies independently of it. Each
    angle is recorded with the wrong answer it excluded and, where one exists, the
    measurement that changed the design -- the architecture section names the two
    occurrences of the same error (the engine deciding on the provider's behalf),
    the test-coverage section names the CI assertion that was itself the defect,
    and the last section gives the dependency order and why it is not the order the
    rows land in.
    * fix(scanner, host modules, toolchain, config, bench): five open issues, and three of the reports were wrong about the cause
    #606 THE SCANNER READ INSIDE COMMENTS, IN BOTH DIRECTIONS. Block-comment
     state never existed in the file's history -- `git log -S` returns no such
     commit -- so the bisect to "after 2026年9月7日.1" dates when the defect
     became audible, not when it was introduced; the refusal added at
     2026年9月9日.1 is correct. The unreported form is worse: `export module y;`
     inside a block comment made a plain `.cpp` the recorded producer of
     `y.gcm`, and a real importer of `y` was then told `imports must be built
     before being imported`. And the OTHER direction, also unreported: a
     commented-out raw-string opener blanked every following line, so real
     imports were invisible to the scanner and visible to the compiler -- a
     missing dependency edge, which is a build-order race rather than a
     deterministic refusal.
     One pass over three states. Eight criteria in tests/e2e/639, two of them
     properties that were already correct and must not be lost; six of the
     eight go red against released 2026年9月10日.2.
    #604 A TWO-TOKEN SWITCH LOST ITS SWITCH. The host-module flag collector
     de-duplicated per token and was written for GCC's one-token `-fmodules`.
     MSVC's reference is a pair whose first half legitimately repeats, so the
     pair lost `/reference` and cl read `<name>=<path>` as a source file
     (C1083). Appended verbatim now; the comment being replaced stated the
     filter's whole value ("harmless but noisy"). Plus
     `orphaned_reference` as a reader that names the cause before the command
     runs.
    #603 THE LEVEL IS A PROPERTY OF THE STL. Calling the existing probe from
     clang's path would have compared a clang version against an MSVC
     threshold. The toolset version is in the path of the `std.ixx` already
     selected; one function, both paths, and a test that the two forms agree
     for a well-formed installation.
    #564 `default_jobs` gained a reader and `default_backend` was removed. Two
     dead keys wanting opposite answers: one names a machine fact with no
     other home, the other promises a choice that does not exist. The test
     asserts the precedence, not the wiring.
    #599 A CHECK THAT HAD RUN IN ZERO CI JOBS. Three defects, not the two
     reported: the hub path was written for the current layout while naming a
     historical tree, the `uninit` branch printed a note that cannot turn a
     job red, and there is no bench workflow at all -- so the test's own
     justification for the note was false. All three fixed, and the note now
     fails under CI while staying a note locally.
    * fix(record): the jobs precedence is documented in docs/04-mcpp-toml.md
    The comment and the analysis both named `docs/03-configuration.md`, which
    does not exist -- caught by this repository's own docs check, which asserts
    that every document a file names is present.
    * ci: 233 runs on three platforms, so three workflows need the pinned trees
    The new criterion fired on macOS and was right to. `submodules: recursive`
    went onto the Linux e2e shards only, and `233_bench_matrix.sh` runs in every
    job that invokes the whole suite -- of which there are three, not one. That is
    the same shape as the defect it was added for: a check reasoned about against
    one job and applied to all of them.
    Enumerated rather than guessed this time. The three unfiltered
    `bash tests/e2e/run_all.sh` jobs are ci-linux-e2e, ci-macos-e2e and
    ci-windows-e2e, and all three now check the trees out.
    ci-windows-msvc-xlings sets `E2E_ONLY: '239_*.sh'`, so 233 does not run
    there; ci-linux-e2e's baremetal job and openkal-cross name their tests
    directly.
    The failure now says what to do rather than asserting that this job already
    asks for the submodules -- which would be false for exactly the job that
    needs to be told.
    ---------
    Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
    Configuration menu
    Copy the full SHA
    d925b6f View commit details
    Browse the repository at this point in the history
Loading

AltStyle によって変換されたページ (->オリジナル) /