〖共创稿事节〗HarmonyOS 7 新特性实战(68):backend 门禁 8 红拍板——worktree 回基线取证,三处改钉、两处刷新、两处起服
# 〖共创稿事节〗HarmonyOS 7 新特性实战(68):backend 门禁 8 红拍板——worktree 回基线取证,三处改钉、两处刷新、两处起服
> 本篇是系列第 68 篇,兑现任务板上挂了近一个月的欠账:「8 项 backend 门禁失败(未拍板)」。结论先说:6 红里没有一个是「修代码」能单独解决的——3 处是钉点过期(改钉保意图),2 处是审读基线过期(复读刷新),2 处根本不是内容问题(先起 mock 服务再谈红绿)。凑不回 8 是因为其中 2 处在第 64 篇的内容修复里已经顺手收掉,账本没记。收口后 backend 套件 12/12、应用侧 54/54、HAP 构建同日通过。
一、欠账对账:8 红从哪来,怎么变成 6 红
这笔欠账难办的地方在于:任务板上只记了一个数——「8 项 backend 门禁失败(未拍板)」,没有名单、没有日期快照。要拍板,先得还原当时的盘面。
办法是 git worktree:把仓库在 2026-10-13 当天最后一个提交上展开成独立工作树,12 项门禁照跑一遍。它不碰主工作区,跑完即删,是给历史盘面取证最干净的工具(git 官方文档对 worktree 的定义只有一句:管理多个工作树):
git worktree add %TEMP%\h7-69-baseline be36b13
# 在 backend\scripts 与 backend\mock-api\scripts 各跑一遍 verify-*.mjs,记录 PASS/FAIL
git worktree remove %TEMP%\h7-69-baseline --force
复跑结果:内容类 7 项直接报红,名单与欠账高度吻合。两个走 mock 服务的门禁需要服务在场才可比——本机服务加载的是主工作区当前内容,跨提交对照会失真,所以拍板口径以「本次开工实测」为准。三个时点摆在一起,账就对上了:
| 时点 | 盘面 | 说明 |
|---|---|---|
| 2026-10-13 欠账记入 | 4 PASS / 8 FAIL | 只记了数,没记名单 |
| 基线提交复跑(be36b13) | 7 项内容红复现 | 含 batch2 两项——正是第 64 篇当日修复的对象 |
| 2026-11-09(第 64 篇) | 8 红 → 6 红 | 鹿蜀钉点改写、相柳边界句恢复,batch2-pilot-content 与 rich-beast-depth 随之转绿,账本未记 |
| 2026-11-10 本次开工 | 6 PASS / 6 FAIL | 拍板对象,下文逐条处置 |

差额本身是个教训:第 64 篇修复内容时顺手让两道门禁转绿,但任务板上的「8 项」没动——欠账只增不减的账本,会让后来者把已经还掉的钱再还一遍。
二、三处钉点过期:改钉保意图
6 红里有 3 处是同一类:钉点门禁断言「定稿必须包含某句话」,之后的审读改写了措辞,句子走了、事实还在。断言撞上的第一堵墙是白泽:
// verify-baize-reader-narration.mjs:旧钉断在 detail 上,审读后早已不匹配
assert.match(baize.detail, /把所述内容绘录成图/);
// 2026-11-10 改钉:detail 现用语是「一场问答与随后的图写」;
// 对账时发现「绘录成图」的事实句并未消失,只是挪进了 readingNote——随行补钉防再丢。
assert.match(baize.detail, /一场问答与随后的图写/);
assert.match(baize.readingNote, /将这些内容绘录成图/);
对账时特意查了旧短语的下落:它没有从语料里消失,而是从 detail 挪到了 readingNote(「黄帝命人将这些内容绘录成图,传示天下」)。这决定了拍板方向——不是删钉,而是把钉子钉到事实现在住的字段上,一处两钉。
应龙是同一模式的两个变体:detail 的悬念句被改写成新问法,knowledge 的「故」字讲解句换了措辞;readingNote 则原封未动,维持原钉。穷奇那处在连环修订门禁里:出处对照句从「另写穷奇状如虎、有翼」改成「另有状如虎、有翼的穷奇」,出处事实不变:
| 对象 | 旧钉(过期) | 现文(事实仍在) | 新钉 |
|---|---|---|---|
| 白泽 detail | 把所述内容绘录成图 | 一场问答与随后的图写 | 一场问答与随后的图写 |
| 白泽 readingNote | ——(未钉) | 将这些内容绘录成图 | 将这些内容绘录成图(新增) |
| 应龙 detail / knowledge | 没有说明不能返回的原因 / 「故」才明确……相接 | 「不能再回到天上」之后发生了什么 / 才把不能复上与下界屡旱连起来 | 按定稿措辞重钉 |
| 穷奇(连环修订) | 《海内北经》另写穷奇状如虎、有翼 | 《海内北经》另有状如虎、有翼的穷奇 | 《海内北经》另有状如虎、有翼 |
改钉有一条底线:新钉必须保住旧钉的意图。旧钉防的是「图写」「出处对照」「因果关节」这三个事实从文案里消失,新钉逐条对应,一句不少。应龙与穷奇两处的落点如下——注意应龙的 readingNote 逐字未动,原钉维持,改钉只动过期的:
// verify-yinglong-reader-narration.mjs
// 2026-11-10 改钉:detail 改问「“不能再回到天上”之后发生了什么」,同一悬念重心的现用语。
assert.match(item.detail, /“不能再回到天上”之后发生了什么/);
// readingNote 未改动维持原钉;knowledge 的「故」句按定稿措辞重钉。
assert.match(item.readingNote, /东北隅交代开篇山名的方位,南极交代应龙的处所/);
assert.match(item.knowledge.content, /才把不能复上与下界屡旱连起来/);
// verify-sequential-reader-revisions.mjs
// 2026-11-10 改钉:审读后定稿为「另有状如虎、有翼的穷奇」;出处对照事实不变。
assert.match(allText('beast_qiongqi'), /《海内北经》另有状如虎、有翼/);

