〖共创稿事节〗HarmonyOS 7 新特性实战(66):给术语立钉点门禁——「发现系/收录系」26 处逐文件登记,复查从一次性网变常设网
# 〖共创稿事节〗HarmonyOS 7 新特性实战(66):给术语立钉点门禁——「发现系/收录系」26 处逐文件登记,复查从一次性网变常设网
上一篇收尾留了一句话:门禁没盯的角落靠语境复查补位,「给它们补门禁之前,复查是唯一的网」。那 5 处术语漏网——2×2 桌面卡、护照印章格、馆长目标卡两处、探索路线文案——没有任何门禁报红,是当天逐组件人工扫出来的。人工复查有个天然缺陷:抓得到,守不住。它覆盖哪些组件取决于当天扫了哪里;下次有人加一张卡片、改一句文案,复查不会自动跟着跑。
本篇就把这句话兑现:给「发现系/收录系」立逐文件钉点门禁。写作当日落地,全量门禁从 52 项长到 53 项,复跑全绿;HAP 构建同日复跑通过。首跑没有抓到新红——这不是门禁没用,恰恰说明上一篇的人工清扫是干净的;但守未来靠的不再是当天的眼力,是此后每一轮改动都要撞一次的钉点。

一、先复述判定标准:语境跟着数据来源走
钉点之前把判定标准写死。第三刀(65 篇)确立的口径是数据来源决定语境,不是词语本身:
| 语境 | 判定标准 | 典型落点 | 例句 |
|---|---|---|---|
| 发现系 | discoveredIds / discovered 等进度状态驱动 | 工具栏筛选、区域进度、桌面卡提示 | 「已发现 17 只神兽」「还有 N 只待发现」 |
| 收录系 | 描述馆藏体量与资料范围 | 展厅导览、路线注记、缺位提示 | 「这里收录 N 件展品」「详情页收录原文与注解」 |
判定标准本身是稳定的,不稳定的是执行。术语回归的特征和上一篇那处权限误删同型:编译不报错、运行不崩、构建绿、门禁绿——当时的 39 项门禁里没有一项管文案口径,只有用户看得见。所以这轮门禁要回答的问题不是「术语对不对」(那是判定标准的事),而是「哪里不许再变」。
二、钉点之前先分治:字面量与注释不是一个风险等级
把 65 篇的结论「每个词只在一个语境出现」直接翻译成计数门禁,会撞上两个坑。第一个坑:一刀切太紧,注释也要吵。首页内容组件里有 6 处「收录」,全部在注释里——是 10-26/10-27 两轮宽屏改造的布局沿革记录(已收录卡固定 262×68、维持 3.86:1 零拉伸之类)。注释是档案,每次重排布局都改注释,裸计数门禁会天天误报。第二个坑:一刀切太松,裁决依据会丢。「已收录」手风琴卡是唯一登记进字面量的收录系进度层级词,它旁边有一行判定注释(「已收录」= 进度卡里的「已发现」那一层)——这行注释是那个合法保留项的裁决依据,被人随手删掉就没人知道为什么留着。
所以门禁用双口径分治:total 数全部出现次数,inString 只数字符串字面量里的次数。字面量直接面向用户,必须逐处裁决;注释只做档案留痕,不拦语义:
const count = (text, term) => (text.match(new RegExp(term, 'g')) || []).length;
// 三个引号段的匹配顺序由正则引擎保证互不重叠,模板串跨行用 s 标志兜住
const stringSpans = text => text.matchAll(/'[^'\n]*'|"[^"\n]*"|`[^`]*`/gs);
判断「这处收录该不该存在」的活儿仍然在人:门禁只保证每次变化都被逼到判定标准面前过一遍。这正是上一篇按钮计数校准的教训换来的纪律——校准值不带出处,下次还是无头案。
三、钉点表:26 处逐文件登记,每条随行出处
钉点表按文件登记两系术语的全部落点,每条 why 字段写明语境出处:
// 每个文件的出现次数都是校准值——校准值不带出处,下次还是无头案。
// inString = 落在字符串字面量里的次数:字面量的收录取舍直接面向用户,必须逐处登记;
// 注释收录只做档案留痕,不拦语义。
const PINS = {
'common/data/ShanhaiMockData.ets': { total: 7, inString: 7,
why: '7 条路线注记:详情页收录原文与注解(馆藏范围)' },
'common/ui/ShanhaiKnowledgeStructureCard.ets': { total: 3, inString: 1,
why: '首页「已收录」手风琴卡:馆藏体量档位(Text 字面量 ×1 + 沿革注释 ×2)' },
'feature/home/ShanhaiHomePageContent.ets': { total: 6, inString: 0,
why: '注释 ×6:已收录卡布局沿革(宽屏改造记录)' },
'feature/world/ShanhaiExploreWorldPanels.ets': { total: 1, inString: 1,
why: '该区域暂未收录这一类线索(区域内容覆盖)' },
// ……共 11 个文件,完整清单见下表
};
11 个文件 26 处的全量登记:
| 文件 | 处数 | 字面量 | 出处(语境) |
|---|---|---|---|
common/data/ShanhaiMockData.ets | 7 | 7 | 7 条路线注记「详情页收录原文与注解」(馆藏范围) |
feature/home/ShanhaiHomePageContent.ets | 6 | 0 | 注释:已收录卡布局沿革(宽屏改造记录) |
common/ui/ShanhaiKnowledgeStructureCard.ets | 3 | 1 | 「已收录」手风琴卡 Text ×1 + 判定/沿革注释 ×2 |
common/data/ShanhaiRichContent.ets | 2 | 2 | 策展话题语料:后世典籍收录叙事(资料正文) |
feature/beast/ShanhaiBeastDetailReadingCards.ets | 2 | 2 | 原文定位/摘录缺位提示 ×2(资料缺位) |
common/data/ShanhaiContentSources.ets | 1 | 0 | 注释:原文摘录缺位分支说明 |
common/data/ShanhaiCrossEntryArticles.ets | 1 | 1 | 展厅正文语料:《云笈七签》收录的后世黄帝叙事 |
common/data/ShanhaiCuratorGuideData.ets | 1 | 1 | 展厅导览语料「这里收录 N 件展品」(展厅体量) |
feature/curator/ShanhaiCuratorSourceRelations.ets | 1 | 1 | 「相关原文已收录」(馆藏结果) |
common/ui/ShanhaiThemeModeSheet.ets | 1 | 0 | 注释:与已收录展开卡比例对照 |
feature/world/ShanhaiExploreWorldPanels.ets | 1 | 1 | 「该区域暂未收录这一类线索」(区域内容覆盖) |
钉点层的对账逻辑很短:
for (const [file, pin] of Object.entries(PINS)) {
const text = readFileSync(new URL(file, root), 'utf8');
const total = count(text, '收录');
const inString = [...stringSpans(text)].reduce((n, span) => n + count(span[0], '收录'), 0);
assert.equal(total, pin.total, `${file} 收录出现 ${total} 次 ≠ 钉点 ${pin.total}:${pin.why} —— 改动后先按语境判定(发现系/收录系),再带着出处回填钉点`);
assert.equal(inString, pin.inString, `${file} 字面量收录 ${inString} 处 ≠ 钉点 ${pin.inString}:${pin.why} —— 新增面向用户的「收录」必须先过语境判定`);
}
报错文案里把该走的流程写全:先判定、再带出处回填。门禁的价值不在拦住,在拦住时把上下文递到眼前——why 字段让下一次对账不用考古。
四、覆盖层与正向钉点:新落点与旧落点都要有人盯着
钉点表只管登记过的文件,还有两个方向没人管:新文件混入与旧落点回退。覆盖层补第一个方向——未登记的文件出现「收录」即红,逼着先归类再登记;禁用形态补第二层保险——「待收录」「收录进度」这两组进度语境组合是事故形态,无论钉点表怎么改都不许在全树出现:
// 覆盖层:未登记文件不许出现「收录」;禁用形态全树扫描(含钉点文件)。
for (const file of files) {
const key = rel(file);
const text = readFileSync(file, 'utf8');
if (!PINS[key]) {
const hits = count(text, '收录');
assert.equal(hits, 0, `${key} 新出现 ${hits} 处「收录」:先按判定标准归类——进度状态驱动改「发现」;馆藏体量/资料范围合法,则登记进 PINS 并带出处`);
}
for (const { pattern, why } of FORBIDDEN) {
assert.doesNotMatch(text, pattern, `${key} 命中禁用形态「${pattern.source}」:${why}`);
}
}
正向钉点管回退方向。发现系的 6 个落点逐一断言存在——有人手滑把某处改回旧词,正向断言比肉眼先知道:
const archive = readFileSync(new URL('feature/beast/BeastArchiveViewModel.ets', root), 'utf8');
assert.match(archive, /BEAST_ARCHIVE_FILTER_DISCOVERED: string = '已发现'/);
assert.match(archive, /BEAST_ARCHIVE_FILTER_UNDISCOVERED: string = '未发现'/);
const toolbar = readFileSync(new URL('common/ui/ShanhaiArchiveToolbar.ets', root), 'utf8');
assert.match(toolbar, /Text\('已发现'\)/);
assert.match(toolbar, /accessibilityText\('已发现' \+ this\.discoveredCount/);
工具栏那条把 accessibilityText 也钉住了:无障碍文本和可见文案是同一句术语口径,可见文案改了、读屏文案没跟,是术语回归里最隐蔽的一种——用户看得见的地方尚且会漏,读屏用户听到的更没人盯。最后一条断言钉的是「裁决依据必须还在」:已收录手风琴卡的判定注释(「已收录」= 进度卡里的「已发现」那一层)一旦被清理注释的顺手一刀删掉,那个合法保留项就变成了无头案。


五、写作当日落地与复跑:52 → 53 项,全绿
落地顺序是先探测后钉点:全树扫一遍两系分布(发现系 106 处、收录系 26 处),对收录系 26 处逐处判定语境、写出处,形成钉点表;发现系只做正向钉点不钉计数——资料正文语料里合法地含有「发现」二字(典籍叙事原文),按文件钉死计数会把语料修订也拦下,正向钉点只锁 UI 落点。
2026-11-10 复跑全量门禁:套件 52 → 53 项(新增 1 项),处置后 53/53 PASS;HAP 构建同日复跑 BUILD SUCCESSFUL。首跑即绿的解读要诚实:没有抓到新红,说明上一篇当日的人工清扫是干净的。但不能由此推出门禁是多余的——人工复查是一次性的网(65 篇靠它抓了 5 处漏网),钉点门禁是常设的网:此后任何一轮改动撞上 26 处钉点、6 处正向落点或 2 组禁用形态,都会当场报红并把判定标准递到眼前。
| 证据 | 结果 | 说明 |
|---|---|---|
| 全量门禁 | 53/53 PASS | 52 → 53(新增 verify-terminology-context 一项),处置后全绿 |
| 钉点覆盖 | 收录系 26 处 / 11 文件 | 字面量 16 处逐处登记,注释 10 处档案留痕 |
| 正向钉点 | 发现系 6 处 | 图鉴过滤器 ×2、工具栏(可见+无障碍)、列表徽标、首页提示、图鉴副标题 |
| 禁用形态 | 2 组全树扫描 | 「待收录」「收录进度」零容忍,含钉点文件 |
| HAP 构建 | BUILD SUCCESSFUL in 14 s | 33 tasks:15 executed,18 up-to-date;当日复跑取新鲜口径 |

收个尾
- 判定标准进代码,语境才不会漂移。 「数据来源决定语境」写在文章里只是一段话,写进门禁才是常设的合同;每次变化都被逼到判定标准面前过一遍。
- 字面量与注释分治,一刀切两头漏。 字面量直接面向用户,逐处登记;注释是档案留痕,只数总数。双口径让宽屏改造的沿革注释不再制造误报,也让裁决依据丢了会报红。
- 校准值必须随行出处。
why字段不是装饰——按钮计数 23→25 的无头案已经演示过一次「数字不带出处,下次还得考古」。 - 覆盖层与正向钉点双向锁。 钉点表拦不住新文件混入,覆盖层补;钉点表拦不住旧落点回退,正向断言补;禁用形态是零容忍的事故形态,全树扫。
- 首跑即绿不是门禁没用,是清扫干净了。 守未来靠的是此后每轮都要撞一次的钉点,不是当天的眼力;红在写作当天,比红在发布后便宜得多。
附:本篇证据清单
- 门禁落地(2026-11-10):
app-harmony/scripts/verify-terminology-context.mjs新增,钉点层(11 文件 26 处对账)+ 覆盖层(未登记文件零出现、禁用形态全树扫描)+ 发现系正向钉点 6 处;全量套件复跑 53/53 PASS(52 → 53)。 - 构建(2026-11-10):HAP 构建 BUILD SUCCESSFUL in 14 s(33 tasks:15 executed,18 up-to-date)。
- 验收记录:
acceptance/2026-10-16-terminology-shoulu-to-shifaxian/(图鉴工具栏「已发现」与探索页区域进度两图,发现系落点取证)。 - 术语分布当日探测:全树发现系 106 处、收录系 26 处(11 文件),字面量 16 处;钉点清单见第三节表格。
- 源码落点:
scripts/verify-terminology-context.mjs(本篇唯一新增);钉点涉及的 11 个文件见第三节表格,均为既有文件的文案口径登记,无应用代码改动。 - 关联稿件:术语语境判定标准与 5 处漏网的人工复查见系列第 65 篇;钉点维护与「实伤/过期」定性见第 64 篇;门禁校准值出处的教训(按钮计数 23→25)同见第 65 篇;无障碍口径的来历见第 48 篇(碰一碰分享的无障碍文本)。
更多推荐
所有评论(0)