panatgithub_AnkiHeadingSync/docs/settings-anki-template-cache-status-gap-report.md
Dusk ffad94dd18 feat: 优化设置页模板缓存状态 / improve settings template cache status
- 设置页在有缓存时立即显示缓存摘要,并在打开时只做一次轻量 note type freshness 检查
- 手动读取仍负责完整模板与字段刷新,不会在页面打开时读取所有字段
- Add tests and docs for cache summary, stale-cache warning, and failed background checks
2026-04-25 11:18:11 +08:00

131 lines
No EOL
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 设置页 Anki 模板缓存状态差距审计
本文基于当前仓库真实实现,审计“设置页模板缓存状态显示 + 后台轻量 freshness 检测”的落地差距。
## 1. 当前设置页已是 cache-first 下拉,但不是 cache-first 状态
- 入口在 [src/presentation/settings/PluginSettingTab.ts](src/presentation/settings/PluginSettingTab.ts)。
- `renderCardTypesCard()` 打开时会先执行 `hydrateVisibleCardTypeCaches()`
- note type 下拉来自:
- `availableNoteModels`,若为空则退回 `settings.ankiNoteTypeCache`
- 字段下拉来自:
- `settings.ankiModelFieldCache` 水合出的 `loadedModelDetails`
- 再经 `getCurrentMappingForConfig()` 生成 draft mapping
这说明缓存实际上已经参与首屏渲染,当前问题不是“缓存没被用”,而是“状态文案没有反映缓存可用性”。
## 2. 当前首屏状态文本仍固定为 idle
- 当前类内状态是:
- `cardTypeStatus: UserFacingMessage = NOTE_TYPE_STATUS_IDLE`
- `NOTE_TYPE_STATUS_IDLE` 指向 `settings.mapping.status.idle`
- `renderCardTypesCard()` 直接渲染 `renderUserFacingMessage(this.cardTypeStatus)`
- `cardTypeStatus` 只会在以下情况变化:
- `saveCardTypeConfig()` 校验失败
- `loadAnkiCardTypeConfig()` 开始 / 成功 / 失败
结果:即使已有 `ankiNoteTypeCache``ankiModelFieldCache`,首次打开设置页仍显示“请先从 Anki 刷新”语义,而不是缓存摘要。
## 3. 当前设置页打开时不会做任何后台 freshness 检测
- `display()` -> `renderCard("card-types")` -> `renderCardTypesCard()` 的当前路径里没有自动调用:
- `listNoteModels()`
- `getModelFieldNamesByModelNames()`
- `getNoteModelDetails()`
- 唯一主动访问 Anki 的入口仍是点击“手动读取 Anki 里的模板配置”。
这与目标方案的差距是:当前没有“只跑一次 modelNames 的轻量后台检测”。
## 4. 当前完整刷新流程已经符合“手动触发全量字段读取”约束
- `loadAnkiCardTypeConfig()` 当前真实流程是:
- `listNoteModels()` 一次
- `getModelFieldNamesByModelNames()` 一次
- `updateSettings({ ankiNoteTypeCache, ankiModelFieldCache })`
- `hydrateVisibleCardTypeCaches()`
- `syncQaGroupMappingFromCache()`
- `renderCard("card-types")`
- 当前不会在设置页打开时读取所有字段。
这意味着本轮应保留该完整刷新流程,只新增轻量 `listNoteModels()` 检测,不改 full refresh 语义。
## 5. 当前 card 1 已具备局部刷新壳层,可直接复用
- `display()` 只在首次进入时 `containerEl.empty()` 和初始化 card shells。
- 后续都是 `renderCard(cardId)` 的局部刷新。
- `loadAnkiCardTypeConfig()`、`saveCardTypeConfig()`、`saveFieldMapping()` 等都只刷新 `card-types` 卡片。
这与目标方案一致:后台检测完成后只需 `renderCard("card-types")`,不需要整页重建。
## 6. 当前没有“一次性检测状态”或“override 状态”的分层模型
- 当前只有一个 `cardTypeStatus` 字段,同时承载:
- idle
- manual refresh loading
- manual refresh success
- manual refresh failure
- validation failure
- 没有单独的:
- cache freshness check 状态
- status override
- detected live note type list
- one-shot lifecycle promise
结果:如果直接把后台检测结果写回 `cardTypeStatus`,会和手动刷新成功/失败状态互相覆盖。
## 7. 当前没有防重入机制来保证“一次生命周期只检测一次”
- 现在 `renderCard("card-types")` 会在很多交互后被反复调用:
- display 初始渲染
- toggle/heading/note type 变更
- QA Group warning acceptance
- manual refresh 前后
- 但类内没有任何 `Promise``status` 标记来阻止重复启动 live 检测。
因此如果要加后台检测,必须把“是否已检测过/是否检测中”挂在 settings tab 实例上,而不是放在 render 逻辑里临时判断。
## 8. 当前测试已证明缓存渲染存在,但未覆盖状态与后台检测
- [src/presentation/settings/PluginSettingTab.test.ts](src/presentation/settings/PluginSettingTab.test.ts) 当前已经覆盖:
- `ankiNoteTypeCache` 渲染 note type 下拉
- `ankiModelFieldCache` 渲染字段下拉
- 手动完整刷新只触发 `listNoteModels()` + `getModelFieldNamesByModelNames()`
- `getNoteModelDetails()` 在设置页刷新路径中不应被调用
- 但未覆盖:
- 有缓存时首屏状态摘要
- 首屏后台 `listNoteModels()` 轻量检测
- 检测 changed / failed 分支
- 无缓存时不启动后台检测
- 手动 refresh 成功后清除 changed 提示
## 9. 当前 i18n 里缺少缓存状态分层文案
- 当前 card types 相关文案已有:
- `loadedSummary`
- `failedLoad`
- `failedSave`
- `loadAnki.loading`
- 但没有:
- `cacheEmpty`
- `cacheSummary`
- `cacheChanged`
- `cacheCheckFailed`
结果:即使实现了 cache-aware status也没有现成 i18n key 可用。
## 10. 结论
当前仓库与目标方案的差距主要集中在状态模型,不在缓存渲染主链:
1. 缓存已经用于下拉和字段渲染,但状态文本仍是固定 idle。
2. 设置页打开时没有任何轻量 `modelNames` freshness check。
3. 当前缺少 cache status 与 manual refresh status 的分层模型。
4. 当前缺少防止重复后台检测的实例级状态。
5. 当前测试和 i18n 都还不知道这套缓存状态语义。
因此最安全的仓库兼容路径是:
1. 保留现有缓存渲染和 manual full refresh 流程。
2. 新增实例级的一次性 `listNoteModels()` 后台检测状态。
3. 用统一的 `getCardTypeStatusMessage()` 计算首屏状态与 override 状态。
4. 让后台检测只影响 card 1 的状态提示,不触碰 `data.json` 和字段缓存。