Skip to content

修复第三轮全代码审查发现的 37 项问题(v1.6.2) - #21

Merged
Pau1am merged 4 commits into
mainfrom
fix/v1.6.2-audit
Oct 15, 2026
Merged

Pau1am merged 4 commits into
mainfrom
fix/v1.6.2-audit

Conversation

@Pau1am

@Pau1am Pau1am commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

改了什么

一轮全代码审查(覆盖三个插件共 90 条)中属于本仓库的 37 条全部落地,另附版本号与 CHANGELOG 更新(1.6.1 → 1.6.2):

  • 一个畸形 mod jar 不再让整次检查没有报告(P1):depends.minecraft 写成数字或对象(例如 1.21 忘了引号)时,以前会让检查整体失败、只剩一句 check failed。
  • 下载请求也计入 network.requests_per_minute(P1);响应体读到一半断连会重试(P1);深嵌套响应的 RecursionError 归类为上游错误(P1);安装成功后删除已消费的下载文件并清扫下载目录(P1)。
  • 配置里写错类型会被点名并备份为 config.json.broken.<时间戳>(P1),不再被 MCDR 静默重置为默认值。
  • 并发写同一 JSON 文件不再失败:按目标目录串行化写入并重试改名。这一条是变异检查逼出来的——只按目标文件加锁时「去掉锁」的变异能存活,最终把锁粒度提到目录。
  • ResolveCache 只回写自己新增的记录;download all 也遵守「同一文件不并发下载」;备份名改为原子抢占;.part 临时名唯一;元数据解压改为分块读并设上限。
  • 版本比较满足传递性、is_prerelease 与之一致;数值选项范围表补全;!!muc list ² 这类输入不再让命令静默失败。
  • i18n 不再依赖 Python 3.9+ 的 API,language: auto 在声明的 3.8 下限上不会退化成只有 en_us;语言文件里让用户设置的键的路径已更正。
  • !!muc 与 !!modupdate 两种别名下屏内提示都指向用户实际输入的那个别名;last_report.json 改为原子写入。
  • tools/mcdr_matrix.py 固定子进程编码并在中文终端下保住失败证据;tools/probe_upstream.py 接受参数、离线时给出结论;tools/check_python_floor.py 改为检查「模块 + 属性」对。
  • CI 增加端到端作业与 pip 缓存、固定 action 版本;补英文 README 与徽章。

为什么

同上:这一轮的重点是「前两轮的修只覆盖了一个入口」,以及若干「坏了但不出声」的路径(配置被重置、缓存互相抹掉、安装后磁盘只增不减)。

如何验证

改动后的分支上本地实测:

  • 全量测试 885 passed(原 827;含 2 项真实 MCDR 端到端)
  • ruff check . 全过;tools/check_python_floor.py 53 个文件合规
  • tools/mutation_check.py 12/12 全部被抓
  • tools/mcdr_matrix.py MCDR 2.13.0 / 2.14.1 / 2.15.0 / 2.15.7 / 2.16.0 五版本通过、54 项判据一致
  • 产物重建与提交件逐字节一致(91,947 B → 95,484 B,包内 changelog 只留最新一节且与版本号一致)

CI 会再跑 lint / unit(含 3.9 地板)/ mutation / e2e / 跨版本矩阵 / 产物自检。

- a non-string `depends.minecraft` in a mod jar no longer costs the whole check
  its report: `_coerce_range` funnels the fabric/quilt/toml readers and
  `parse_spec`/`normalize_spec` refuse mappings and non-string values
  (MUC-A-01, MUC-A-08).
- the download client shares the rate limiter with every other request
  (MUC-A-02); `RecursionError`/`MemoryError` from a deeply nested response
  become `UpstreamError` (MUC-A-03); a body that breaks mid-read is retried
  (MUC-A-04).
- an installed download is deleted and the folder swept (MUC-A-05); `.part` and
  backup names are unique (MUC-A-11, MUC-A-13); permanently uninstallable
  records are marked instead of retried every stop (MUC-A-12); metadata reads
  are bounded by chunked reads rather than the declared size (MUC-A-10).
- writes to one JSON file are serialised per directory and the rename retried,
  which is what Windows actually refuses (MUC-A-07); `ResolveCache` writes back
  only its own dirty keys under a process-wide lock (MUC-A-06).
- a config type mistake is caught before MCDR regenerates the file (MUC-B-01);
  `isdigit` becomes `isdecimal` (MUC-B-02); `download all` honours the
  in-flight claim (MUC-B-03); the numeric range table is complete (MUC-B-04).
- i18n no longer needs a 3.9+ API on the declared 3.8 floor (MUC-B-05);
  `last_report.json` is atomic (MUC-B-09); the eight hard-coded `!!modupdate`
  mentions use the alias that was actually typed (MUC-B-08); the version
  ordering is transitive and `is_prerelease` follows it (MUC-A-15).

- `tools/mcdr_matrix.py` pins `PYTHONIOENCODING=utf-8`, reconfigures its own
  streams and decides "loaded" from ASCII markers, so a CP936 console no longer
  loses the failure evidence (MAIN-02).
- `tools/probe_upstream.py` takes arguments, no longer downloads a jar for
  `--help` and reports offline failures instead of a traceback (MAIN-03); the
  mutation tool documents its real reason for requiring e2e (MAIN-04).
- `tools/check_python_floor.py` checks (module, attribute) pairs, so
  `importlib.resources.files` cannot slip past the 3.8 floor again (MUC-B-05).
- CI gains an e2e job and a pip cache and pins its actions; dependabot is
  enabled (REPO-21, REPO-29).

An English README with a language cross-link and badges (REPO-34); the CI table
matches `ci.yml`; the bench takes a mods path instead of a hard-coded one
(REPO-22); the configured message the report tells admins to set is the path
that exists (DOC-01, DOC-02).

One commit for the whole round: the suites pin the files a fix/chore/docs split would
separate - MUC's `tests/test_docs.py` asserts the packaging metadata, its CI table and the
READMEs, IG's `tests/test_build_artifact.py` asserts the metadata and the packer, and SLF's
tests read `tools/mcdr_matrix.py` - so splitting would leave red intermediate commits.
- 版本号 1.6.1 → 1.6.2(`mcdreforged.plugin.json`)。
- `CHANGELOG.md` 换成 1.6.2 一节,只保留最新版。
- README 与 README_en 的界面示例标题栏跟着升到 v1.6.2。
- 验证:884 项测试、变异 12/12、MCDR 2.13.0–2.16.0 五版本矩阵通过、产物逐字节可重建。
`cache: pip` without `cache-dependency-path` makes `actions/setup-python` look for
`**/requirements.txt` or `**/pyproject.toml`; this repository has neither, so the step
failed before ruff ever ran. Point it at `tests/requirements-test.txt`, the same file the
other jobs use.
`test_eight_threads_writing_one_file_always_succeed` decides whether the per-directory write
lock is present by looking for a failed rename or a retry. Both only happen on Windows: on
Linux two concurrent `os.replace` calls at one destination do not fail, so with the lock
removed nothing in that test changes and the mutation check reports the mutation as
survived (CI runs on Linux, and it did).

`test_writes_to_one_target_never_overlap` measures the overlap directly: a counting wrapper
around the rename records how many writers are inside the write path at once, and asserts the
peak is one. That holds on any platform, so the mutation is caught everywhere.
@Pau1am
Pau1am merged commit 57f2f19 into main Oct 15, 2026
12 checks passed
@Pau1am
Pau1am deleted the fix/v1.6.2-audit branch October 15, 2026 08:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant