fix+feat(vocab): A2/B1 富字段回填 + A1 取数 API 化(ADR-0014) - #61
Merged
Merged
Conversation
- 根因:sync{A2,B1}CardsFromServer 为 append-only(if (!existingIds.has(wid)) 无 else),
存量词条(富字段上线前首次同步)永远停在 ex:[] → 用户看到「只有部分词有例句」
- 修复:新建分支行为逐字不变;新增 else 分支「只补空字段」(ex/ipa,B1 另含 gender/plural),
绝不覆盖非空(保护手编例句/音标),不碰 hw/gloss/tags/id,只动词表(FSRS 进度零接触),幂等
- 进 A2/B1 档即自愈(wordFilters.scope 不持久化,切换必然触发 sync)
- a1_cards.js:备考域卡片背面/列表卡片例句块改条件渲染(空值不输出孤立标签+空行)
- 探针 tools/wb_rich_backfill_probe.mjs(真实切片 + node:vm 真跑,19 场景,--json 模式)
已由 pytest 驱动接入 CI(test_rich_backfill_probe_reports_no_failures)
- 回归:749 passed(--ignore=test_server,2 条为既有 Windows 环境失败)+ test_server 228 passed/1 skipped
= 977 passed + 1 skipped;13 探针零漂移;ruff/mypy 全绿
- Vault 01-ADR/0014:词表源头不入库(FTS5 仅派生索引)/ A1 取数 API 化 / 同步语义固化 - PROJECT_OVERVIEW 增 ADR-0014 引用 + Task A(32a8f0f)门禁数据
- _contract_item 增 letter 形参/输出(唯一构造点);reader 分支由内联 dict 收敛到它 - A1 分支逐字透传 seed 原值(不派生:letterOf 会在 10 条上漂移 O<->Ö / U<->Ü / K<->- / A<->S) - 非 A1 分支(A2/B1/reader)取 hw 首字母大写,与前端现行派生逐字一致 - 同步 4 处字段集守卫(contract_uniform / sources / a1_workbench_source / test_server) - 新增 3 条 TDD:A1 seed 逐条等价 / 非 A1 口径 / 反向守卫防派生 - 回归 752 passed(--ignore=test_server,2 条既有环境失败)+ test_server 228 passed 1 skipped;ruff/mypy 全绿
- 新增纯函数 a1WordFromApi(服务端 12 字段→前端词对象,逐条 normalizeWord,letter 取原值不派生) 与 a1WordsFromInline(旧内联建表原样抽出,全文件唯一一份) - loadAll 首装分支改为置空表 + 挂起标记;async bootstrapA1Words:fetch 成功覆盖/合并, 失败回退内联并 toast;挂起期集中式 renderA1BootLoading 占位(不误报空态/已完成) - 黄牌② 引入来源标记 wb.a1.src.v1(server/inline):曾兜底的设备下次启动真实重试, 成功后按 ADR-0014 只增+只补空合并(mergeA1ServerWords,不覆盖手编、不碰 cards/log/wrong) - 红牌① 三处启动 saveWords 加挂起守卫 + saveWords 顶部统一兜底闸(挡挂起+空表, 不误挡首装成功路径)+ bootstrap 补跑 migrateSeedIdAliases - 黄牌③ bootstrap 尾部 try/catch/finally + 调用点 catch,杜绝永久加载态 - 探针 tools/wb_a1_bootstrap_probe.mjs(真实切片 + node:vm,8 场景,含挂起不落盘 / inline 重试) 经 pytest 驱动接入 CI;变异验证:去守卫→场景 A 红、改覆盖→场景 B 红 - 回归 756 passed(--ignore=test_server,2 条既有环境失败)+ test_server 228 passed 1 skipped;ruff/mypy 全绿
- 裁决:不删 SEED_WORDS/CORE_CUSTOM_WORDS(file:// 直开是 ADR-0011 明示保护的离线能力) - 两常量上方注释标注「离线 fallback,非主路径数据源」+ 指向 ADR-0014 §6-S3 - 新增守卫 G1/G2/G3:loadAll 体内无 SEED_WORDS.map(;全文件 a1WordsFromInline( 恰 2 处 且调用点只在 bootstrapA1Words 内;成功路径不引用内联(三个变异实跑验证非死断言) - 探针新增场景「内联仅作离线兜底」:服务端可用 inlineCalls=0 / 服务不可用 inlineCalls=1 - ADR-0014 §6-S3 同步改写;PROJECT_OVERVIEW 实施状态更新(S1-S3 完成,S4 点检待做) - 134 passed(定向)+ 全探针零漂移 + ruff/mypy 全绿
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
按 ADR-0014 顺序执行:A(富字段回填)→ C(ADR 归档)→ B(A1 取数统一)。
解决的问题
1)A2/B1「只有部分词有例句」——根因是字段冻结,不是缺词。
sync{A2,B1}CardsFromServer原为 append-only(if (!existingIds.has(wid))无 else),存量词条首次同步后就再不会被更新 → 永远停在ex:[]。修:新建分支逐字不变,新增 else 只补空字段(
ex/ipa,B1 另含gender/plural)——不覆盖非空(保护手编例句)、只动词表、不碰cards/log/wrong、幂等。进 A2/B1 档即自愈。另:备考域卡片例句块改条件渲染(空值不再输出孤立标签 + 空行)。
2)A1 取数统一(ADR-0014 §4-2)
letter)。必须下发而非前端派生:实测letterOf会在 10 条上漂移(O↔Ö、U↔Ü、K↔-、A↔S)。a1WordFromApi/a1WordsFromInline/bootstrapA1Words——API 优先 → 内联兜底 → localStorage 缓存;wb.a1.src.v1(server/inline)让「可稍后刷新重试」真实可重试,升级时按「只增 + 只补空」合并,不覆盖用户手编、不动 FSRS;挂起期renderA1BootLoading()占位(不误报空态/已完成)。file://直开是 ADR-0011 明示保护的能力,本地服务下 124KB 收益近零。由 G1/G2/G3 三条守卫钉死「内联绝不当主路径」。关键决策(ADR-0014)
门禁
no such table: exam_trials为既有 Windows 环境失败,已用无关文件组合复现证实);分半 Btest_server228 passed + 1 skippedtools/*.mjs)wb_rich_backfill_probe.mjs(19 场景)、wb_a1_bootstrap_probe.mjs(10 场景)改动含
static/→ Android 必须覆盖安装(桌面端即时生效)。点检:A1 五档可见、A2/B1 例句音标齐全、进度零丢失、字母分组一致。ADR-0014 §6-S4。