主题
09 · 习语归一治理 + canonical_surface reseed 交接(RVH → RB)
RVH 接 RB
08-rb-phrase-reseed-confirmation.md「数据质量待 RVH 跟进」段,完成预装短语库两类归一噪声治理。 日期:2026-06-08 · RVH Schema v54 / 预装 v18 · 优先级 P2(不阻塞 RB 匹配,仅显示 + 含 as 习语覆盖)
TL;DR(RB 要做的 4 件事)
- 复制资产:
surface_to_base.json整包覆盖(新 SHAca75b179…)。base_forms.json不变。 - 复制预装库:
reading_vocab.db整包覆盖(新 SHAef7a7297…),VOCABULARY_SEED_VERSION升 v18。 - reseed prune 48 旧 PK(merge 路径残留,见 §4)。
- 更新单测:
normalize_phrase内联样例同步rvh-phrase-normalize.csv(picked up→pick up 等,见 §5);build_dict.rs移植 override 保未来重生成不回退(见 §2)。- popup/WordRow 改读
COALESCE(canonical_surface, word)(见 §3,RB 跟进会话)。
- popup/WordRow 改读
§1 根因与决策
| 根因 | 现象 | 修法 |
|---|---|---|
| 1. 资产错映射 | as→a 毁 48 条含 as 习语 PK(as a whole→a a whole);picked→pic/passed→pas/trying→trie 毁 RB 运行时单词查询 | 修 surface_to_base.json(§2) |
| 2. 引用形被归一吃掉 | 逐 token lemmatize 让 raining cats and dogs→rain cat and dog,弹窗/复习卡显示非英语骨架 | 新增 vocabulary.canonical_surface 列存可读引用形(§3) |
数据模型澄清(防回退):归一键当 PK 承重不可动(跨端红线 #9 一致性 + 屈折召回 + 学习项去重)。归一键↔引用形非一对多屈折——屈折变体(rained/raining/rains)运行时由 normalize_phrase 吸收、永不入库;Kaikki 每习语一引用形;匹配只走归一键,canonical_surface 纯展示。
§2 资产修正(红线 #5e,byte-equal)
只 surface_to_base.json 变:
| 资产 | 旧 SHA256 | 新 SHA256 | 词数 |
|---|---|---|---|
surface_to_base.json | 1a468a82d7f1d58844bc039484e3759562ea07d5078f12db59feca0fb90d8c99 | ca75b17972fc239d82affdb13634477d22f0bbc461527d3d2e4c05e731956147 | 140371→140370 |
base_forms.json | 3094c829fee1bcaf430917a9f77377d146cc93e8f6c591cd622b45381f7deadc | 未变 | 101646 |
改了什么(RVH tools/vocabulary_builder_v3/bin/patch_lemmatizer_assets.py,文本级精确替换保 byte-equal):
as → a删除映射 →lemmatize("as")由 Layer 2 base_forms 自映射返回"as"(as已在base_forms.base数组,故 base_forms 不动)picked → pic改pick;passed → pas改pass;trying → trie改try(tried → try本就对,未动)count140371→140370(删 1 key)
RB 落地:以复制 RVH 同字节为准(不要独立重跑 build_dict.rs 产出,避免序列化漂移)。 durability 移植(保未来全量重生成不回退):
as加进build_dict.rs::force_as_base数组(既有机制:加 base_forms + 清 s2b,正好等价)picked/passed/trying加进新 correction map(surface→正确 base 覆盖层)- 移植后跑 CI:
build_dict.rs输出须与 RVH patch 后资产 byte-equal(diff)
验证(红线 #5e 双端跑分,必须 diff 为空):
bash
# 单词级
diff <(RB phase0_normalize < lemma-regression.txt) <(RVH /tmp/phase0_rvh < lemma-regression.txt)
# 短语级(红线 #9)
diff <(RB normalize_phrase < phrase-normalize-regression.txt) <(RVH /tmp/phase0_rvh --phrase < ...)RVH 已实测:as→as(base)、picked→pick、passed→pass、trying→try、tried→try; normalizePhrase("as a whole")=="as a whole"、("as long as")=="as long as"。
§3 canonical_surface 列(Schema v54,红线 #10)
DDL:vocabulary 加 canonical_surface TEXT(紧跟 emoji 列后)。RB SQLite 同步加。
语义:习语可读引用形(如 raining cats and dogs),归一键 word(rain cat and dog)的展示形。
- 来源:RVH
generate_db._applyPhraseOverlay取phrase_library_final.raw_forms[0](Kaikki headword 引用形)。 - 覆盖:phrase 行 6608/6611 非空。3 个 NULL(
good night/last minute/rush hour——复合名词习语,归一无损,word 本身可读)。 - 匹配/同步零参与,不进 Supabase 同步矩阵(与 emoji 同策略)。
RB 读取:COALESCE(canonical_surface, word)——phrase 显示引用形,NULL 时回退 word(对 3 个复合名词正好可读)。popup/WordRow 改读属 RB 跟进会话,本交接只在库里产出该列。
⚠️ 引用形保真度受 Kaikki 限制:少数 headword 是基本形(
rain cats and dogs而非raining cats and dogs),但复数/屈折已还原,远好于归一骨架rain cat and dog。
§4 预装库 + 48 旧 PK prune
| 旧(v17) | 新(v18) | |
|---|---|---|
reading_vocab.db SHA256 | 22ee5f1f…c070fd | ef7a7297cb0ea118db15d58053a7250aafa14c01fb9fd39a41fb2b0467644125 |
VOCABULARY_SEED_VERSION | rvh-18899-v17-phrases-2026-06-07 | rvh-18899-v18-asfix-canonical-2026-06-08 |
| 总词数 | 18899 | 18899(不变) |
| tag 分布 | basic 400 / idiom 5336 / phrasal_verb 1861 | 同左(不变) |
⚠️ merge 路径残留:RB reseed 走 merge SQL(非全量重建),48 个旧 as-PK(a a whole 等)不会被新行(as a whole)覆盖 → 孤儿行 + 新行并存。RB 须显式 prune:
sql
DELETE FROM vocabulary WHERE word IN (
'a a rule','a a whole','a be','a ever','a far a one be concern','a far a one know',
'a good a it get','a good one can','a if by magic','a if there be no tomorrow','a it happen',
'a long a','a luck would have it','a of','a soon a','a the case may be','a the crow fly',
'a the next guy','a the next person','a the say go','a they say','a well','a yet','a you go',
'a you know','be that a it may','business a usual','busy a a bee','dumb a a post','gentle a a lamb',
'give a good a one get','go so far a','green a grass','hard a nail','may a well','old a the hill',
'poor a a church mouse','proud a a peacock','quick a a flash','quick a lightning','quiet a a mouse',
'silent a the grave','so a','so long a','take something a it come','thick a thief','tough a nail',
'try a one may'
);用户数据风险:vocabulary→user FK 为 RESTRICT。若有用户 notebook_entries 已指向这 48 旧 PK(短语特性仅数天,预计近零),prune 前须 remap 或保护。RVH 端无短语 UI(本地不可能产生);RB/Supabase 端 RVH 未能 headless 实测(rvh-debug MCP 需 app 运行 + 登录)——RB reseed 前请自查 user_notebook_entries WHERE word IN (48 旧 PK),非空则先 remap 到对应新 PK(映射见 §6)。
§5 单测样例同步(RB normalize_phrase_byte_equal_with_rvh)
tools/vocabulary_builder_v3/output/rvh-phrase-normalize.csv 已重生成,RB 内联单测须同步。变化项:
picked up→pick up(原pic up)- 新增
passed out,pass out - 新增 as 习语:
as a whole,as a whole/as long as,as long as/as soon as,as soon as/as the crow flies,as the crow fly(flies→fly 合法逐 token,as 保留) /business as usual,business as usual
完整 41 行见 RVH output/rvh-phrase-normalize.csv。
§6 48 条 old → new PK 映射(含引用形)
| 旧 PK(prune) | 新 PK(matching key) | canonical_surface(raw 引用形) |
|---|---|---|
a a rule | as a rule | as a rule |
a a whole | as a whole | as a whole |
a be | as be | as is |
a ever | as ever | as ever |
a far a one be concern | as far as one be concern | as far as one is concerned |
a far a one know | as far as one know | as far as one knows |
a good a it get | as good as it get | as good as it gets |
a good one can | as good one can | as best one can |
a if by magic | as if by magic | as if by magic |
a if there be no tomorrow | as if there be no tomorrow | as if there were no tomorrow |
a it happen | as it happen | as it happens |
a long a | as long as | as long as |
a luck would have it | as luck would have it | as luck would have it |
a of | as of | as of |
a soon a | as soon as | as soon as |
a the case may be | as the case may be | as the case may be |
a the crow fly | as the crow fly | as the crow flies |
a the next guy | as the next guy | as the next guy |
a the next person | as the next person | as the next person |
a the say go | as the say go | as the saying goes |
a they say | as they say | as they say |
a well | as well | as well |
a yet | as yet | as yet |
a you go | as you go | as you go |
a you know | as you know | as you know |
be that a it may | be that as it may | be that as it may |
business a usual | business as usual | business as usual |
busy a a bee | busy as a bee | busy as a bee |
dumb a a post | dumb as a post | dumb as a post |
gentle a a lamb | gentle as a lamb | gentle as a lamb |
give a good a one get | give as good as one get | give as good as one gets |
go so far a | go so far as | go so far as |
green a grass | green as grass | green as grass |
hard a nail | hard as nail | hard as nails |
may a well | may as well | may as well |
old a the hill | old as the hill | old as the hills |
poor a a church mouse | poor as a church mouse | poor as a church mouse |
proud a a peacock | proud as a peacock | proud as a peacock |
quick a a flash | quick as a flash | quick as a flash |
quick a lightning | quick as lightning | quick as lightning |
quiet a a mouse | quiet as a mouse | quiet as a mouse |
silent a the grave | silent as the grave | silent as the grave |
so a | so as | so as |
so long a | so long as | so long as |
take something a it come | take something as it come | take something as it comes |
thick a thief | thick as thief | thick as thieves |
tough a nail | tough as nail | tough as nails |
try a one may | try as one may | try as one may |
RB 回执(2026-06-08)— 4 项全落地,实机验证通过
RB 实机:48 旧 as-PK=0 / preinstalled=18899 / rain cat and dog→canonical rain cats and dogs / seed_version rvh-18899-v18-asfix-canonical-2026-06-08。RB 弹窗 / 词表(学习+Browse)/ 词详情 / 复习卡 / TTS 跟读 均用 COALESCE(canonical_surface, word) 读可读形。
决策差异(知会,无需 RVH 动作):
- 48-PK:RB 用直接 DELETE(开发期,未做 §6 old→new remap;本机 0 引用)。RVH 无短语 UI,本地不产生这些 PK。
- 版本号:RB 字符串
rvh-18899-v18-…vs RVH 整数_preinstalledVocabVersion,各端自管。
⚠️ 遗留项 1(重要)— build_dict 生成器双端未验证 byte-equal(deferred)
现在资产有两个生成器,本次未跑「RB build_dict 输出 vs RVH patch 后资产 byte-equal」CI:
- RVH:
patch_lemmatizer_assets.py(对既有资产做文本级补丁) - RB:
examples/build_dict.rs(从 AGID 全量重生成 + override:as→force_as_base、picked/passed/trying→corrections 覆盖层)
当前资产 byte-equal 仅靠 RB 复制 RVH 字节保证(红线 #5e 满足)。但未来任一端全量重生成资产时, 两生成器可能漂移 → 重新引入 as→a / picked→pic 回归。 触发条件下必做:任一端跑全量资产重生成时,先跑双端生成器输出 diff,对齐后再提交。 关联 memory reference_lemmatizer_asset_bugs。
遗留项 2 — RVH 短语 UI 镜像 canonical_surface(待 RVH 做短语 UI 时)
RVH 当前无短语词卡/复习 UI;将来做时,词卡/复习卡显示须镜像 RB 的 COALESCE(canonical_surface, word) 读法(习语显示可读引用形,普通词回退 word)。canonical_surface 不进 Supabase 同步(红线 #10)。
关联
- RVH 落地:本会话 commit · plan
~/.claude/plans/sequential-giggling-treehouse.md+docs/plans/ - 红线 #5e(资产 byte-equal)/ #9(短语归一)/ #10(预装库单点产出)见 CLAUDE.md
- RB 接收前序:
08-rb-phrase-reseed-confirmation.md「数据质量待 RVH 跟进」段