Skip to content

汇总:2026-08-09 全量 issue 核验 —— 关闭说明、合并去向,以及 9 条新发现缺陷的收口 #397

Description

@speak-agent

本轮对全部 26 个 open issue 逐条落到当前代码做了核验(基线 main@80291ca / v2026.8.8.4,xlings 2026.8.9.2,xim-pkgindex c0aded29,mcpp-index b86fc7c)。
本 issue 是那次核验的汇总与收口:它接住所有被关闭 issue 的残留项,并登记核验中新发现、目前无处安放的缺陷。

A. 本轮关闭的 issue,以及残留项落在哪

关闭 理由 残留 → 去处
#289 三条核心主张全部被 PR #378(fdad165)消除 两条新缺口 → 本 issue C-5 / C-6
#371 核心前提被证伪;验收标准由 PR #387 承接 AC1/AC5 的取舍决定 → 本 issue D-1
#382 主症状已由 xim-pkgindex #563/#565 修复 op="set" 语义 → 本 issue C-7
#313 7 条建议:3 条已交付,其余各自归位 建议 3/7 → 本 issue D-2;建议 2 → #276;建议 5 → #260
#177 与 #144/#276 是同一缺口的三个面 合并进 #276
#144 同上 合并进 #276

合并后的承载点是 #276 —— 「mcpp 缺少一个申报『外部已经存在之物』的入口」这条 roadmap,涵盖外部工具链、外部 sysroot、外部第三方库三轴。


B. 新发现的缺陷 —— 核验中撞出来、当前没有任何 issue 覆盖

以下每条都在 main@80291ca 上复核过,行号为实读。

C-1 🔴 P0 · fast path 命中时 compile_commands.json 永不重建

src/build/execute.cppm:757-764 的 try_fast_build 新鲜度门只比对 build.ninja 的 mtime 与 mcpp.toml/源码,不检查任何产物是否存在;命中后 :768-774 直接 run_ninja_fast + return 0,NinjaBackend::build() 整个不执行,而 write_compile_commands 全仓唯一调用点就在那里(src/build/ninja_backend.cppm:1549)。

$ mcpp new demo && cd demo && mcpp build      # 成功,CDB 生成
$ rm compile_commands.json
$ mcpp build ; echo $?                        # "Finished dev in 0.00s" ; 0
$ ls compile_commands.json                    # No such file   ← 此后每次都如此

触发条件很日常:mcpp new 写的 .gitignore 只有 target/ 和 .mcpp/,CDB 未被忽略 ⇒ git clean -fd 删掉它、保留 target/ ⇒ 下一次 mcpp build 命中 fast path ⇒ CDB 再也回不来。

而 mcpp-vscode(src/extension.ts:105,128-136)的流程是「CDB 不存在 → 提示 Run mcpp build → 用户点 Build → 再检查」。这个组合让扩展陷入死循环:构建每次都成功,提示每次都还在。

同一形状在 try_fast_run(execute.cppm:788 起)也在。

真正该问的不是「补一次产物存在性检查」,而是:fast path 的新鲜度门缺的是一整类判据 —— 输入新鲜 ≠ 输出齐全。

C-2 🔴 P1 · 模块扫描器的 strip 顺序本身是一个假阴性

src/modgraph/scanner.cppm:588-589 先 strip_raw_strings 后 strip_line_comment。于是只要源文件的 // 注释里出现一个未闭合的 R"((写文档解释 raw-string、贴一段带 raw-string 的示例,都会产生),in_raw 就悬挂到文件末尾,后面所有 import / export module 全部消失。

实测两例:真的 export module mylib; 被吞 ⇒ 消费者收到 module 'mylib' imported but not provided(一个明明存在的模块);import totally.real.module; 被吞 ⇒ 一路到 g++ 才报 failed to read compiled module。

这比 #373 报告的块注释问题更重:那个是假阳性(多报一条 warning),这个是假阴性(真声明消失)。两者同源,必须一起修。

修复本身还有一个必踩的地雷:普通 "..." 字面量里的 /* —— mcpp 自己的树里就有,src/build/distribution.cppm:417 的 "/* Generated by mcpp. …",配对 " */\n" 在 :426。一个不认识字符串字面量的块注释 pass 会把 417–426 整段吞掉。安全阀:普通字符串状态必须行内即抛、绝不跨行。

