# width-measurement（子模块规范）

## 子模块名称

width-measurement（宽度测量与降级）

## 目标描述

提供统一的宽度测量接口与缓存策略，并定义“宽度不可用”时的确定性降级行为（approx mode），确保 APP 与 WIDGET 在测量能力差异下仍能：

- 保持搜索/评分流程可运行
- 输出可解释（meta 打点）
- 性能稳定（缓存与上限）

## 输入/输出定义

### 输入

- `context: 'APP' | 'WIDGET'`
- `fontSpec?: { fontSize: number; fontWeight?: string; fontFamily?: string }`
- `measureWidth?: (text: string, fontSpec) => number`（可选注入）
- `text: string`
- `slice?: { start: number; end: number }`（可选：段落切片测量）

### 输出

- `width: number | null`
  - 当不可用/失败时返回 `null`（触发 approx mode）
- `meta?: { isApprox: boolean; reason?: 'WIDTH_UNKNOWN' | 'MEASURE_FAILED' }`

并提供缓存约定（逻辑输出）：

- 字符串测量缓存 key：`(text, fontSpecKey, contextProfile)`
- 切片测量缓存 key：`(start, end, fontSpecKey, contextProfile)`

## 验收标准（可验证）

- **测量一致**：在 APP 注入 `measureWidth` 时，同一输入重复测量命中缓存（不会重复计算）
- **失败降级**：`measureWidth` 缺失/抛错/返回 NaN 时：
  - 输出 `width=null`
  - meta 标记 `isApprox=true` 且 reason 可追踪
- **approx mode 口径一致**：
  - EN：宽度近似值使用 `wordCount`
  - TC：宽度近似值使用 `charCount`（或 grapheme 数）
- **确定性**：相同输入在相同 contextProfile 下，测量与降级行为一致

## 依赖与关联

- **被依赖**：`search-engine-app`、`search-engine-widget`、`overflow-fallback`
- **依赖**：`core-contract`（fontSpecKey 规范化、切片文本重组）

