# core-contract(技术计划) ## 1. 计划目标 基于 `spec.md` 与 `设计说明文档/文档换行算法.md v1.2.1`,落地跨端一致的“基础口径与契约”,为后续断点生成、搜索与评分提供稳定输入与确定性工具,确保: - EN/TC 的 **token 索引体系** 与断点 `pos` 语义固定 - 文本 **可重组**:任意 `[start..end)` 区间可稳定还原为行文本 - EN 关键词命中规则严格为 **全词等值匹配**(避免 substring 误伤) - 空白归一化策略可配置但默认一致(推荐 NORMALIZE) - 提供可复用的 **确定性比较工具**(用于 breaks 字典序/tieKey 比较) ## 2. 默认技术决策(本计划采用) - **空白策略**:默认 `whitespacePolicy=NORMALIZE` - 行为:折叠连续空白为 1 个空格、去首尾空白 - 并在 meta(后续模块)中打点 `hadMultiWhitespace`(本模块先预留布尔返回位) - **EN tokenize**:仅生成 WORD token(不生成 SPACE token),以空白分隔;标点按“极简派”保留在词内 - **TC tokenize**:本模块只定义接口,具体分割由 `grapheme-segmentation` 提供 - **EN 关键词命中**:`lowercase → strip 两端常见标点 → 等值比较`,禁止 contains/substring - **确定性比较**:breaks 字典序比较按“逐项比较 + 公共前缀相同则更短者更小” ## 3. 目录与产物 本子模块目录: - `spec_kit/Text Wrap/modules/core-contract/spec.md` - `spec_kit/Text Wrap/modules/core-contract/plan.md`(本文) 建议未来代码落位(实现阶段再定,不在本计划强制): - `client/src/features/textWrap/core/`(或 `client/src/utils/textWrap/`) ## 4. 设计与实现要点(按落地顺序) ### 4.1 文本预处理:normalizeWhitespace 实现 `normalizeWhitespace(text) -> { normalizedText, hadMultiWhitespace }`: - 规则: - 把任意连续空白(空格/制表/换行等)折叠为单个空格 - 去除首尾空白 - 注意: - 该规范会改变输入文本;必须作为“算法契约”的一部分固定下来 - 若后续产品需要保留原始空白,则走 `PRESERVE` 分支并输出 `rawSeparators`(见 4.3) ### 4.2 EN tokenize:word tokens(极简派) 实现 `tokenizeEN(normalizedText) -> tokens[]`: - 以空格分隔生成 token - token 只包含 WORD,标点视为词内字符(例如 `tired.`、`Wait...`、`hello—world`、`don't` 都是单 token) - 输出 token 的 `text/start/end`(start/end 为原始或 normalized 的字符区间,需固定口径;建议以 normalizedText 为基准) ### 4.3 文本重组:joinTokens 实现 `joinTokens(tokens, start, end, separators?) -> string`: - EN 默认:使用单空格 `" "` join `[start..end)` 的 token.text - 若 `whitespacePolicy=PRESERVE`: - 需要 `rawSeparators[i]` 表示 tokens[i] 与 tokens[i+1] 间的原始分隔符 - 重组时按 separators 拼接(本计划仅定义接口与行为) ### 4.4 EN 关键词命中:normalizeENKeyword + matchENKeyword 实现: - `normalizeENKeyword(tokenText) -> string` - `lowercase` - `strip` 两端常见标点(集合需配置化并全端一致,默认参考文档:`, . ! ? : ; " ' … — – ( ) [ ] { }`) - `matchENKeyword(tokenText, keyword) -> boolean` - `normalizeENKeyword(tokenText) === normalizeENKeyword(keyword)` - 禁止 `includes/contains` 类 substring 命中 ### 4.5 断点/区间的索引契约 固化约定(后续模块必须复用,不得自行发挥): - token 索引:`tokens[0..N-1]` - 断点 `pos`:位于 token 边界,切分为 `[0..pos)` 与 `[pos..N)` - 行区间:`[start..end)` 表示 `tokens[start] ... tokens[end-1]` ## 5. 回归用例与验证方式 ### 5.1 必测示例(EN) - `"I am so tired"` → tokens=`[I, am, so, tired]` - `pos=2` → `"I am"` / `"so tired"` - 标点极简派: - `"tired."` 为单 token - 关键词命中: - keyword=`"but"`:`"but,"` 命中;`"rebuttal"` 不命中 ### 5.2 确定性检查 - 同一输入在同一配置下多次调用: - `normalizedText`、`tokens[]`、`joinTokens()`、`matchENKeyword()` 输出完全一致 ## 6. 风险与规避 - **start/end 索引口径漂移**:若不同端选择以原始 text 或 normalizedText 计数,可能导致 span 对不齐 - 规避:本模块明确 start/end 以 normalizedText 为准(或在实现阶段统一选择一种并写入 README/注释) - **标点集合不一致**:strip 集合若跨端不同会导致命中差异 - 规避:将 `punctuationStripSetEN` 写入配置并版本化,禁止散落常量 ## 7. 完成定义(DoD) - `core-contract/spec.md` 中定义的输入/输出与验收条目均有可运行的最小实现或可验证的约束说明 - EN tokenize / 空白归一化 / 关键词命中 / breaks 字典序比较口径写清楚且可复现 - 关键示例用例可在本地/CI 以单元测试或脚本方式验证(实现阶段落地)