C-3 🟠 P1 · --no-color 在 TTY 下是空操作

  • src/cli.cppm:107 — --no-color → mcpp::ui::disable_color()(argv 预扫描,早于任何输出)
  • src/ui.cppm:239 — void disable_color() { g_color = false; } ← 只改 g_color,不置 g_inited
  • src/ui.cppm:233-237 — void init() { if (g_inited) return; g_color = detect_color(); g_inited = true; }
  • 每个输出入口(status/info/finished/warning/error/diagnostic)都先调 init()

时序:--no-color 把 g_color 置 false → 第一条 ui::status() 调 init(),发现 g_inited 仍是 false → 重新 detect_color() → 在 TTY 上又变回 true。

一直没被发现的原因:CI 与所有 e2e 都通过管道捕获输出,detect_color() 在非 TTY 下本来就返回 false ⇒ 「无色」这个结果是对的,但原因是错的,测试测不出这个开关有没有生效。MCPP_NO_COLOR / NO_COLOR 走 detect_color() 内部,不受影响;只有 --no-color 这一条路径坏了。

修法一行:{ g_color = false; g_inited = true; }。测试必须直连 ui:: 断言输出不含 \033——靠现有 e2e 是假绿。

C-4 🟠 P1 · [modules].exports 校验对任何设了 namespace 的包是静默空操作

src/modgraph/validate.cppm:98 比的是 u.packageName == manifest.package.name,而 src/modgraph/scanner.cppm:789-791 给 u.packageName 填的是限定名:

const std::string qualifiedName =
    manifest.package.namespace_.empty()
        ? manifest.package.name
        : manifest.package.namespace_ + "." + manifest.package.name;

于是 namespace="acme" / name="lib1" 时 "acme.lib1" != "lib1",actual 恒为空集,整个 exports 校验(含 strict)一条都不触发。实测:

  • [package] name="lib1", namespace="acme" + exports = ["totally.not.this"] + export module acme.lib1; → mcpp build 通过,零诊断
  • 删掉 namespace = "acme" 这一行,同一工程立刻报 module 'acme.lib1' is exported by code but not listed in [modules].exports

成因可追:scanner.cppm:786-788 的注释说这个限定名是为了让「模块名必须以包名为前缀」的检查工作,而那条检查在 0b8b81b 里被删了,留下的 :98 就悬空了。

⚠️ 修 #374 之前必须先看懂这条:如果 #374 的新谓词照抄 u.packageName == manifest.package.name,就会对所有 namespaced 包判成「没有模块接口」,把 warning 全局静默 —— 症状看起来像「issue 修好了」,实际是又踩了同一个坑。

