panatgithub_AnkiHeadingSync/docs/semantic-qa-decisions.md

5.2 KiB
Raw Permalink Blame History

Semantic QA Decisions

Decision Summary

本轮按真实仓库结构锁定如下实现决策:

  1. 新功能接入 current manual-sync 主链,不新增平行 sync path。
  2. 新增独立内部 CardType = "semantic-qa"
  3. 语义 QA 使用独立 semanticQaNoteType 和独立 mapping key不复用 basic:...
  4. 语义 QA 的字段映射行为是 basic-like仍然走 title/body 两字段。
  5. 触发条件是“标题级别等于当前 QA 标题级别,且标题文本末尾包含配置的 hashtag marker”。
  6. 拆卡单位只认一级列表项;只有带缩进子内容的一级项生成卡。
  7. 一级列表项同行正文不进入答案;答案只取其缩进子内容。
  8. 语义 QA 子卡各自写独立 <!--ID: noteId--> marker不共享父标题 marker。
  9. 为了兼容当前 backlink 实现新增“显示题面标题”和“backlink 锚点标题”的分离。
  10. settings validation 继续沿用当前仓库的 lazy mapping 模式:
  • marker 语法与 note type 非空做全局校验
  • mapping 结构合法性继续全局校验
  • mapping 完整性在“保存 mapping”和“实际同步使用该 note type”时强制校验

Concrete Decisions

1. Internal card type name

使用:

  • semantic-qa

原因:

  • 语义清晰
  • 与当前 basic / cloze 明确区分
  • 仍能在实现里被当作 basic-like 类型处理

2. Settings shape

新增设置:

  • semanticQaMarker
  • semanticQaNoteType

本轮不新增 semanticQaEnabled

原因:

  • 仓库当前没有其他 feature-toggle 先例
  • 触发权已经由 marker + 标题级别共同控制
  • 可以在不改变当前 settings 生命周期的前提下完成需求

3. Marker syntax validation

合法 marker 语法固定为 hashtag token

  • 必须以 # 开头
  • 后面至少 1 个非空白字符
  • 不允许内部再含空白

v1 不支持:

  • emoji trigger
  • wikilink trigger
  • 多 token 组合 trigger

4. Parsing integration point

解析入口放在 CardIndexingService 内部。

行为:

  • 普通 QA 标题:保持一标题一张 basic
  • 普通 Cloze 标题:保持现状
  • 带 semantic marker 的 QA 标题:进入 semantic list parser产出 0..n 张 semantic-qa

原因:

  • 当前主链的 identity / note type / deck / writeback 都从 IndexedCard 起步
  • 在这里拆卡,后续 planner/executor/state 都能自然复用

5. Semantic child identity strategy

每张 semantic 子卡的稳定 basis 为:

  • file path
  • 一级列表项的 blockStartLine
  • 父标题文本
  • 子项稳定键
  • 子项答案内容

其中子项稳定键采用:

  • normalized child label + occurrence index among same labels within the same semantic heading

原因:

  • 比“全局顺序号”更稳
  • 仍然是 deterministic
  • 能处理同一父标题下重复 label 的情况

具体做法:

  • 把上述信息编码进 semantic 子卡的 rawBlockText / rawBlockHash
  • syncKey 仍使用现有 filePath + blockStartLine + rawBlockHash

6. Marker placement for semantic child cards

每个 semantic 子卡都在自己所属一级列表项区域内独立写 marker。

默认位置:

  • 该子项缩进内容的末尾之后

默认缩进:

  • 优先复用已有 marker 行缩进
  • 否则复用该子项首个子内容行的缩进
  • 若仍不可用,则回退到“一级列表项缩进 + 两个空格”

原因:

  • 避免多个子卡争用同一父标题尾部 marker 槽位
  • 维持 Markdown 列表结构可读性

为 indexed/state/render 数据增加一个单独字段:

  • backlinkHeadingText

语义:

  • heading = 实际题面标题(父标题 + 子项名)
  • backlinkHeadingText = 原父标题文本(含 semantic marker

原因:

  • 题面和 backlink anchor 在语义 QA 下不再相同
  • 当前仓库的 backlink 生成严格依赖 heading text

8. Question/title format

v1 题面格式固定为:

  • 父标题原文
  • 换行
  • 一级列表项标签文本(去掉列表 marker 本身,保留该项 markdown 文本)

原因:

  • 符合“父标题 + 子项名”
  • 最大程度贴近用户示例

9. Answer/body extraction rule

答案只取:

  • 该一级列表项下面的缩进子内容

不包含:

  • 一级列表项同行正文

若某一级列表项没有任何缩进子内容:

  • 不生成卡

10. Preview implementation

preview 只放在 settings 页,且只做 settings-driven fixed sample preview。

不做:

  • 当前文件实时扫描
  • 编辑器内实时提示

实现方式:

  • 复用 semantic list parser
  • 对固定样例输入做解析
  • 展示 marker 是否合法、会拆出多少张卡、每张卡的题面/答案摘要

Intentional Deviations From The Prior AI Plan

1. 不新增 semanticQaEnabled

原因:

  • 当前仓库并不依赖 feature-toggle 驱动 settings validity
  • marker 已经是足够明确的触发约束

2. mapping completeness 不在全局 settings load/save 时强制要求“已经存在”

原因:

  • 当前 basic/cloze 也不是这样工作的
  • 仓库真实模式是 lazy load fields -> save mapping -> runtime validate when used

3. 额外引入 backlinkHeadingText

原因:

  • 这是当前仓库实现决定的必需项
  • prior AI plan 没显式覆盖这个模型缺口