docs: record P14 as delivered (wrapper 0.3.7, ROADMAP row + backlog)

The ContentService split landed in crearte-server 0.18.0 as merge fe810dd off
merge-base dbf7fe5. The third-wave table gains the P14 row and the doc index
marks it executed against the merge commit, per the P12/P13 convention of citing
the merge rather than the accounting commit.

The row records the batch's actual result, which is not the split but the two
review rounds that each caught the controller's own error: the task review found
that the guard purpose the spec states was covered by no assertion at all and
that the spec's own positive control had a bypass; the branch review then found a
hole in the first round's fix, where the source-scan pattern required a named
receiver and so let an unnamed-receiver shadow pass all seven assertions while
the shadow was effective. It also overturned two universal claims I had already
committed to the spec, both reproduced before acting on them.

Backlog gains the 169-line Approve function with its line range relocated after
the split (the base-tree mapping is void), plus six smaller items. It also logs a
dark-mode gap found while surveying the next batch: P13's token work covered only
the src/index.html entry and missed the second Vite entry, bootstrap, whose
loading screen hardcodes light values, so dark-theme users see a white flash on
every virtual game launch.
This commit is contained in:
2026-10-03 12:37:10 +08:00
parent 33c2d8d4b8
commit 163b0d703a
2 changed files with 18 additions and 1 deletions
+16
View File
@@ -6,6 +6,22 @@ All notable changes to this repository should be documented in this file.
The format loosely follows Keep a Changelog and can be adapted to the team's habits.
本文档参考了 Keep a Changelog 的思路,也可以根据团队习惯调整。
## [0.3.7] - 2026-10-03
### Done / 完成
- P14 splits the `ContentService` god object in crearte-server (0.18.0, merge `fe810dd`, merge-base `dbf7fe5`): an 856-line file carrying five unrelated responsibility lines becomes five sub-service files plus an 82-line composition root, and the five handlers each narrow from 22 visible methods to a consumer-defined interface of 4/5/2/5/6 with zero over-declaration and zero orphaned methods. `cmd/catalog.go` stops paying the god object's tax (dependency slots 4 → 2, the `nil` bundle placeholder gone). Pure structural refactor with no behaviour change — 25 methods moved byte-for-byte, `NewContentService`'s four-parameter signature unchanged character for character, `cmd/serve.go` untouched, and not one existing `*_test.go` modified.
- P14 拆分 crearte-server 的 `ContentService` god object(0.18.0,merge `fe810dd`,merge-base `dbf7fe5`):一个承载五条互不相干职责线的 856 行文件,变成五个子 service 文件加一个 82 行的组合根;五个 handler 各自从 22 个可见方法收窄到 4/5/2/5/6 个消费方定义的接口,零过声明、零孤儿方法。`cmd/catalog.go` 不再为 god object 交税(依赖槽 4 → 2、`nil` bundle 占位消失)。纯结构重构、零行为变更——25 个方法逐字节迁移、`NewContentService` 的四参数签名逐字不变、`cmd/serve.go` 未动、无任何既有 `*_test.go` 被修改。
- The review ladder ran two rounds and **both caught the controller's own errors**, which is the batch's main result rather than the split itself. The task review (PASS with notes, 7 findings from 10 self-designed mutations) found that the guard purpose the spec states — "prevent methods migrating back to the composition root" — was covered by **no assertion at all**: adding a method to the root left all three assertions PASS, `go build`/`go vet` clean, and the full 11-package suite green. It also found that the spec's own positive control had a bypass: mutation (a) turns red because it *removes* the method from the sub-service, not because anything detects the extra root method, so rewriting it as a copy would have passed green. The branch review (APPROVE with notes, 6 findings from 16 mutation/spike rounds, all run on a HEAD-exported copy proven byte-identical by 140 blob hashes) then found a hole **in the first round's own fix**: the source-scan pattern required a *named* receiver, but Go permits omitting an unused one and a shadowing body is exactly the case that often needs none — `func (*ContentService) CoverURL(k string) string` left build, vet and all seven assertions green while the shadow was effective. One token fixed it. Thirteen notes were adjudicated before merge: four fix-forward commits (`e195be0`, `e04694b`) and the rest accepted-with-reason, spec-wording corrections, or backlog.
- 审查阶梯跑了两轮,**两轮都抓到了控制者自己的错误**——这才是本批的主要产出,而非拆分本身。任务级审查(PASS with notes,10 条自设 mutation 挖出 7 条 findings)发现 spec 自述的守卫目的「防方法迁回组合根」**没有任何断言覆盖**:在组合根上加方法会让三条断言全 PASS、`go build`/`go vet` 全绿、全量 11 包测试也全绿。它还发现 spec 自己的 positive control 有绕行路径:mutation (a) 之所以红,是因为它把方法从子 service **拿走**了,而不是因为任何断言侦测到组合根多出方法,故把它改写成「复制」就会误绿。全分支终审(APPROVE with notes,16 轮 mutation/spike 挖出 6 条 findings,全部跑在以 140 个 blob hash 证明与 HEAD 逐字节一致的导出副本上)接着在**第一轮的修复自身**里找到洞:源码扫描的正则要求接收者**有名**,但 Go 允许省略不用的接收者名,而遮蔽体恰好常不需要它——`func (*ContentService) CoverURL(k string) string` 会让 build、vet 与七条断言全绿,而遮蔽确实生效。一个 token 就修好了。13 条 note 在合并前逐条裁定:4 条 fix-forward(`e195be0`、`e04694b`),其余为 accepted-with-reason、spec 措辞纠正或挂账。
- Two fixes a reviewer proposed were rejected on measurement, and the branch review confirmed both rejections on the real repo: asserting `NumMethod() == 0` on the value type is unsatisfiable because embedding `*T` puts its methods in both the value and pointer method sets — the legal tree already reports 22, making it a vacuously *false* assertion, the mirror image of the vacuously *true* one P13 shipped; and comparing `Method.Func` identity cannot detect shadowing because promoted methods are forwarding wrappers that already differ on the legal tree (`9683808 != 9511104` unshadowed, `9515680 != 9511104` shadowed). Two lessons went into the spec: a vacuously false guard is as worthless as a vacuously true one and is *more* likely to pass review by looking strict; and a claim that some check is "the only way" must enumerate the forms it covers (named/unnamed receiver, value/pointer, exported/unexported) or it becomes the next reviewer's counterexample — the review overturned two such claims I had already committed.
- 审查者提议的两条修法经实测被否决,全分支终审在真仓复核确认两条驳回都正确:断言值类型的 `NumMethod() == 0` 不可满足,因为嵌入 `*T` 会使其方法进入值类型与指针类型两者的方法集——合法树上已经报 22,故那是恒**假**断言,正是 P13 交付的恒**真**断言的镜像形态;而比较 `Method.Func` 同一性无法侦测遮蔽,因为提升方法本身是 forwarding wrapper,合法树上两者已经不同(未遮蔽 `9683808 != 9511104`、遮蔽 `9515680 != 9511104`)。两条教训写入 spec:恒假守卫与恒真守卫同样无价值,且**更容易因看起来严格而通过审查**;声称某个检查是「唯一手段」时必须枚举它覆盖的形态(有名/匿名接收者、值/指针、导出/未导出),否则它会成为下一个审查者的反例——本轮审查推翻了我两处已入库的这类声明。
- Spec re-pinned twice (`11fa1e2` after the task review, `33c2d8d` after the branch review) and ROADMAP updated: D-J amended from three assertions to seven, the mutation list extended to a–h with (a)'s bypass annotated, line counts pinned to the `wc -l` convention, D-D recording that `ErrSubmissionConflict` is also used at `account.go:136` outside the two lines that share it, and the risk table gaining two Route C properties — the root has no named fields so `s.objects` is an ambiguous selector rejected at compile time (a barrier earlier than any guard), and `go vet` stays silent on a root method shadowing a promoted one. The third wave table gains the P14 row and the doc index marks it executed against the merge commit; backlog gains `Approve` at 169 lines (`moderation.go:47-215`, seven phases already mapped), `memory_content.go`'s 814-line test double, handler error-mapping dedup, the `now`-field audit for `AccountService`/`CleanupService`, assertion 6 pinning field names rather than types, the lexical scan's deliberate over-strictness on block comments, and orphan private helpers. It also logs a dark-mode gap found while surveying the next batch: P13's token work covered only the `src/index.html` entry and missed the second Vite entry `bootstrap` (`vite.config.ts:21`), whose loading screen hardcodes light values — so dark-theme users see a white flash on every virtual game launch.
- spec 两次 re-pin(任务级审查后 `11fa1e2`、全分支终审后 `33c2d8d`)并更新 ROADMAP:D-J 从三类断言增订为七类、mutation 清单扩到 a–h 并注解 (a) 的绕行路径、行数口径钉为 `wc -l`、D-D 补记 `ErrSubmissionConflict` 还被两线之外的 `account.go:136` 使用、风险表新增两条 Route C 性质——组合根零具名字段故 `s.objects` 是编译期即拒绝的 ambiguous selector(比任何守卫都更早的屏障),以及 `go vet` 对组合根方法遮蔽提升方法保持沉默。第三波表新增 P14 行、文档索引按 merge commit 标记已执行;挂账新增 169 行的 `Approve`(`moderation.go:47-215`,七阶段已测绘)、`memory_content.go` 的 814 行测试替身、handler 错误映射去重、`AccountService`/`CleanupService` 的 `now` 字段复核、断言 6 只钉字段名不钉类型、词法扫描对块注释的刻意过严、孤儿私有方法。另登记一条在为下一批取证时发现的暗色缺口:P13 的令牌化只覆盖了 `src/index.html` 入口,漏了第二个 Vite 入口 `bootstrap`(`vite.config.ts:21`),其加载屏硬编码亮色值——故暗色用户每启动一个虚拟游戏都会看到一次白闪。
## [0.3.6] - 2026-10-03
### Done / 完成