diff --git a/.agents/docs/2026-07-08-index-side-adoption-plan.md b/.agents/docs/2026-07-08-index-side-adoption-plan.md new file mode 100644 index 0000000..a938ca6 --- /dev/null +++ b/.agents/docs/2026-07-08-index-side-adoption-plan.md @@ -0,0 +1,90 @@ +# Index-side adoption plan — mcpp 0.0.85 train (floor, strict lint, scan_overrides, long brackets) + +Companion to mcpp repo +`.agents/docs/2026-07-08-descriptor-index-evolution-roadmap.md` (master) and +its two design docs (same date). This doc is the mcpp-index execution detail. + +Rule of the whole rollout: **floor first, new grammar/keys after** — enforced +mechanically by lint once P1 lands (lint parses with the pinned mcpp; before +the pin reaches 0.0.85, new-grammar descriptors cannot merge). + +--- + +## P0 — merge PR #63 as-is (pre-train) + +fmt 12.2.0 via `generated_files` works on today's 0.0.81 (verified locally +2026-07-08: lint pass, sha256 match, member test green, generated file = +upstream `src/fmt.cc` minus exactly the `import std;` guard). Don't couple it +to the train; migrate it in P2. + +## P1 — floor PR (single atomic PR) + +1. `index.toml` at repo root: + + ```toml + [index] + spec = "1" + min_mcpp = "0.0.85" + latest_mcpp = "0.0.85" + ``` + +2. `.github/workflows/validate.yml`: `MCPP_VERSION` 0.0.81 → 0.0.85. +3. lint job: add the pinned-mcpp download step (same snippet as the workspace + job) and run `mcpp xpkg parse --strict` over changed (PR) / all (push, + nightly) descriptors — **in addition to** the existing `lua5.4 loadfile` + check (the xim side executes real Lua; both grammars stay guarded). +4. `tools/publish_mcpp_index.sh`: pack `index.toml` into the artifact tree + (one `cp` next to the existing `pkgs/` copy). Pointer untouched. +5. `docs/repository-and-schema.md`: floor paragraph (what breaks for + pre-0.0.85 clients, why now). + +## P2 — fmt: generated_files → scan_overrides + +`pkgs/f/fmtlib.fmt.lua` descriptor `mcpp` segment becomes: + +```lua +mcpp = { + schema = "0.1", + language = "c++23", + import_std = true, + modules = { "fmt" }, + include_dirs = { "*/include", "*/src" }, + sources = { "*/src/fmt.cc" }, -- upstream file, verbatim + cxxflags = { "-DFMT_IMPORT_STD" }, + scan_overrides = { + ["*/src/fmt.cc"] = { provides = { "fmt" }, imports = { "std" } }, + }, + targets = { ["fmt"] = { kind = "lib" } }, +} +``` + +- Deletes the 3.4 KB escaped `generated_files` copy entirely. +- `tests/examples/fmtlib.fmt/` member unchanged — it is the live CI proof + (also the matrix's first `import_std = true` package build on mac/win). +- mcpp-side reconciliation (mandatory for override files) audits the declared + `(provides, imports)` against the compiler's `.ddi` every build. + +## P3 — long-bracket migrations (one PR per package) + +`pkgs/n/nlohmann.json.lua`, `pkgs/c/compat.eigen.lua`: `generated_files` +escaped strings → `[==[ … ]==]`. Mechanical; reviewer checks the parity +oracle output (content via lua5.4 == content via `mcpp xpkg parse --json`), +which the lint step re-verifies anyway. + +## P4 — docs refresh + +`docs/repository-and-schema.md`: +- replace "`generated_files` … 不支持 `[[…]]`" with: long brackets require + mcpp ≥ 0.0.85 (index floor guarantees this; lint enforces). +- new row in the case-index table: "guarded-import module unit → + `scan_overrides`" pointing at `pkgs/f/fmtlib.fmt.lua` post-P2. +- mention `mcpp xpkg parse --strict` as the local reproduction of lint. + +## Verification / rollback + +- Every PR rides the existing `mcpp test --workspace` 3-OS matrix. +- P1 is the only PR with blast radius (floor + version bump together): if + 0.0.85 misbehaves in CI, revert P1 alone restores the 0.0.81 world; P2/P3 + cannot have merged yet (lint gate). +- CN mirror for fmt (from PR #63 review) remains a separate follow-up via + gtc/mcpp-res — unrelated to this train. diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 32bef31..a23f2ad 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -13,7 +13,7 @@ on: env: # Bumped to 0.0.78: carries L3 build.mcpp native build program (build-mcpp member), # compat.openblas Windows recipe (bin/libopenblas.dll staged beside the .exe). - MCPP_VERSION: "0.0.81" + MCPP_VERSION: "0.0.85" jobs: lint: @@ -59,6 +59,30 @@ jobs: done [ $fail -eq 0 ] && echo "All package files valid." exit $fail + # ── Single-source-of-truth grammar check ───────────────────────── + # `mcpp xpkg parse` uses EXACTLY the resolver's parser, so what + # passes here is what builds for users of the pinned MCPP_VERSION. + # Strict by default: unknown mcpp-segment keys fail (they would be + # silently ignored at build time). This also mechanically enforces + # the rollout rule "floor first, new grammar after": descriptors + # needing a newer grammar cannot pass a lint pinned to an older mcpp. + - name: Download pinned mcpp + run: | + curl -L -fsS -o mcpp.tar.gz \ + "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz" + tar -xzf mcpp.tar.gz + echo "MCPP=$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/bin/mcpp" >> "$GITHUB_ENV" + - name: Parse descriptors with the resolver grammar (mcpp xpkg parse) + run: | + fail=0 + for f in pkgs/*/*.lua; do + if ! "$MCPP" xpkg parse "$f" > /dev/null; then + echo "::error file=$f::mcpp xpkg parse failed (resolver grammar)" + fail=1 + fi + done + [ $fail -eq 0 ] && echo "All descriptors parse with mcpp ${MCPP_VERSION}." + exit $fail mirror-cn-reachable: # Closed-loop guard for the CN mirror: every CN url referenced by a @@ -111,20 +135,20 @@ jobs: include: - platform: linux os: ubuntu-latest - archive: mcpp-0.0.81-linux-x86_64.tar.gz - root: mcpp-0.0.81-linux-x86_64 + archive: mcpp-0.0.85-linux-x86_64.tar.gz + root: mcpp-0.0.85-linux-x86_64 mcpp: bin/mcpp xlings: registry/bin/xlings - platform: macos os: macos-15 - archive: mcpp-0.0.81-macosx-arm64.tar.gz - root: mcpp-0.0.81-macosx-arm64 + archive: mcpp-0.0.85-macosx-arm64.tar.gz + root: mcpp-0.0.85-macosx-arm64 mcpp: bin/mcpp xlings: registry/bin/xlings - platform: windows os: windows-latest - archive: mcpp-0.0.81-windows-x86_64.zip - root: mcpp-0.0.81-windows-x86_64 + archive: mcpp-0.0.85-windows-x86_64.zip + root: mcpp-0.0.85-windows-x86_64 mcpp: bin/mcpp.exe xlings: registry/bin/xlings.exe steps: diff --git a/docs/repository-and-schema.md b/docs/repository-and-schema.md index 9e998d5..8fff690 100644 --- a/docs/repository-and-schema.md +++ b/docs/repository-and-schema.md @@ -47,13 +47,26 @@ tools/gtc gitcode CLI,见 cn-mirror.md | `c_standard` | C 源码:`"c99"` 或 `"c11"` | | `modules` | module 库:`{ "x.y" }` | | `include_dirs` | glob 列表,暴露给消费者的头目录 | -| `generated_files` | `{ ["相对路径"]="内容字符串" }`;不支持 `[[…]]`,须以 `\n`、`\"` 转义 | +| `generated_files` | `{ ["相对路径"]="内容字符串" }`;mcpp ≥ 0.0.85 支持 Lua 长括号 `[==[…]==]` 多行字符串(推荐,可读可 review);转义单行串仍兼容 | +| `scan_overrides` | `{ ["glob"]={ provides={…}, imports={…} } }`;声明式扫描结果,命中文件跳过 M1 文本扫描(适用于带条件 import 守卫的上游模块单元,如 fmt 的 src/fmt.cc);构建期由编译器 P1689 输出自动对账,声明错误响亮失败(mcpp ≥ 0.0.85)| | `sources` | glob 列表,编入 lib 的源码 | | `cflags` / `cxxflags` / `ldflags` | 追加至对应规则 | | `targets` | `{ ["name"]={ kind="lib"/"bin", main=…, soname=… } }` | | `features` | `{ ["f"]={ sources={…} } }`,仅识别 sources | | `deps` | `{ ["ns.name"]="ver" }`,扁平或点号式 | +## index 版本契约(index.toml) + +仓库根的 `index.toml` 声明 `[index] min_mcpp` —— 能解析本索引全部描述符的最老 +mcpp 版本。契约随树旅行:`publish_mcpp_index.sh` 把它打进 artifact,git clone 与 +`[indices] path =` 本地索引天然携带。mcpp ≥ 0.0.85 在打开索引树时检查,违反时报 +`E0006` + 升级指引(调试逃生口 `MCPP_INDEX_FLOOR=ignore`)。 + +规则(由 lint 机械强制,非纪律):**floor 先行、新文法在后**——lint 用 CI pin 的 +mcpp 跑 `xpkg parse`(strict:未知键即失败),所以需要更新文法/键的描述符在 +`MCPP_VERSION` 与 `min_mcpp` 同步提升之前物理上合不进 main。本地复现: +`mcpp xpkg parse pkgs//.lua`。 + ## CI 行为(validate.yml) - 触发条件:PR(改动 `pkgs/**/*.lua`、`tests/**`、`README.md` 或本 workflow)、push 至 main、nightly cron、手动触发。 diff --git a/index.toml b/index.toml new file mode 100644 index 0000000..3230b75 --- /dev/null +++ b/index.toml @@ -0,0 +1,11 @@ +# Index→client version contract (design: mcpp .agents/docs/2026-07-08-index- +# version-semantics-and-descriptor-grammar-design.md D3). The contract travels +# WITH the index tree: packed into the artifact, present in git checkouts and +# path-indices alike. mcpp >= 0.0.85 checks it at the index-open choke point +# (E0006 on violation). Bump min_mcpp ONLY together with the CI MCPP_VERSION +# pin — lint parses descriptors with the pinned mcpp, which enforces the +# "floor first, new grammar after" rollout rule mechanically. +[index] +spec = "1" +min_mcpp = "0.0.85" +latest_mcpp = "0.0.85" diff --git a/tools/publish_mcpp_index.sh b/tools/publish_mcpp_index.sh index 58eeec3..a157b2f 100755 --- a/tools/publish_mcpp_index.sh +++ b/tools/publish_mcpp_index.sh @@ -25,6 +25,9 @@ info() { echo "[mcpp-index] $*"; } TREE="$OUT/tree"; mkdir -p "$TREE" cp -a "$SRC/pkgs" "$TREE/" [ -f "$SRC/README.md" ] && cp "$SRC/README.md" "$TREE/" || true +# index.toml carries the index→client version contract (min_mcpp floor); +# it must travel with the tree so unpacked snapshots enforce it offline. +[ -f "$SRC/index.toml" ] && cp "$SRC/index.toml" "$TREE/" || true tar --sort=name --owner=0 --group=0 --numeric-owner -czf "$OUT/$BASE.tar.gz" -C "$TREE" . 2>/dev/null \ || tar -czf "$OUT/$BASE.tar.gz" -C "$TREE" . SHA="$(sha256sum "$OUT/$BASE.tar.gz" | awk '{print $1}')"