状态:路线 B 已拍板执行并落地(2026-09-28 批)——vendor 搬迁 + 漂移探针 + moon.mod 依赖块清空,全量防线复跑与 0.6.0 收官基线逐位一致。§1–§4 为 2026-09-27 会话实测产出(决策依据,数字为当时快照);§8 为落地记录。
关联:MoonBit迁移总计划 §4 包切分总图(L0–L9)| 脚本总清单与必跑防线(新增探针的入册义务)|
scripts/toolchain_probe/(探针形态与--update-baseline模板)| MoonBit工具链漂移处置手册(处置流程同构参照)
0. 摘要
- 事实:
vitro/engine的唯一外部依赖是moonbitlang/x@0.5.5;消费面仅 5 个 cmd 工具包,且只用到其中的x/fs子模块 7 个函数。引擎核心包(lexer→vm 全链)零消费。 - 可清除性:可清除。MoonBit core 无文件 IO 能力(实测包列表),故实现必须自持——要么自写,要么把上游实现 vendor 进本模块。
- 本次实测新发现:上游
moonbitlang/x的fs/fs_native.mbt已漂移,且上游未 bump 版本号(main 的moon.mod仍是0.5.5)——「只盯版本号」的探针会漏报,漂移检测必须走文件内容哈希口径。 - 推荐:路线 B(vendor 上游 + 漂移探针),时机在 0.6.0 发布之后(0.6.0 彩排已过,此刻动依赖=重新彩排)。
- 收益定位:清除的目标不是省一次下载,而是把发布链路上「必须正确的外部引用数」归零——deps 字段、传递解析、端口版本对账、第三方 registry 存续绑定一并消失。
1. 依赖现状(2026-09-27 实测)
1.1 形状
| 项 | 实测值 | 证据 |
|---|---|---|
| 声明位置 | moonbit/moon.mod 唯一一条 import { "moonbitlang/x@0.5.5" } |
亲读 |
| 引入时点 | commit 765b4c0(2026-09-19,S2 词法器片收官批) |
git log -S'"moonbitlang/x@0.5.5"' |
| 引入后变更 | 从未升级(0.5.5 至今) | 同上 |
| 上游 license | Apache-2.0(每个源文件头带声明) | 亲读 .mooncakes/moonbitlang/x/fs/fs.mbt:1-13 |
| 上游包性质 | 模块自述「experimental packages for moonbitlang/core」 | 亲读 moon.mod description |
1.2 消费面:5 包 × 7 函数(2026-09-27 实测)
消费者全部是 cmd 可执行包,全部 supported_targets = "native":
| cmd 包 | 行数 | 入口职责 |
|---|---|---|
vitro/engine/cmd/dump_tokens |
138 | 词法 dump |
vitro/engine/cmd/dump_ast |
160 | AST dump |
vitro/engine/cmd/dump_typeck |
211 | 类型检查 dump |
vitro/engine/cmd/dump_compile |
194 | 编译产物 dump |
vitro/engine/cmd/run |
184 | D 级运行期对拍 runner(vm_diff / clang_direct 的消费端) |
x/fs 提供 11 个 pub fn,Vitro 实际使用其中 7 个(调用点约 38 处,全部在 5 个 main.mbt 内):
| 函数 | 调用点 | 用途 |
|---|---|---|
read_file_to_string |
9 | 读源文件 / 读 VFS 输入 |
is_dir |
8 | 目标路径判定 |
read_dir |
7 | 目录批量遍历(dump 四包) |
write_string_to_file |
5 | 写 dump 产物 |
create_dir |
4 | 建输出目录 |
path_exists |
4 | 输出目录存在性 |
write_bytes_to_file |
1 | --dump-memory 二进制出口 |
引擎核心零消费:lexer / parser / typeck / codegen / bytecode / memory / host / vm 等包均不 import x——依赖只存在于「工具壳层」。
1.3 上游漂移已发生(本次实测新发现)
用 raw 拉上游 main 的 3 个 fs 文件与本地锁定 0.5.5 做 sha256 比对(2026-09-27 实测):
| 文件 | 上游 main vs 本地 0.5.5 | 结论 |
|---|---|---|
fs/fs.mbt |
哈希一致(41d895c7…) |
未变 |
fs/fs_native.c |
哈希一致(f10144a5…) |
未变 |
fs/fs_native.mbt |
不一致(上游 5f20626e… / 本地 29dbb4f9…) |
已漂移 |
差异内容:上游把 @unicode.to_utf8_bytes / @unicode.to_utf8_string 换成了 @utf8.encode / @utf8.decode_lossy(依赖从 moonbitlang/x/unicode 迁到 moonbitlang/core/encoding/utf8)。
且这是语义变更,上游 CHANGELOG 原文记载(Unreleased 段):解码器把非法 UTF-8 输入替换为 U+FFFD,而非静默截断尾部字节;@fs.read_file_to_string 行为随之改变。
两个直接影响结论:
- 版本号口径失效:上游改了内容但
moon.mod的 version 仍是0.5.5(未发版)——只比对版本号的探针在此案例中零报警。 - 跟进可行性已验证:本机 core
0.10.14+7d59c7ec9含encoding/utf8(有encode/decode_lossy),上游新写法在本机工具链下可编译。
1.4 为什么值得清除:四条结构性成本
- 发布件的 deps 字段成为必对非平凡字段。0.6.0 彩排实证:手工投放的 index 行漏写
deps: {"moonbitlang/x": "0.5.5"}即报Cannot find import 'moonbitlang/x/fs' in cmd/dump_ast解析失败。该坑根因是手工投放(真实moon publish会自动上报 deps),但依赖的存在把该字段从「可空平凡字段」变为「每次发版必须联动的对账点」。 - 安装可用性绑定第三方 registry 存续。mooncakes 上传后 checksum 不可覆盖、发错无法撤回;只要 deps 挂着外部版本,一旦该版本从 registry 消失,全部历史版本的
vitro/engine安装同时失效。零依赖发布件才是真正自包含制品。 - 下游连带拉整个 x 模块。mooncakes 是模块级粒度:下游
moon add vitro/engine会连带拉入x的 bcrypt / crypto / jwt / json5 / time 等全部子包源码,只为其中 1 个 fs。清除后 index 行 deps 可空,下游零连带。 - 镜像 / 内网场景多一个同步点:私有 registry 镜像需额外同步第三方模块,清除后发布件单点自包含。
1.5 反面事实:为什么这不是高息债
诚实计价,避免夸大紧迫性:
- cmd 包是 native-only 工具层,不参与下游 wasm-gc 制品的编译链接——依赖只存在于「安装期」,不影响任何出口制品。
x是 moonbitlang 官方仓库且版本锁定,供应链风险低于任意第三方。- 0.5.0(25 次下载)起就带着该依赖发布,历史版本已被下游拉取过——清除的收益只及未来下游,无追溯性。
结论:它伤的是发布纯净度与供应链面,不是制品正确性。值得做,不值得为此打乱发版节奏。
2. 决定路线集的硬约束(2026-09-27 实测)
| # | 约束 | 实测证据 | 对路线的影响 |
|---|---|---|---|
| 1 | core 无文件 IO | core 包列表无 fs/io 包(encoding 下有 ascii/base64/hex/percent/utf16/utf8,均非文件系统能力);x/fs 是生态唯一来源 |
不存在「改用 core」的捷径;必须自持实现(自写或 vendor) |
| 2 | Windows 宽字符路径 | 上游 native 分支走 _wfopen / _wmkdir / _wremove / _wrmdir / FindFirstFileW + UTF-16 转换(fs_native.c) |
任何自写实现必须复制宽字符路径,否则中文用户名等非 ASCII 路径直接失败 |
| 3 | 双平台防线义务 | CI 在 ubuntu 跑 native cmd(vm_diff / clang_direct 的消费端),本机是 Windows | 实现必须两平台全绿,防线一条不能少跑 |
| 4 | publish 无包级排除 | moon publish --help 无 exclude 选项(发布最小单位=整个模块) |
「cmd 留仓内但不进发布件」不可行;摘依赖只能把实现搬进本模块(或拆模块,见路线 C) |
| 5 | read_dir 顺序本就两平台不一致 | 上游 Windows 用 FindFirstFileW 收集、POSIX 用 readdir;dump 四包的用途是产出各自独立的 JSON 文件,顺序不敏感 |
自持实现可自由定序(排序返回更稳);不构成阻塞 |
| 6 | 分层闸管新包 | scripts/moonbit/pkg_deps/rules.json:level(D) <= level(P),cmd/* 豁免可依赖任意层;未登记新包即红 |
新包须登记分层(L0 候选)并同步总计划 §4 |
| 7 | 无主 pub 闸管对外面 | scripts/moonbit/moonbit_surface/(无主 pub 白名单双面闸) |
新包 pub 面必须收窄到实际被消费的函数,否则产生无主 pub 触发闸 |
3. 路线
路线 A — 自写原生 mini-fs(零上游,零 vendor)
做法:新建 native-only 包,自己实现 7 个函数 + C stub。参考上游已趟平的宽字符路径,但不逐字复制。
工作量:约 300–400 行(MoonBit 绑定 + C stub),含错误处理与双平台分支。对照:上游 native 分支三文件合计 691 行(fs.mbt 173 + fs_native.mbt 231 + fs_native.c 287),扣除注释与全平台冗余后为该估算提供锚点(估算,非实测)。
代价:
- 正确性从零自证:宽字符转换、边界(空文件 / 大文件 / 目录不存在)、错误码映射都要自己的测试锚。
- 永久自维护:上游修 bug 我们不会自动受益。
- ⚠️ 合规提醒:读过上游实现之后,所谓「自写」已非 clean-room。若实质参考了上游设计,Apache-2.0 的来源标注义务不可省(「自写就无 license 负担」是幻觉)。
收益:无任何上游绑定,探针义务为零;实现面可控(只做 7 函数)。
风险:中。新写的 C stub 是安全相关代码,边界 bug 可能只在非 ASCII 路径 / 大文件上暴露。
路线 B — Vendor 上游实现 + 漂移探针(推荐)
把上游 fs 的实现 vendored 进本模块(等价搬迁),配一个盯上游漂移的探针。
B-1 vendor 边界
拷贝 3 个文件 + 测试:
| 上游文件 | 行数 | 处置 |
|---|---|---|
fs/fs.mbt(平台无关 API 层) |
173 | 拷入,pub 面收窄 |
fs/fs_native.mbt(native 实现) |
231 | 拷入,Windows / POSIX 双分支全保留 |
fs/fs_native.c(C stub) |
287 | 拷入,符号前缀改名 |
fs/blackbox_test.mbt |
105 | 测试随迁(转项目测试体系形态) |
不拷:fs_js.mbt(331 行)/ fs_wasm.mbt(296 行)——本项目 cmd 是 native-only,不需要 js/wasm 分支。
B-2 机械改造点(七项)
- 包名与路径 →
vitro/engine/<新包名>。候选:vitro/engine/fs:import 别名自动为@fs,5 个main.mbt零改动(只改 moon.pkg);vitro/engine/hostfs:语义更清晰(与 host 包的Vfs虚拟文件系统区分),代价是 38 处@fs.机械替换为@hostfs.。- 取舍:别名零改动 vs 命名清晰。两案均可行,落地时二选一。
- UTF-8 依赖指向 core:
@unicode.to_utf8_*→@utf8.encode/@utf8.decode_lossy(moonbitlang/core/encoding/utf8,本机0.10.14+7d59c7ec9已验证存在)。这同时消掉了 x 内部的unicode子包依赖,vendor 边界得以闭合在这一层。 - C 符号前缀:
moonbitlang_x_fs_*→ 本模块前缀(避免与任何同时链接的 x 版本符号撞名)。 - file 头合规:保留 Apache-2.0 文件头,追加来源标注(上游 repo / 版本 / 改动摘要),LICENSE 或 THIRD_PARTY 说明附 Apache-2.0 全文。
- pub 面收窄到 7 函数 +
IOError(约束 7 的双面闸要求;未消费的read_file_to_bytes/is_file/remove_dir/remove_file不 pub)。 - moon.pkg:
supported_targets = "native"+options("native-stub": ["fs_native.c"])+ import core utf8。 moon.mod删依赖:import块清空——发布件自包含,deps 字段消失(1.4 的四条成本一并归零)。
B-3 漂移探针设计(vendor_drift)
形态对齐 toolchain_probe(本项目已有模板):脚本目录 = main.go + main_test.go(J9),基线文件外置、首行 # @generated by … --update-baseline,CI 落 hygiene job(判据原文:「红了是否意味着这一批提交不能要——否则归 hygiene」;上游漂移=代码没坏、是该评估跟进,属记账型)。
双层口径(本设计由 1.3 的实测直接推导):
| 层 | 检测 | 退出语义 |
|---|---|---|
| 层 1(主口径)内容哈希 | 拉上游 main 的 3 个文件(raw.githubusercontent.com,无速率限制),sha256 与基线记录比对;不等即红,打印 diff 摘要 + 上游 CHANGELOG 相关条目 |
exit 1 = 漂移 |
| 层 2(辅助)版本号 | 上游 moon.mod 的 version 与基线记录比对 |
仅报告,不单独判红(1.3 实证该口径会漏报) |
基线条目(外置 JSON,scripts/moonbit/vendor_baseline.json 候选):
as_of / 上游 repo / 跟踪 ref(main)/ 上游版本号 / 每个被跟踪文件的 path + sha256 + 对应 vendored 文件。
退出码契约(fail loud、禁静默 default):
0上游与基线一致;1漂移(内容哈希不等,或文件被删除/移动=404 结构变更);2无法判定(网络失败 / 超时)——与「漂移」区分,避免把网络抖动误报成上游变更。
J9 义务:探针必须先证红——篡改基线哈希 → 必须 exit 1;断网 / 假域名 → 必须 exit 2。与 toolchain_probe_test.go 同构。
B-4 跟进流程(红之后做什么)
探针红 = 评估令,不是自动合并令:
- 读探针输出的 diff 摘要 + 上游 CHANGELOG 条目;
- 裁定:无关改动(如我们不用 js/wasm 分支)/ 有利修复(跟进)/ 有害变更(登记并考虑脱离该改动);
- 跟进则:手工同步 vendored 文件(保留本模块改造点)→ 跑全量防线 →
--update-baseline更新基线 → CHANGELOG 留痕。
与 moon-toolchain-upgrade-playbook 的处置形态同构:探针负责报警,人工负责搬家。
路线 C — 拆第二模块(已判不划算)
做法:把 cmd 及 fs 实现拆成第二个 mooncakes 模块,主模块零依赖。
代价:发布流程 ×2(两个模块各自版本与 CHANGELOG)、CI 与脚本改造、违背 0.6.0 彩排刚确认的「cmd/ 进包」前提(cmd/ 进包 ⇒ 下游连带拉 x 的现状认知)。改动面远大于自写 fs。
结论:不可取,除非未来出现「必须隔离发布」的独立动因。
路线 D — 保留依赖(现状 + 债务登记)
做法:不动。把 1.4 的四条成本登记为已知债,附触发线(如:上游 x 出现破坏性变更 / 发布件因 deps 出事故 / 企业内网镜像需求落地)。
代价:四条结构性成本持续;每次发版多一个对账点。 收益:零投入;不触碰已彩排的 0.6.0 发布面。
适用:0.7.0 排期被更高优先级(S7 协议 / S8 教学)挤占时。
路线 E — 被动等待 core 收敛(观察项,非路线)
x 自述为「experimental packages for core」——长期看 fs 有进入 core 的可能。若成真:依赖对象从「第三方模块 x」变为「随工具链分发的 core」,第三方 registry 绑定与下游连带问题自然消失。
代价:时机不可控,不能作为主路线;仅作为观察项(可在漂移探针的报告里附「core 是否收录 fs」的探查)。
4. 路线对比
| 维度 | A 自写 | B vendor+探针 | C 拆模块 | D 保留 | E 等 core |
|---|---|---|---|---|---|
| 去依赖彻底性 | ✅ 零绑定 | ✅ 零绑定 | ✅ 主模块零 | ❌ | ⏳ 不可控 |
| 新增代码量 | ~300–400 行(自写) | ~690 行 + 测试 105 行(搬迁) | 同 B + 流程改造 | 0 | 0 |
| 正确性起点 | 中(从零自证) | 高(上游已趟平 + 现成测试) | 高 | — | — |
| 上游漂移义务 | 无 | 有(探针 + 人工评估) | 同 B | 无(被动承受) | 无 |
| 发布流程影响 | 无 | 无 | ×2 流程 | 无 | 无 |
| Apache-2.0 合规 | 仍需(读过后非 clean-room) | 明确(保留文件头 + 来源标注) | 同 B | n/a | n/a |
| 与上游同构度 | 低(未来对拍困难) | 高(diff 可读) | 高 | — | — |
| 推荐度 | 备选 | 首选 | 废弃 | 兜底 | 观察 |
为什么 B 优于 A:两者的目标态相同(本模块自持一份 native-only fs),差别在正确性起点与维护形态。B 拿上游趟平的宽字符实现 + 现成测试起步,自证义务只剩「搬迁无损」;且 vendored 内容与上游同构,未来上游修 bug 时 diff 可读、可评估跟进。A 的唯一优势是零上游绑定,但代价是从零自证安全相关代码——而这恰恰是本项目「实测大于脑测」纪律最不划算的用法。
5. 推荐与时机
推荐路线 B,时机与批次:
- 不早于 0.6.0 发布:0.6.0 彩排已过、发版件就绪(
moon.mod已 bump 0.6.0),此刻动依赖=重新彩排;且 0.6.0 记录中「cmd/ 工具在包内引用 x/fs,下游会连带拉 x」的事实应作为发布事实保留。 - 候选批次:0.7.0(或 S7 前的独立批次),工作量与 S6 的 G-1 util 批同量级。
- 落地顺序:探针先行(先建基线与红口径,证红)→ vendor 搬迁(行为等价,防线全绿)→ 删依赖(moon.mod 清空)→ 分层与索引登记。
若排期紧张:走路线 D 并显式登记债务与触发线,不要做「半程」(如只建探针不 vendor、或 vendor 后仍留着 deps 字段)。
6. 路线 B 落地清单(批次分解)
| # | 事项 | 验收锚 |
|---|---|---|
| B-1 | 新建 native-only 包(vitro/engine/fs 或 vitro/engine/hostfs),登记 pkg_deps/rules.json 分层(L0 候选)+ 同步总计划 §4 包切分总图 |
go run ./scripts/moonbit/pkg_deps 绿 |
| B-2 | vendor 3 文件 + 测试;执行 §3B-2 的七项改造(含 pub 面收窄到 7 函数) | 新包测试绿;moonbit_surface 闸绿(无主 pub) |
| B-3 | 5 个 cmd 的 moon.pkg 改 import;若选 fs 包名则 main.mbt 零改动 |
moon build --release --target native cmd/... 全绿 |
| B-4 | 非 ASCII 路径证红→绿:先在旧路径(x/fs)造中文路径用例确认现状行为,vendored 后同用例须同行为 | 新增测试用例(中文用户名 / 空格 / 长路径) |
| B-5 | 漂移探针 scripts/moonbit/vendor_drift/(main + test + 基线 JSON),J9 双路证红(篡改哈希 → exit 1;假域名 → exit 2) |
go test ./scripts/moonbit/vendor_drift 绿 + 埋雷记录入 J9 台账 |
| B-6 | CI 接线(hygiene job)+ 脚本总清单入册(§2.1 或 §2.3 + §1.2 必跑矩阵) | CI hygiene 绿;清单同步 |
| B-7 | moon.mod 删 import { "moonbitlang/x@0.5.5" };双平台防线全量复跑 |
vm_diff / clang_direct / 443 测试全绿;moon.mod 依赖块为空 |
| B-8 | 发布面:CHANGELOG 记录「移除唯一依赖」+ README 包表如涉及 | 0.7.0 发版件(届时) |
7. 风险与诚实边界
- 本文所有数字均为 2026-09-27 时点实测(行数 / 调用点 / 哈希 / 版本号),代码演进后会漂移;引用时须重回现场。
- 探针红 ≠ 必须跟进:上游改动可能是我们不需要的平台分支或有利修复,裁定权永远在人。探针的唯一职责是「不让漂移静默发生」。
- 探针本身有网络依赖:CI 上拉 raw.githubusercontent.com 失败会走 exit 2(无法判定),需人工复查;这与 1.3 的教训同源——别让检测机制自己变成假绿源头。
- 路线 B 的「行为等价」有一个已登记的例外:若选择直接采用上游 main 写法(1.3 的 utf8 迁移),则非法 UTF-8 输入的处理从「截断丢弃」变为「U+FFFD 替换」——需作为显式行为变更登记并评估(对正常源文件无影响,dump 工具读的都是合法源文件)。若要求严格零行为变化,则 vendor 0.5.5 版本并内联两个转换函数(约 30 行,多一份自制解码器)。
- 路线 A 的合规提醒(见 §3A):读过上游实现后「自写」非 clean-room,Apache-2.0 来源标注仍不可省。
- 未覆盖:本文未实测 vendor 搬迁后的编译结果与防线表现(尚无代码),§3B-2 的
@fs别名零改动假设、supported_targets = "native"对全模块构建的影响,均以落地时编译验证为准。 (2026-09-28 补:均已落地验证——见 §8。)
8. 落地记录(2026-09-28 批)
执行顺序按 §5:探针先行 → vendor 搬迁 → 删依赖 → 登记。逐项对照 §6 清单:
| # | 事项 | 落地与验收 |
|---|---|---|
| B-5 | 漂移探针 scripts/moonbit/vendor_drift/(main.go + main_test.go)+ 基线 scripts/moonbit/vendor_baseline.json |
先行落地。双层口径:层 1 内容哈希(四文件:fs.mbt / fs_native.mbt / fs_native.c / blackbox_test.mbt)判红,层 2 版本号仅报告。退出码 0/1/2 = 一致/漂移/无法判定(网络抖动不误报上游变更——首跑实锤:fs_native.mbt 拉取超时走 exit 2 未误报)。J9 双路实跑证红:基线副本篡改哈希 → FAIL——上游漂移(1 处) exit 1;VENDOR_DRIFT_RAW_BASE 假域名 → 无法判定 exit 2;go test(httptest 三态 + 基线形状校验)绿。基线哈希与 §1.3 的 2026-09-27 实测逐位吻合(fs.mbt 41d895c7… / fs_native.mbt 5f20626e…〔上游 main,已漂移版〕/ fs_native.c f10144a5…),上游版本号仍 0.5.5 未 bump(漏报形态再确认) |
| B-1 | 新包 vitro/engine/fs + 分层登记 |
pkg_deps/rules.json levels 加 "fs": 0;闸绿(27 包)。总计划 §4 L0 行已同步 |
| B-2 | vendor 四文件 + 七项改造 | fs.mbt(4 函数去 pub:read_file_to_bytes/is_file/remove_dir/remove_file——保留 priv 由白盒覆盖)/ fs_native.mbt(unicode 四函数内联为 utf8_compat.mbt priv;C 符号前缀 vitro_engine_fs_*)/ fs_native.c(符号前缀同步)/ fs_wbtest.mbt(上游三测试改写转正 + utf8 往返锚 + 0.5.5 截断分界锚 + 非 ASCII 路径锚)+ fs_test.mbt(黑盒 7 pub 函数消费面点名 + IOError raise 锚)。包 9 测试全绿;moon check --target native fs 零警告(包级 -unused_value——priv 保留形态的消费点全在 wbtest,core builtin 同款先例);moonbit_surface 闸绿(26 条 cmd 消费边换 provider 后无红);preferred-backend = "native" 使 mbti 可生成(canonical backend 默认 wasm 会跳过 native-only 包) |
| B-3 | cmd×5 切 import | 五个 moon.pkg 的 "moonbitlang/x/fs" → "vitro/engine/fs"(@fs 别名零改动假设实证成立,main.mbt 一行未动);moon build --release --target native cmd×5 全绿(26 tasks 0 errors,C stub 链接通过) |
| B-4 | 非 ASCII 路径红→绿锚 | vendor 前先跑 x/fs@0.5.5 取证探针(一次性 moon run,Windows native):中文目录+中文文件名+空格路径读写往返无损、read_dir 返回非 ASCII 文件名、remove 后不可见;vendored 后 non_ascii_path_roundtrip 白盒测试复现同一行为,绿 |
| B-7 | 删依赖 + 全量防线 | moon.mod import 块清空。防线复跑与 0.6.0 收官基线逐位一致(当时实测):moon test 504/504(+fs 9);moon check --target all 0 errors;vm_diff 601 = SAME 596 / KNOWN 5 / DIFF 0;clang_direct 696 = SAME 688 / KNOWN 8 / DIFF 0;pkg_deps / moonbit_surface / mbti_sync 闸绿 |
| B-6 | CI + 入册 | ci.yml hygiene job 接 go run ./scripts/moonbit/vendor_drift(toolchain_probe 步后);脚本总清单 §1.1/§1.2/§2.1(27→28)入册;moonbit/AGENTS.md 包表加行;本文档状态翻新 |
| B-8 | 发布面 | moonbit/CHANGELOG.md Unreleased 段建册(随 0.7.0 发布);THIRD_PARTY.md(Apache-2.0 全文 + vendored 清单)随发布件分发 |
落地批的三个执行细节(超出 §3B-2 七项的新事实):
- unicode 内联边界比预估多两个函数:
to_utf8_bytes/to_utf8_string依赖utf16_pair_to_char/char_to_utf16_pair(x/unicode/basic.mbt)——四函数一并内联进utf8_compat.mbt(全 priv),vendor 边界才真正闭合。 - 上游测试的
to_unchecked_string断言是 UTF-16 平台耦合:上游 write_and_read 用@encoding.encode(UTF16, …)写字节再to_unchecked_string()位重解释读回(String 内部 UTF-16);转正改写为直接字节保真断言(read_file_to_bytes == to_utf8_bytes(content)),语义等价且不绑 String 内部表示——首个测试红即此(效汬Ɐ圠牯摬= UTF-8 字节按 UTF-16 码元解释的实锤)。 - 黑盒无自清能力:pub 收窄掉 remove 后黑盒测试不能删自己建的临时目录——
.gitignore补moonbit/fs/tmp_vitro_fs_*/兜底(上游黑盒用 pub remove 自清的形态随收窄不再可用)。
遗留与后续义务:
- ✅ 干净世界终验(2026-09-28 当日补齐):主工作区因 S7 批三号(cmd/serve)并行开发无法跑全模块 moon 命令,改用 git worktree 干净副本(eade61f + 本批、无 serve)完成终验:
moon test504/504(与 README×2 声明一致,testcount闸 PASS);moon check --target all0 errors;moon fmt零漂移;mbti_syncPASS(22 接口面——fs 的pkg.generated.mbti已用_build中 moon 自生权威产物回填替换手工版,moon info --target nativeinspect 确认逐字一致);moonbit_surface/pkg_deps/go test ./scripts/.../go vet全绿;vendor_drift正跑 PASS(exit 0)。 - ✅ gen_svg 包图连坐已验证无需变更:eade61f 的包图重生成时 fs 已在工作区(facts 扫到 27 包),干净世界重生成逐字节一致(0 diff)——L0 行图上只画代表节点(util 同样不在图), 会绿。
- ⚠️ S7 批三号依赖冲突(登记待裁定):cmd/serve 半成品 import 了
moonbitlang/x/json5——本批删依赖后该 import 无 moon.mod 声明,实测解析失败(Cannot find import 'moonbitlang/x/json5' in vitro/engine/cmd/serve),已阻塞主工作区一切全模块 moon 命令。serve 若确需 JSON 解析,面临与 fs 同款的决策(vendor / 换实现 / 恢复依赖);建议并入 serve 批裁定,勿静默恢复 x 依赖。 - README×2 分解式(人工域):测试总数 504 已三方一致(实跑/两 README/testcount);分解括号尚未列入
fs 9(白盒 7 + 黑盒 2)——分解式为人工维护域,随 serve 批的测试数连坐一并补列即可。