三、审读基线刷新:两层哈希的过期与复读
第 4 红是审读门禁:ShanhaiMockData.ets: 公共文本快照缺失或已变化。这套机制值得展开,因为它防的正是第二节的这种漂移——基线文件里存了两层哈希,都基于 Node.js crypto 的 createHash 计算:一层是 9 个公共文案文件的全文 sha256,一层是 36 篇异兽内容的全对象哈希(键序无关、文字或值一变即失效)。对账函数逐层核对:
for (const path of expectedFiles) {
if (snapshot.publicFiles?.[path] !== sha256(publicFiles[path])) problems.push(`${path}: 公共文本快照缺失或已变化`);
}
for (const item of items) {
const row = entries.find(entry => entry.beastId === item.beastId);
if (row.sha256 !== articleHash(item)) problems.push(`${item.beastId}: 内容变化,需重新审读`);
}
刷新前先回答一个问题:基线之后变了的文本,变对了吗?逐处核对后确认两处过期,性质不同。
第一处是公共文件层。ShanhaiMockData.ets 的工作区里躺着一行未提交改动,正是第 66 篇立的术语门禁(套件第 53 项)钉住的那类修订:
- content: '……还可以继续认识猼訑、陆吾与开明兽;收录这条路线的全部神兽后,再到山海护照查看昆仑印章。',
+ content: '……还可以继续认识猼訑、陆吾与开明兽;发现这条路线的全部神兽后,再到山海护照查看昆仑印章。',
这句话已经被第 53 项门禁逐文件钉住,再做候选扫描零命中——合法修订,基线哈希随之刷新(5e704eaa… → c3b36cc9…)。
第二处是内容层:beast_xiangliu: 内容变化,需重新审读。来源明确——第 64 篇当日恢复了相柳故事卡被误删的审读边界句,内容变了,基线里的逐篇记录却停在 10 月 13 日。处理走流程而不是改数字:候选扫描 0 命中后,该篇重记 reread_passed、reviewedOn 更新到当日,引用出处字段保持原有报告引用不变。

