# core-contract（任务清单）

> 对应计划：`spec_kit/Text Wrap/modules/core-contract/plan.md`
>
> 状态含义：`[ ]` 未完成，`[x]` 已完成。  
> 执行完本清单后，需要在 `spec_kit/overview.md` 的 `Text Wrap` 条目下补充“已完成编码/任务执行完毕”的标记（见最后一节）。

---

## 0. 任务标记规则

- 用勾选框标记执行状态：
  - `[ ]` 未完成
  - `[x]` 已完成
- 每个任务必须可独立验收（有明确产出与检查方式）。
- 涉及“口径”的任务，必须在代码注释中写清楚（简体中文），避免后续模块实现漂移。

---

## 1. 文档对齐（先把口径写死，避免实现漂移）

- [x] 1.1 复核 `core-contract/spec.md` 与 `core-contract/plan.md` 的一致性  
  - **检查点**：
    - `whitespacePolicy`（NORMALIZE/PRESERVE）语义一致
    - EN token 规则为“极简派”（不拆标点、不生成 SPACE token）
    - EN 关键词命中为“全词等值匹配”（禁止 substring）
    - breaks 字典序比较规则清晰且无歧义
  - **验收**：两份文档无冲突描述；关键字段命名一致。

- [x] 1.2 明确 `start/end` 的索引口径（以 normalizedText 为基准）并写入代码注释与 README（如有）  
  - **原因**：跨端 span/调试定位会依赖该口径  
  - **验收**：任意 token 的 `start/end` 都可映射到同一份文本基准（normalizedText）。

---

## 2. 目录与代码骨架（客户端侧优先落地）

> 说明：当前仓库已有 `client/src/features/*` 结构，Text Wrap 建议也放到 `features/` 下，便于后续 Home/Widget 复用。

- [x] 2.1 新建目录 `client/src/features/textWrap/core/`  
  - **产出**（建议文件）：
    - `types.ts`：Token/Config/Options 类型
    - `normalizeWhitespace.ts`
    - `tokenizeEN.ts`
    - `joinTokens.ts`
    - `enKeyword.ts`（normalizeENKeyword/matchENKeyword）
    - `compare.ts`（breaks 字典序比较）
    - `index.ts`（统一导出）
  - **验收**：目录存在且可被 TS 正常 import（不报路径错误）。

- [x] 2.2 定义 `Token` 与基础配置类型（只含 core-contract 需要的字段）  
  - **要求**：
    - `Token` 至少包含 `text/start/end`
    - `CoreConfig` 至少包含 `whitespacePolicy` 与 `punctuationStripSetEN`
  - **验收**：类型定义满足后续函数签名需要，且命名清晰。

---

## 3. 核心函数实现（纯函数 + 确定性）

- [x] 3.1 实现 `normalizeWhitespace(text)`（默认 NORMALIZE）  
  - **规则**：
    - 连续空白折叠为单个空格
    - 去除首尾空白
    - 返回 `hadMultiWhitespace`（用于后续 meta 打点）
  - **验收**：
    - 输入 `"  a   b \n c  "` 输出 `"a b c"`
    - `hadMultiWhitespace` 在出现折叠/trim 时为 true

- [x] 3.2 实现 `tokenizeEN(normalizedText)`（极简派）  
  - **规则**：
    - 以空格切分为 WORD tokens
    - 标点作为 token.text 的一部分（不拆）
    - 不生成 SPACE token
  - **验收**：
    - `"I am so tired"` → `[I, am, so, tired]`
    - `"tired."` 为单 token

- [x] 3.3 实现 `joinTokens(tokens, start, end, separators?)`  
  - **规则**：
    - 默认用单空格 join `[start..end)` 的 token.text
    - `start/end` 为半开区间，越界/空区间需有明确行为（建议：空区间返回空字符串，交由上层硬约束处理）
  - **验收**：
    - tokens=`[I, am, so, tired]`，`join(0,2)` 为 `"I am"`

- [x] 3.4 实现 EN 关键词命中：`normalizeENKeyword` + `matchENKeyword`  
  - **规则**：
    - `lowercase`
    - strip 两端常见标点（使用配置 `punctuationStripSetEN`，全端一致）
    - 等值比较（禁止 substring）
  - **验收**：
    - keyword=`but`：`but,` 命中；`rebuttal` 不命中

- [x] 3.5 实现 breaks 字典序比较 `compareBreaksLexicographically(a, b)`  
  - **规则**：
    - 从 index=0 起逐项比较，首个不同元素更小者更小
    - 公共前缀相同则更短数组更小
  - **验收**：
    - `[2] < [3]`
    - `[2] < [2, 5]`
    - `[2, 3] > [2]`

---

## 4. 单元测试（Vitest，纯函数为主）

- [x] 4.1 新建测试目录 `client/src/features/textWrap/core/__tests__/`  
  - **验收**：测试文件可被现有 test runner 发现。

- [x] 4.2 为 `normalizeWhitespace` 增加用例  
  - **覆盖**：多空格、换行、首尾空白、空字符串、全空白字符串  
  - **验收**：测试断言输出字符串与 `hadMultiWhitespace` 符合预期。

- [x] 4.3 为 `tokenizeEN` + `joinTokens` 增加用例  
  - **覆盖**：普通句子、带标点的 token、单词间多个空格（先 normalize 再 tokenize）  
  - **验收**：tokens 序列与 join 后文本完全一致且确定。

- [x] 4.4 为 `matchENKeyword` 增加用例  
  - **覆盖**：大小写、两端标点、误伤样例（rebuttal vs but）  
  - **验收**：命中与不命中行为符合 spec。

- [x] 4.5 为 breaks 字典序比较增加用例  
  - **验收**：比较规则在多组数组上输出稳定顺序。

---

## 5. 最终自检清单（合入前）

- [x] 5.1 `tsc --noEmit` 通过（或项目既有 TS 检查命令通过）  
  - **验收**：无类型错误。

- [x] 5.2 `vitest` 通过（或项目既有测试命令通过）  
  - **验收**：新增用例全部通过，不影响现有测试。

- [x] 5.3 代码注释口径检查（简体中文）  
  - **检查点**：
    - EN 极简派与“断点只在词间”
    - 全词等值匹配（禁止 substring）
    - `start/end` 基于 normalizedText 的口径说明
  - **验收**：后续模块开发者只看代码也不会产生歧义。

---

## 6. 文档回写（任务清单执行完毕后必须做）

- [x] 6.1 在 `spec_kit/overview.md` 的 `Text Wrap` 条目下补充执行状态  
  - **建议写法**：
    - 增加一行：`- **已完成编码（阶段性）**：core-contract（核心口径与契约）`
  - **验收**：overview 能反映该子模块已完成，便于全局追踪。