相关:限定包名至少三处独立推导且算法不一致(scanner.cppm:789-791 无守卫 / plan.cppm:264-271 多一个 starts_with 守卫 / #374 将新增的第三处)。namespace="acme" + name="acme.lib1" 时 scanner 产出 acme.acme.lib1 而 plan 产出 acme.lib1,plan.cppm:1054 的 devDepPackages.contains(cu.packageName) 会静默失配。

C-5 🟠 P1 · Windows 上 xlings 版本门整套空转(#289 的残留之一)

src/fallback/xlings_binary.cppm:160 把 2>/dev/null 硬编码进一条经 cmd.exe /c 执行的命令 —— cmd 解析不了这个重定向,命令不执行,函数返回空串。空串在两个消费点都被当成「读不出来,不作判断」:acquire_xlings_binary 退回旧的 early return,doctor 退化成一条 warn。

也就是说 #289 点名的那个受害平台(Windows CI),恰恰是 PR #378 的修复不生效的平台。

仓库里已有 mcpp::platform::null_redirect(src/platform/common.cppm:37-41)就是为这件事准备的,这里没用。import mcpp.platform 在 xlings_binary.cppm:16 已在 ⇒ 一行改动。

守卫必须是「在本平台真 spawn 一次探针」,而不是再加一条 version_is_older 的字符串用例 —— 后者在 Linux 上照样绿。

C-6 🟠 P1 · 发布包自带的 xlings 没接进候选链(#289 的残留之二)

candidate_source_version()(src/fallback/xlings_binary.cppm:214-224)只看 MCPP_VENDORED_XLINGS 和 which xlings。而:

  • release 顶层 wrapper 是 .github/workflows/release.yml:351-354 的 exec "$(dirname "$0")/bin/mcpp" "$@",不导出 MCPP_VENDORED_XLINGS(只有 AUR 三个包导出);
  • src/home.cppm:92-99 把 data/xpkgs/ 下的 mcpp 显式取消自包含资格 ⇒ xlings install mcpp 装出来的 mcpp,MCPP_HOME 回落 ~/.mcpp,自带副本永远在视野外。

而正是「机器上的 xlings 很旧」这个前提,决定了 which xlings 在最需要自愈的场景里也是旧的 ⇒ 走进 candidate.empty() || !version_is_older(...) 分支,打一行 Note 就放弃 —— 尽管一份与 pin 逐字一致的 xlings 就躺在 <install>/registry/bin/xlings(本机实测 2026.8.8.4 包内为 xlings 2026.8.8.1)。

顺带:src/doctor.cppm:411-417 的「It is replaced automatically on the next mcpp self init」在这个分支里是错的。

C-7 🟠 P2 · mcpp 把 subos 的 op="set" 读成无条件覆盖(#382 的残留)

src/xlings/subos_info.cppm:256-281 取了 ambient 值但对 set 完全不用:

auto amb = ambient_of(d.var);
if (d.op == "set") { … out.emplace_back(d.var, value); continue; }   // amb 被丢弃

而 xlings 的四个后端全是条件赋值:

后端 代码 位置
POSIX : "${VAR:=value}"; export VAR; xlings/src/core/subos.cppm:1012
fish if not set -q VAR; set -gx VAR …; end :1120
pwsh if (-not $env:VAR) { … } :1143
in-process else if (existing.empty()) { set_env_variable(...) } :1166

后果:同一个 subos,xlings subos use 进去用户的 export 保留,mcpp run 进去被覆盖 —— 正是 subos_info.cppm:262-272 那段注释自己声称要避免的分歧,而分歧是 mcpp 造成的。

注释给的两条「不修」理由,一条错一条反过来支持修:(a)「subos 需要 set 表达用户不得覆盖」在当前生态零实例 —— 整个 xim-pkgindex 里 op="set" 只有 pkgs/w/wsl-gl-host-link.lua 一处,其余全是 prepend,而唯一那处恰恰是用户需要能覆盖的那个;(b)「消费方不得给 op 加第二种含义」是对的,但它指向的是现在的代码。

修法:改成 xlings 的两段式 —— 先纯 manifest 折叠(set 在则 set 赢、prepends 丢弃;否则按 provider 逆序去重拼接),再对 ambient 应用(prepend 接在前;set ambient 存在就整个让位)。判据用「有没有」而不是「空不空」(两个消费点的 lambda 正好是 std::getenv 的 optional,execute.cppm:367-374 / :888-896),对齐 xlings 的 utils::env_is_set。

⚠️ 不要照抄 73ab179 那版的 amb && !amb->empty() —— 那对应 xlings 2026.8.6.1 的旧语义。而 subos_info.cppm:287/289 的 prepend 分支今天正是这个旧写法,顺带一起收敛。
⚠️ 这个误读已经来回过三次(73ab179 两半都修 → 1cc1052 撤回 set → c1e9360 合入只剩 prepend)。修的时候请把上表四个行号写进注释和测试 —— 光写「set 是默认值」没用,上一版就是这么写的。

C-8 · 两个「看起来在做事」的空转循环

src/toolchain/lifecycle.cppm:559-564 与 src/build/prepare.cppm:1668-1670 的 sysroot 预装循环传的是无版本的 "xim:glibc" / "xim:linux-headers",而 src/pm/package_fetcher.cppm:930-935 一进门就是:

if (parsed.packageName.empty() || parsed.version.empty())
    return std::unexpected(CallError{"invalid xpkg target ... expected `<name>@<version>`"});

⇒ 自引入至今一次都没装成过任何东西。一处 (void) 丢弃返回值,一处只进 log::debug,所以从来没人看见。glibc 实际是靠 gcc 的 xim 依赖顺带装上的,症状被遮住了。

建议直接删除(mcpp 没有绕过 xlings 的依赖解析,即使能跑也是重复劳动;而在 mcpp 里钉死 glibc 版本常量会立刻和上游的 latest 2.39→2.44 漂移打架)。

C-9 · 其余已登记、优先级较低的发现

展开(11 条)
归属 发现
#393 MCPP_OUT_DIR/MCPP_MANIFEST_DIR 用 .string()(build_program.cppm:230-231),而 a.command 从不过归一化层(directives.cppm:668-670 只绝对化 inputs/outputs)⇒ 一个从不写 ${mcpp.…} 的 build.mcpp,照样在 Windows 上把混合分隔符塞进命令行
#393 含 ${mcpp. 的 role="source" 输出被 prepare.cppm:2969 整体排除在源集外 ⇒ 产物永远不会被编译且零诊断,而 docs/07-build-mcpp.md:222-224 承诺「畸形 action 是硬错误,绝不静默跳过」
#386 prepare.cppm:3210 的默认 glob(4 项)已与 toml.cppm:1476(7 项)漂移 ⇒ 走多版本 mangling staging 的包今天就漏掉汇编源
#380 template.cppm:142-144 三遍独立全文扫描 ⇒ 占位符串扰(实测 projectName = "{{self.name}}" 时 name = "{{project.name}}" 渲染成 name = "imgui",静默错值);template.cppm:156 的 ec 接住从不判读 ⇒ 模板目录读不了时零迭代、返回成功、打印 "Created";mcpp new foo.bar rc=0 且能构建,但违反 docs/spec/package-identity.md §3.2 ⇒ 生成本地能编、一发布就不合规的 manifest
#304 flags.cppm:884-885 把 runtime_dirs 拼在 user_ldflags 之前 ⇒ 用户显式写的 -Lvendor 也被压过;macOS 上 [runtime] library_dirs 完全是死的(flags.cppm:873-874 既不发 -L 也不发 -rpath),而 execute.cppm:1370-1377 还在警告「dependencies must be reachable through the binary's rpath」
#370 mcpp add <pkg>@'*' 静默写进一个永不可解析的依赖(commands.cppm:55 对任何范围直接早退)
#290 target_cfg 里写 cfg(version=…) 能过解析但 match_kv(prepare.cppm:152-158)不认 ⇒ 永远不生效且不报错
#256 canary tests/e2e/150_...sh 三个洞:control 只 precompile 不 import(:92-95)、ACTUAL 只看退出码(:104,而 22.1.8 上 SIGSEGV 经 driver 映射后退出码是 1 不是 139)、未登记大版本 exit 0(:108-112,实测构造 23.0.0 payload 后打印 no recorded expectation 然后 RC=0 通过)
#215 cppfly.cppm:161-164 的 gate 循环只比 family 就 break,与 latest_std_canonical(:142-148)语义不一致 ⇒ 给 Clang 加第二行的那一刻它会静默不可达;100_cppfly_reflection.sh:16-19 是会自我关闭的守卫(GCC 17 改名或默认开启 -freflection ⇒ 唯一那条硬路径 e2e 静默停跑)
#259 ci-linux-e2e.yml:104-166 的 hermetic job 缓存 ~/.mcpp 且带 restore-keys ⇒ 冷装路径跑绿一次后再也不被覆盖;lifecycle.cppm:576-582 安装后只 exists(bin) 不 exec
#379 xpkg parse --format json 失败契约自相矛盾:坏 descriptor 时 stdout 是合法信封但错误在 data.error 里是人类文本、diagnostics 为 [];另三个失败分支在 --format json 下 stdout 一字不写 ⇒ 客户端把「descriptor 写错了」误判成「这个 mcpp 太老」。另有第四种机器输出拼写 mcpp test --message-format json,契约文档零提及,而它恰恰是 CI 最可能消费的出口

C. 从关闭 issue 转移过来的决定项

D-1 · #371 的两块「明确不做」需要留痕

#379 §四已经否掉 ide 独立命名空间、artifact 状态枚举 / phase 状态机 / 快照 ID 体系、NDJSON 事件流。这是一个决定而不是待办,但这个决定从没写在 #371 上。已在 #371 的关闭留言里写明。

#371 的 AC2/AC3/AC4 由 PR #387(feat: generate compile database without building)承接 —— 该 PR 已实现 --configure-only、CDB 原子发布(platform::fs::replace_file,POSIX rename / Windows MoveFileExW)、tests/** 与 dev-dependency 覆盖。当前状态:OPEN / CHANGES_REQUESTED / 2 条红 e2e(e2e 1/2 linux 与 e2e 1/2 windows)。

注意 C-1 与 PR #387 正交但同文件:#387 让 configure-only 绕开 fast path,但没有修 normal build 的 fast path 漏 CDB。两者都改 src/build/execute.cppm,需要排序(建议 #387 先落地)。

D-2 · #313 未交付的两条

  • 建议 3(help 一级标题着色):src/cli.cppm:50 的 print_usage()。若要做,色码应只有一个产地(src/ui.cppm 加 heading(),复用 with_color),且必须先修 C-3,否则 mcpp --help --no-color 仍会出色。
  • 建议 7(CMake ↔ mcpp 互转译):按维护者结论走 Agent Skill(.agents/skills/ 下今天只有 mcpp-usage / mcpp-contributing / mcpp-release),不做 CMake 解析器。可参考 增设关闭src自动扫描字段 - mcpp.toml 使用问题 #386 报告人正在做的 cmake2mcpp。

D. 保持 open 的 18 条

#396 #393 #392 #386 #380 #379 #374 #373 #370 #304 #293 #290 #284 #283 #276 #259 #256 #215

(另有 #43、#260 两条按约定保留,不在核验范围内。)

核验结论:没有一条是「已修复」或「过时」。逐条的根因、当前代码状态(带 file:line)、修法与回归判据在 .agents/docs/2026-08-09-issue-triage-full-sweep.md。

几条判定要点:


E. 方法与边界

27 个 agent、1594 次工具调用;每条事实主张落到当前 file:line,issue 原文的行号平均漂移两到三个版本,一律重新定位。对判为「可关闭」的结论各派两名独立反驳者(代码事实 + 报告人视角),不确定默认推翻 —— 上表 6 条关闭全部是在残留项有了本 issue 这个去处之后才成立的。

未核项:#290 的 check_llamacpp_snapshot.py 主张(未 checkout mcpplibs/llama.cpp-m);#382 的 GPU 加速路径(无 WSL2 / 无 Intel GPU,mesa 25.0.7.2 的 d3d12/iris 在 payload 里但从未被执行过)。

/cc @Sunrisepeak

Activity

  1. speak-agent commented on Aug 8, 2026

    @speak-agent
    MemberAuthor

    PR 清理补充(speak-agent / 2026-08-09)

    Issue 收口完成后,又对当前全部 5 个 open PR 做了一轮合入门禁复核。基线仍是 main@80291ca01a98;本轮 0 个 PR 合并,原因不是权限或按钮状态,而是没有一条同时满足「方向允许、非 Draft、无冲突、review 通过、实际 CI 全绿」。

    PR 处置 证据
    #272 保持 open,不合并 MERGEABLE 但 REVIEW_REQUIRED,且从未产生 CI checks;维护者已明确留言「先保留,后面看真实使用再评估」。当前默认 sources、lib-root 约定及文档仍只承认 .cppm,PR 的 e2e 也必须显式列出 .ccm/.cxxm/.ixx,不能把它表述成默认完整支持。
    #351 特殊保留,不动 Draft + CONFLICTING + do-not-merge;标题已明确「RFC(勿合入)」,属于探针/设计证据。
    #353 CI 阻断,不合并 18 条既有 checks 为绿,但 ci-aarch64-fresh-install 失败。用 gh run rerun 30914588943 --failed fresh 重跑后仍失败(job 93164930354):刷新后的索引只提供 mcpp@2026.8.8.4,自举当前 main 却请求 mcpp@2026.8.6.2,报 version '2026.8.6.2' not found。因此不是可忽略的历史红灯。
    #372 保持 Draft,不合并 Draft + CONFLICTING;维护者已明确要求本 PR 不继续推进,A 部分拆出,协议方向归 #379。
    #387 修复后再评估 非 Draft,但 CONFLICTING + CHANGES_REQUESTED,并有 2 条失败 E2E;它是 #372 拆出的 A 部分,也是 #371 真正剩余能力的承载点。

    本轮实际 GitHub 写动作

    后续最短路径:先让 #387 解冲突并修掉 review/两条 E2E;#353 则要先修 fresh-install 自举对「历史精确版本已被索引淘汰」的脆弱依赖,再重新跑全绿。当前证据不支持 admin merge 或跳过 CI。

  2. speak-agent commented on Aug 9, 2026

    @speak-agent
    MemberAuthor

    2026.8.10.1 发布收口 —— 残留项登记

    PR #400 已 squash 合入(0006ce6),
    v2026.8.10.1 已发布并核验。本轮关闭:#398(随 PR)、#380、#396、#401。
    #392 已留证据但未关(症状环境相关,等原报告者在 2026.8.10.1 上复核)。

    以下是我做不了或按设计不该由我做的残留项。

    R-1 · 索引 bump PR 需要维护者合并 ⚠️ 阻塞索引传播

    openxlings/xim-pkgindex#588
    (bump(mcpp): track 2026.8.10.1 as latest)15/15 检查全绿,diff 只动
    pkgs/m/mcpp.lua,四个平台的 sha256 我已独立复算并与已发布 payload 逐一比对一致:

    linux-x86_64   b7e0d51c0c5a…
    linux-aarch64  991b6fd28cdd…
    macosx-arm64   72eeb3c8c998…
    windows-x86_64 de04a0330d53…
    

    speak-agent 在该仓没有 MergePullRequest 权限,--admin 也被拒。
    在它合并之前,xlings install mcpp@2026.8.10.1 拿不到新版本
    (install.sh / GitHub release / 两个镜像都已经可用,不受影响)。

    R-2 · AUR 首次发布需要一次有人盯着的手工放行(按 D3 的设计)

    aur-publish 在 release 之后自动跑了,并且正确地只报告、没有推送 —— 这是本轮加的
    布防门第一次在生产上生效:

    AUTOPUBLISH:
    ::notice::AUR_AUTOPUBLISH is not set — reporting the desired state without publishing.
    --- mcpp-bin desired-state diff ---
    -	pkgver = 2026.8.1.1
    +	pkgver = 2026.8.10.1
    

    按设计,第一次真实对外推送应该是有人看着的一次:

    gh workflow run aur-publish.yml -R mcpp-community/mcpp -f publish=true
    

    确认 AUR RPC 可见、.SRCINFO、两个架构 checksum、干净 Arch 容器安装之后,
    再设仓库变量 AUR_AUTOPUBLISH=true 打开定时收敛。取消该变量就是 kill switch,
    不需要 revert 任何代码。

    R-3 · xlings 2026.8.10.1 冷装 gcc 失败 ⚠️ mcpp 的 xlings pin 因此停在 2026.8.9.2

    openxlings/xlings#524。
    同一 workflow、同一 runner 镜像、两次都确认 cache miss 的 A/B:2026.8.9.2 冷装成功,
    2026.8.10.1 冷装失败(依赖解析下载 glibc 2.44,gcc 的 config hook 找不到该 payload)。
    修复发布后,用独立 commit 把 pin 提上去并重跑全矩阵。

    这条本身是个判据:「pin 到最新」是一个需要被验证的动作,不是一次文本替换。
    它能被抓到,只是因为换 pin 同时换掉了 CI 缓存键,把冷启动路径暴露了出来。

    R-4 · 图形栈:GLX vendor 可达性 ⚠️ 目前跑不出 GL context

    openxlings/xlings#525。

    隔离 home + xlings install -y graphics(NVIDIA 550.144.03,35 包)之后,
    官方 imgui 模板 app 构建通过,mcpp why runtime 的 requirement / provider /
    provenance / link intent / SubOS 图形环境 / post-link 闭包校验全部正确,
    但运行时 GLX: No GLXFBConfigs returned。

    定位:<subos>/lib/libGLX_nvidia.so.0 装了,但 payload 的 libGLX.so.0 在 dlopen 时
    够不到 —— SubOS 只声明了 EGL vendor 目录,没有 GLX 侧等价物。
    而且不能用 LD_LIBRARY_PATH 兜(那目录同时含私有 glibc,一放上去宿主二进制立刻死于
    __pointer_chk_guard,#401 原样复现)。正解是 payload 侧 RPATH ——
    xim 自己在安装时打印的警告就是这么说的。

    mcpp 侧在这条链上没有待办:它消费的是规范化后的 provider 事实,没有探测 GPU/driver,
    诊断出口也正确指向 xlings doctor。

    R-5 · 裸名过渡期在 2026.9 移除

    kBareNameFallbackRemovedIn = "2026.9"。到期时删掉
    legacy_bare_candidates 及其两个调用点、tests/unit/test_pm_bare_name_window.cpp
    (独立文件就是为了让删除是一次删除而不是考古),并把 162 的第 5 节改回硬失败。

    R-6 · 一个待复核的覆盖盲区

    本轮发现:身份/索引路由的 e2e 全部要 gcc 或 fresh-sandbox,而 Windows 两者皆无 ——
    路径语义真正不同的平台,恰好是从不断言它的平台。已新增
    210_local_index_addressing_on_every_host.sh(无编译器、无沙箱、无网络,三平台都跑)
    和 00_fixture_path_hygiene.sh(lint)。值得再扫一遍 # requires:,看还有没有别的
    断言被挡在它最该跑的平台之外。

  3. speak-agent commented on Sep 20, 2026

    @speak-agent
    MemberAuthor

    Status of section B (the nine defects this issue was opened to hold), re-measured on origin/main at 05d03cd / 2026.9.18.3. Four are closed, three still reproduce, and one has moved elsewhere. Recorded here so the next reader does not re-derive any of it.

    Closed.

    Still reproduces on 2026.9.18.3. All three measured, not read.

    • C-1 — a fast-path hit never rebuilds compile_commands.json.

      $ mcpp new cdbdemo && cd cdbdemo && mcpp build   # CDB written
      $ rm compile_commands.json && mcpp build
          Finished dev in 0.00s
      $ ls compile_commands.json
      ls: cannot access 'compile_commands.json': No such file or directory

      write_compile_commands still has its single call site inside NinjaBackend::build() (src/build/ninja_backend.cppm:3067), which the fast path does not enter. The freshness gate in try_fast_build / try_fast_run has since grown several inputs — the SubOS manifest's mtime, dependency source roots, the validated-artifact snapshot — and every one of them is an input. The class the issue named is still missing: fresh inputs do not imply complete outputs.

    • C-3 — --no-color is still a no-op on a TTY. disable_color() (src/ui.cppm:239) sets g_color = false and leaves g_inited false, so the first init() recomputes from detect_color(), which returns is_tty(). Measured under a pty:

      $ script -qec "mcpp build --no-color" /dev/null | cat -v | grep -c '\^\['   # 1
      $ script -qec "mcpp build"            /dev/null | cat -v | grep -c '\^\['   # 1

      Same count with and without the flag. MCPP_NO_COLOR and NO_COLOR are unaffected, because they are read inside detect_color(). The fix is still one line, and the warning in the original text still holds: a test routed through a pipe cannot see this, so the criterion has to assert on ui:: output directly.

    • C-4 — [modules].exports validation is still a silent no-op for any namespaced package. src/modgraph/validate.cppm:98 compares u.packageName == manifest.package.name, and src/modgraph/scanner.cppm:1207-1210, 1273, 1320 still fill u.packageName with the qualified name. So namespace = "acme" makes actual the empty set and neither the plain check nor strict ever fires.

    Moved. C-9's ${mcpp.out_dir} rows belong to #393, which is still open and still unfixed (src/build/prepare.cppm:13454 replaces with outputDir.string(), unnormalised).

    Leaving this issue open: C-1, C-3 and C-4 have no other home.

  4. speak-agent commented on Sep 26, 2026

    @speak-agent
    MemberAuthor

    Item C-1 (a fast-path hit never rebuilds compile_commands.json) is fixed in mcpp 2026.9.26.2 (#702, squash c109fdd6).

    • Each configuration now keeps its own database under target/<triple>/<fingerprint>/compile_commands.json.
    • The root file is a copy of that database.
    • mcpp build, the fast path included, restores a missing root file from the configuration's database without planning.

    e2e 781 fails on 2026.9.26.1 and passes on 2026.9.26.2. It also passes in an xlings sandbox against the published binary. The same item is B1 of #677.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions