Skip to content

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 件事)

  1. 复制资产surface_to_base.json 整包覆盖(新 SHA ca75b179…)。base_forms.json 不变
  2. 复制预装库reading_vocab.db 整包覆盖(新 SHA ef7a7297…),VOCABULARY_SEED_VERSION 升 v18。
  3. reseed prune 48 旧 PK(merge 路径残留,见 §4)。
  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 跟进会话)。

§1 根因与决策

根因现象修法
1. 资产错映射as→a 毁 48 条含 as 习语 PK(as a wholea a whole);picked→pic/passed→pas/trying→trie 毁 RB 运行时单词查询surface_to_base.json(§2)
2. 引用形被归一吃掉逐 token lemmatize 让 raining cats and dogsrain 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.json1a468a82d7f1d58844bc039484e3759562ea07d5078f12db59feca0fb90d8c99ca75b17972fc239d82affdb13634477d22f0bbc461527d3d2e4c05e731956147140371→140370
base_forms.json3094c829fee1bcaf430917a9f77377d146cc93e8f6c591cd622b45381f7deadc未变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 → picpickpassed → paspasstrying → trietrytried → try 本就对,未动)
  • count 140371→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→pickpassed→passtrying→trytried→trynormalizePhrase("as a whole")=="as a whole"("as long as")=="as long as"


§3 canonical_surface 列(Schema v54,红线 #10)

DDLvocabularycanonical_surface TEXT(紧跟 emoji 列后)。RB SQLite 同步加。

语义:习语可读引用形(如 raining cats and dogs),归一键 wordrain cat and dog)的展示形。

  • 来源:RVH generate_db._applyPhraseOverlayphrase_library_final.raw_forms[0](Kaikki headword 引用形)。
  • 覆盖:phrase 行 6608/6611 非空。3 个 NULLgood 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 SHA25622ee5f1f…c070fdef7a7297cb0ea118db15d58053a7250aafa14c01fb9fd39a41fb2b0467644125
VOCABULARY_SEED_VERSIONrvh-18899-v17-phrases-2026-06-07rvh-18899-v18-asfix-canonical-2026-06-08
总词数1889918899(不变)
tag 分布basic 400 / idiom 5336 / phrasal_verb 1861同左(不变)

⚠️ merge 路径残留:RB reseed 走 merge SQL(非全量重建),48 个旧 as-PKa 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 uppick 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 ruleas a ruleas a rule
a a wholeas a wholeas a whole
a beas beas is
a everas everas ever
a far a one be concernas far as one be concernas far as one is concerned
a far a one knowas far as one knowas far as one knows
a good a it getas good as it getas good as it gets
a good one canas good one canas best one can
a if by magicas if by magicas if by magic
a if there be no tomorrowas if there be no tomorrowas if there were no tomorrow
a it happenas it happenas it happens
a long aas long asas long as
a luck would have itas luck would have itas luck would have it
a ofas ofas of
a soon aas soon asas soon as
a the case may beas the case may beas the case may be
a the crow flyas the crow flyas the crow flies
a the next guyas the next guyas the next guy
a the next personas the next personas the next person
a the say goas the say goas the saying goes
a they sayas they sayas they say
a wellas wellas well
a yetas yetas yet
a you goas you goas you go
a you knowas you knowas you know
be that a it maybe that as it maybe that as it may
business a usualbusiness as usualbusiness as usual
busy a a beebusy as a beebusy as a bee
dumb a a postdumb as a postdumb as a post
gentle a a lambgentle as a lambgentle as a lamb
give a good a one getgive as good as one getgive as good as one gets
go so far ago so far asgo so far as
green a grassgreen as grassgreen as grass
hard a nailhard as nailhard as nails
may a wellmay as wellmay as well
old a the hillold as the hillold as the hills
poor a a church mousepoor as a church mousepoor as a church mouse
proud a a peacockproud as a peacockproud as a peacock
quick a a flashquick as a flashquick as a flash
quick a lightningquick as lightningquick as lightning
quiet a a mousequiet as a mousequiet as a mouse
silent a the gravesilent as the gravesilent as the grave
so aso asso as
so long aso long asso long as
take something a it cometake something as it cometake something as it comes
thick a thiefthick as thiefthick as thieves
tough a nailtough as nailtough as nails
try a one maytry as one maytry 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:asforce_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 跟进」段