# search-engine-widget（技术计划）

## 1. 计划目标

在 **WIDGET** 场景实现确定性的 Beam Search（文档 9.2）：

- 每一行扩展时只保留 TopK partial layouts（beam）
- 每步扩展断点数 M 受控（更强裁剪）
- 支持 `widthMode='MEASURE' | 'APPROX'`
- 结束时从 `pos==N` 的 beams 中选最优；若无解返回可解释的失败原因（最终由 `overflow-fallback` 统一语义）

## 2. 确定性与性能约束

### 2.1 确定性（必须）

- beams 的遍历顺序固定（按当前 beams 排序后的顺序）
- nextPos 候选顺序固定（`pos` 升序）
- pruning 固定（先按候选优先级/位置排序，再取前 M）
- beam 的 TopK 维护固定：`score` 降序；再 `tieKey`；再 `breaks` 字典序

### 2.2 性能参数（写死默认值）

来自文档 9.3：

- `beamK=5`
- `expandM=12`

## 3. Beam Search 设计（对应文档 9.2）

令 `N=tokens.length`，token 边界为 `pos in [0..N]`。

### 3.1 beam 状态

一个 beam（partial layout）包含：

- `pos`：当前已覆盖到的 token 边界
- `breaks: number[]`
- `lines: LineInfo[]`
- `score` + `tieKey`
- `meta`（可选）：debug Top-3 terms、approx reason 等

### 3.2 扩展 nextPos（每步最多 M）

对每个 beam，从 `pos` 扩展到若干 `nextPos`：

- nextPos 来源：`breakpoints[].pos > pos`（按 pos 升序）
- 额外包含 `nextPos=N`（结束边界）
- 为控制复杂度：对候选 nextPos 进行裁剪，仅保留前 `expandM`

裁剪规则（确定性，首版简单可控）：

- 先取 `nextPos` 最小的 `expandM` 个（最短前缀优先，利于早结束）

> 注：后续可升级为“优先级 + 距理想切分点近”裁剪，但首版以确定性与稳定为主。

### 3.3 宽度模式

- `widthMode='MEASURE'`：
  - 若提供测量能力：使用 `measureSliceWidthCached` 获取 lineWidth
  - 若测量不可用/失败：降级为 approx（记录 `reason=WIDTH_UNKNOWN` 或 `MEASURE_FAILED`），lineWidth 采用近似值
- `widthMode='APPROX'`：
  - 不调用测量；lineWidth 使用近似值：
    - EN：`tokenCount`
    - TC：`charCount`
  - meta 标记 `reason=WIDTH_UNKNOWN`

### 3.4 硬约束（最小集）

与 App 一致的最小硬约束：

- 禁止空行：`nextPos > pos`
- 最大行数：lineIndex 不超过 `maxLines`
- TC 禁止行首标点（H6）：若 `tokens[nextPos]` 属于 `tcPunctuations` 则该转移无效
- 超宽约束：
  - MEASURE 模式下若 width 可用且 `lineWidth > availableWidth`，转移无效
  - APPROX 模式下不执行超宽硬过滤（因为单位不一致），交给评分处理

### 3.5 每轮保留 beamK

对所有扩展出来的新 beams：

- 使用 TopK 维护（去重同 breaks，排序按 score/tieKey/breaks）
- 全局只保留 `beamK` 个作为下一轮 beams

### 3.6 结束选择

重复扩展最多 `maxLines` 轮后：

- 优先从 beams 中选 `pos==N` 的最优
- 若无 `pos==N`：返回 `NO_CANDIDATE`（由 overflow-fallback 统一兜底语义）

## 4. 代码落位（客户端）

- `client/src/features/textWrap/searchWidget/`
  - `types.ts`
  - `beam.ts`
  - `topK.ts`（可复用 App 逻辑，首版复制一份避免耦合）
  - `constraints.ts`
  - `index.ts`
  - `__tests__/searchWidget.test.ts`

## 5. 测试计划（Vitest）

- 确定性：同输入重复执行输出一致
- 性能约束：beamK/expandM 生效（可通过构造大量断点断言扩展次数上限）
- widthMode=APPROX：仍能产出结果，且 meta.reason=WIDTH_UNKNOWN
- TC H6：行首标点转移被禁止

## 6. 完成定义（DoD）

- Beam Search 可运行，且确定性单测通过
- 宽度模式与降级 meta 符合 spec
- 性能参数默认值写死且可覆盖
- 更新 overview 标记阶段性完成并记录变更文件

