Files
mindfulness/spec_kit/Text Wrap/modules/search-engine-app/tasks.md
2026-02-10 11:39:33 +08:00

3.9 KiB
Raw Blame History

search-engine-app任务清单

目标:在 APP 场景实现 DP + TopK 的确定性组合搜索(对应文档 9.1),并接入 scoring-tiebreak 输出最优 layout。

0. 对齐与准备

  • 复核输入/输出与依赖
    • 阅读 spec_kit/Text Wrap/modules/search-engine-app/spec.md
    • 阅读 spec_kit/Text Wrap/modules/search-engine-app/plan.md
    • 阅读 设计说明文档/文档换行算法.md 的 9.1/9.3/11 章节
  • 创建客户端模块目录
    • 新建 client/src/features/textWrap/searchApp/

1. 类型定义与导出

  • 新建 client/src/features/textWrap/searchApp/types.ts
    • 定义 LineMode = 'AUTO' | 'FIXED'
    • 定义 SearchAppConfig(包含 topKtooLongThresholds 等,首版给默认值)
    • 定义 SearchAppInput
      • tokens: Token[]
      • lang: 'TC' | 'EN'
      • breakpoints: Breakpoint[]
      • availableWidth: number
      • maxLines: number
      • lineMode: LineMode
      • measure: { contextProfile; fontSpec; measureWidthImpl }(复用 width-measurement 类型)
      • scoring: { config; lexicons; debug? }(复用 scoring-tiebreak 类型)
    • 定义 SearchAppResult
      • 成功:bestLayout { breaks; lines; wrappedText; meta }
      • 失败:{ ok:false; reason:'TOO_LONG'|'WIDTH_UNKNOWN'|'NO_CANDIDATE'; meta }
  • 新建 client/src/features/textWrap/searchApp/index.ts
    • 统一导出 types 与核心入口 searchBestLayoutApp()

2. TopK 维护(确定性)

  • 新建 client/src/features/textWrap/searchApp/topK.ts
    • 实现 compareLayouts(a,b)
      • score 降序
      • tieKey 逐项比较(数值越小越优)
      • breaks 字典序兜底11.0A
    • 实现去重:同 breaks 仅保留最优
    • 实现 insertTopK(list, cand, K):插入、去重、排序、截断(全程确定性)

3. 约束与可解释失败原因

  • 新建 client/src/features/textWrap/searchApp/constraints.ts
    • 实现 isTooLong(tokens, lang)TC>60 或 EN>30首版写死
    • 实现 isLineStartPunctTC(tokens, pos, tcPunctuations)H6
    • 实现 isOverWidth(width, availableWidth)H1

4. DP + TopK 主流程

  • 新建 client/src/features/textWrap/searchApp/dpTopK.ts
    • 实现入口 searchBestLayoutApp(input)
    • 构造 dpdp[pos][linesUsed] = TopK[]
    • 枚举顺序固定:
      • pos0..N
      • linesUsed0..maxLines-1
      • nextPos从 breakpoints 里取 >pos 的 pos 升序 + 追加 N
    • 每次转移:
      • 构造 lineText使用 joinTokensEN 默认空格TC 使用 rawSeparators 拼接)
      • 测量 lineWidth使用 measureSliceWidthCached
      • 过滤硬约束H1/空行/H6/maxLines
      • 构造 layoutCandidatebreaks + lines[]
      • 调用 scoreLayout + buildTieKey 得到 score/tieKey
      • 插入目标 dp 并维护 TopK
    • 结束选择:
      • AUTOdp[N][<=maxLines] 选最优
      • FIXED优先 dp[N][==maxLines],否则返回 NO_CANDIDATE(交给 overflow-fallback 再降级)
    • meta 输出:
      • breaks
      • scoreTopTerms(若 debug=true从 scoring 输出 Top-3

5. 单测Vitest

  • 新建 client/src/features/textWrap/searchApp/__tests__/searchApp.test.ts
    • 确定性:同输入运行多次结果一致
    • TopK 去重:两条路径同 breaks 只保留一个
    • FIXED必须刚好 maxLines否则失败 reason=NO_CANDIDATE
    • TC H6行首标点导致的转移必须被禁止
    • TOO_LONG触发阈值直接返回 reason=TOO_LONG

6. 收尾

  • 跑测试与类型检查
    • npm test
    • npx tsc --noEmit
  • 将本 tasks.md 全部勾选完成
  • 更新 spec_kit/overview.md
    • 标记 search-engine-app 已完成编码(阶段性)
    • 写入变更文件清单