# overflow-fallback(技术计划) ## 1. 计划目标 实现统一的“溢出与兜底”策略模块,用于在以下情况给出确定性且可解释的返回: - 搜索器无法在 `<=maxLines` 覆盖到结束边界 `N` - `lineMode=FIXED` 需要刚好 `maxLines` 但无解 - 测量不可用或失败导致无法执行宽度派约束(尤其 Widget) 支持三种模式: - `ELLIPSIS`:最后一行加省略号并保证不超宽(必要时回退移除 token 再加) - `CLIP`:截断到 `maxLines`(不加省略号) - `SYSTEM_DEFAULT`:算法层不插入换行,交给系统排版(仅在 meta 标记) ## 2. 对外输入/输出(与 spec 对齐) ### 2.1 输入 - `tokens: Token[]` - `partialLayout?: { breaks: number[]; lines: Array<{ start; end; text? }> }` - 若提供:表示搜索器的 best-effort(可能未覆盖到 N) - `overflowMode: 'ELLIPSIS' | 'CLIP' | 'SYSTEM_DEFAULT'` - `availableWidth: number` - `maxLines: number` - `lang: 'TC' | 'EN'` - `context: 'APP' | 'WIDGET'` - `ellipsisToken: string`(推荐 `"…"`,配置化) - `measure?: { contextProfile; fontSpec; measureWidthImpl; widgetEnableMeasure? }`(用于“加省略号后再测量”) - `reason: 'NO_CANDIDATE' | 'WIDTH_UNKNOWN' | 'TOO_LONG' | 'WIDOW' | 'PARTICLE' | string` ### 2.2 输出 统一返回: - `result: { lines: string[]; wrappedText: string; meta: { fallback_type; overflow_type; reason } }` 其中: - `fallback_type`: `NONE | RELAX_RULES | SYSTEM_DEFAULT` - `overflow_type`: `NONE | ELLIPSIS | CLIP` ## 3. 核心行为细则(对应文档 12.x) ### 3.1 overflow 判定 在本模块内不重新跑搜索,仅基于输入判断: - 若 `partialLayout` 覆盖到 `N`(即最后一行 `end==N`),则 overflow_type=NONE - 否则为 overflow,按 overflowMode 执行 ### 3.2 SYSTEM_DEFAULT(12.4A) - 返回 `lines=[原文单行]`,`wrappedText=原文` - `meta.fallback_type='SYSTEM_DEFAULT'` - `meta.overflow_type='NONE'`(因为不再输出算法换行;由 UI 决定是否完全交给系统) - `meta.reason=输入 reason` ### 3.3 CLIP - 若 `partialLayout` 有 lines:取前 `maxLines` 行,重组 `wrappedText=lines.join('\n')` - 若无:返回单行原文 - `meta.overflow_type='CLIP'`,`fallback_type='NONE'`,`reason=输入 reason` ### 3.4 ELLIPSIS(12.3/12.5) 仅处理最后一行: 1. 选取 baseLines: - 优先使用 `partialLayout.lines`(若为空则把全文当单行) - 截断到 `maxLines`(只在最后一行做 ellipsis) 2. 清理规则(固定,确定性): - 不输出 `" …"`:最后一行末尾空白先 trim - 不输出 `",…"/"。…"`:若最后一行末尾是常见 TC 标点(`,。!?;:、`),则移除该标点再加 ellipsis 3. 宽度检查(12.3): - 若提供测量能力且启用: - 重新测量 `lastLine+ellipsisToken` - 若超宽:按语言回退单位移除 token 再加省略号并重测 - EN:按整词(token) - TC:按 grapheme(token) - 若测量不可用:不做重测,直接输出(meta.reason 仍保留) > 说明:首版不做“避免截断 emotionPhrase 的整段前移/整段省略”,该策略可在后续结合 scoring 决策升级,但必须保持确定性。 ## 4. 代码落位(客户端) - `client/src/features/textWrap/overflow/` - `types.ts` - `ellipsis.ts` - `fallback.ts`(入口:applyOverflowFallback) - `index.ts` - `__tests__/overflowFallback.test.ts` ## 5. 测试计划(Vitest) - SYSTEM_DEFAULT:lines 单行,meta.fallback_type=SYSTEM_DEFAULT - CLIP:超过 maxLines 时截断行数 - ELLIPSIS: - 末尾空白去除,不输出 `" …"` - 末尾 TC 标点去除,不输出 `",…"` - 测量超宽时按 token 回退直到不超宽(用 mock measureWidthImpl) ## 6. 完成定义(DoD) - 三种 overflowMode 行为稳定且可解释 - ELLIPSIS 的清理与回退测量实现完毕(可测) - 输出 meta 字段满足文档 12/14 的治理需求