四、两处环境依赖:先起服务再谈红绿
最后 2 红的报错长得完全不同——不是断言失败,是 ECONNREFUSED:连接本机 3199 端口被拒。这两个门禁验的是 HTTP 契约:详情 36、卡片 72、主题 144 走接口逐一核对,服务不在场就谈不上红绿。这类红和内容红必须分开拍板,混在一起会把「环境缺条件」误判成「文案出问题」:
cd backend\mock-api
$env:PORT='3199'; node server.mjs
# verify-curator-topic-content.mjs
# PASS curator topic contract: 白泽四主题正文去前缀/标题后两两不同,并各自命中对应主题正文。
# verify-rich-beast-content-v3.mjs
# PASS rich API content: 36 details and 72 reading cards match active canonical copy
# (2026.09.14-v4.13-sequential-reader-revision).
起服即绿,内容零改动。拍板结论:这两项的「失败」从第一天起就是运行条件缺失,值得改的只是跑门禁的前置说明——先把服务拉起来,再看红绿。至此六红的处置口径全部分清,三类红的修法互不可替代:
| 红的类型 | 断言形态 | 处置 | 不可混淆的理由 |
|---|---|---|---|
| 钉点过期(×3) | 正则 / 子串断言失配 | 改钉保意图 | 删钉等于放弃事实防回归 |
| 基线过期(×1 门禁两层) | 哈希对账失配 | 复读后刷新记录 | 只改数字会把证据变成橡皮章 |
| 环境依赖(×2) | 连接失败,非断言 | 起服务补条件 | 当内容红去修会误伤正确文案 |
五、收口与反向验证
六红处置完毕,三套证据同日复跑:backend 套件 12/12 PASS(2026-10-13 以来第一次全绿);应用侧套件 54/54 PASS 无回归;HAP 构建 BUILD SUCCESSFUL in 34s 971ms(25 executed / 8 up-to-date)。
改钉和刷新这类操作自己也可能出错,所以照例做反向验证——故意把事情改坏,看门禁叫不叫:
| 反向用例 | 操作 | 预期 | 实测 |
|---|---|---|---|
| 旧钉复活 | 白泽新钉换回 /把所述内容绘录成图/ | 报红 | AssertionError,正则失配如实报出 |
| 基线哈希篡改 | 快照里 ShanhaiMockData 哈希改成 64 个 0 | 报红 | 「公共文本快照缺失或已变化」逐字报出 |
| 还原后复跑 | 恢复新钉与原快照 | 全绿 | 12/12 PASS |

| 复跑项 | 结果 |
|---|---|
| backend 套件(scripts 9 项 + mock-api 2 项 + 审读 1 项) | 12/12 PASS |
| 应用侧全量门禁套件 | 54/54 PASS,无回归 |
| HAP 构建 | BUILD SUCCESSFUL in 34 s 971 ms(25 executed / 8 up-to-date) |
| 反向验证 | 2 组报红均成立,还原后复绿 |
拍板清单沉淀成三分法,下回再遇到门禁红,先分类再动手:钉点过期(事实还在、措辞变了 → 改钉保意图)、基线过期(合法修订未重记录 → 复读刷新,流程走完不改数字)、环境依赖(服务或条件缺失 → 补条件,不碰内容)。任务板上与此欠账并列的「来源卡 → 出处」措辞一项,核对后确认早在第八轮已收口(应用侧全文 0 命中,规则库保留为侦测词),属账本残留,一并清账。剩下的 UX 自检遗留(状态栏、挖孔区各 1 例低频)留给下轮自检观察,不在此篇展开。
收个尾
这笔欠账挂了近一个月,期间三次全量复跑都路过它,三次都以「与基线一致、非本次引入」为由放行。放行有当时的道理——每轮改动确实没引入新红——但「没变坏」和「拍板」是两回事。这次真正的产出不是改掉的几行:三处改钉、两处刷新、一次起服,而是把门禁红拆成了三类,每类有了可复用的处置路径;账本也顺手正了本清——第 64 篇顺手收掉的两红补记在案,第八轮就已收口的「来源卡」措辞移出仍欠。门禁全绿不是终点,名单可追溯、差额有解释,账本才配得上「已拍板」三个字。下一篇见。
证据清单
- 钉点改钉:
backend/scripts/verify-baize-reader-narration.mjs、verify-yinglong-reader-narration.mjs、verify-sequential-reader-revisions.mjs(改钉原因与日期随行注释) - 基线刷新:
docs/development/reader-copy-review-2026-10-13.json——ShanhaiMockData.ets 哈希 5e704eaa… → c3b36cc9…;beast_xiangliu 重记 reread_passed / reviewedOn 2026-11-10,引用出处字段保持原报告引用 - 历史盘面取证:git worktree 于基线提交 be36b13 复跑 12 项门禁(取证后工作树已删)
- mock 服务:
backend/mock-api(PORT=3199,node server.mjs),两个 HTTP 契约门禁起服即绿 - 全量复跑:backend 12/12 PASS · 应用侧 54/54 PASS(2026-11-10);HAP 构建 BUILD SUCCESSFUL in 34 s 971 ms(25 executed / 8 up-to-date)
- 欠账出处:第十六轮任务板「仍欠」条目与第八轮「4 PASS / 8 FAIL」记录
- 系列前置:第 64 篇(详情层去重与 batch2 内容修复)· 第 66 篇(术语钉点门禁,套件第 53 项)· 第 67 篇(生僻字覆盖对账,套件第 54 项)
更多推荐



所有评论(0)