Skip to content

Commit 77e5e26

Browse files
committed
docs(mixed): 明确 ProtectTopN 仅纯码表路径生效(方案 B)
混输路径 convertMixed/convertMixedOverflow 在合并码表+拼音候选后按 weight tier 重排,applyProtectTopN 锁定的位置(只改顺序不改 weight) 会被纯 weight 重排还原。这是有意的设计取舍(方案 B),而非待修 bug: 混输的 tier/boost 体系本身是精心设计的优先级,再叠加位置锁定会冲突。 同步更新 codetable Config 字段注释、schema.go FreqSpec 注释、 codetable/AGENTS.md、docs/design/codetable-engine-refactor.md, 在两个重排点加防御性注释,防止未来被误判为 bug 而"修复"。
1 parent e221ff8 commit 77e5e26

5 files changed

Lines changed: 15 additions & 4 deletions

File tree

docs/design/codetable-engine-refactor.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ type Config struct {
6363
- 应用 `CharsetPreference` 特权(如全码词组提前)。
6464
6. **合并、排序与截断 (Phase 5/6)**:全局排序(`Better``BetterNatural`),应用 `ProtectTopN`,返回最终页。
6565

66+
> **ProtectTopN 作用域(方案 B,2026-06-07)**:本节描述的是码表引擎**自身**的输出顺序,`ProtectTopN` 在此生效。但上层混输引擎(`mixed.convertMixed` / `convertMixedOverflow`)会在合并码表+拼音候选后按 weight tier 重排,且**不补救** `ProtectTopN`(它只改位置不改 weight,会被纯 weight 重排还原)。因此 `ProtectTopN` 实际仅在纯码表路径(`convertCodetableOnly`,短码 < `MinPinyinLength`)对用户可见;多码混输有意不锁首选,与顶码上屏(复用 `e.ConvertEx`,与 UI 同源)保持一致。
67+
6668
## 3. 实施步骤
6769

6870
1. **配置层改造**:扩展 `codetable.Config`,实现向后兼容逻辑。修改 `gen_codetable_wdb` 支持 `HasWeight` 探测。

wind_input/internal/engine/codetable/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
- `PunctCommit`:标点符号触发顶码上屏
2626
- `SingleCodeInput`:关闭前缀匹配,只做精确匹配(逐字键入模式)
2727
- `ShowCodeHint`:候选词显示四码编码提示
28-
- `ProtectTopN`:首选保护,前 N 位锁定**系统码表**原始顺序(通过 `CompositeDict.SearchSystemOnly` 取,仅看 `LayerTypeCell+LayerTypeSystem`,跳过 user/temp/phrase 避免用户词污染肌肉记忆)
28+
- `ProtectTopN`:首选保护,前 N 位锁定**系统码表**原始顺序(通过 `CompositeDict.SearchSystemOnly` 取,仅看 `LayerTypeCell+LayerTypeSystem`,跳过 user/temp/phrase 避免用户词污染肌肉记忆)**作用域**:仅 `convertCodetableOnly` 纯码表路径(短码 < `MinPinyinLength`)生效;混输 `convertMixed`/`convertMixedOverflow` 在合并码表+拼音候选后按 weight tier 重排,**有意不保留**此锁定(方案 B 设计取舍,详见 `mixed.convertMixed` 注释)
2929
- `CandidateSortMode`:候选排序模式,由引擎在每次调用 `CompositeDict.Search/SearchPrefix` 时通过 `dict.SearchOptions.SortMode` 传入(**不再**经由全局 `SetSortMode`,避免多方案共享 dm 时跨方案污染)
3030
- `SkipShadow`:跳过引擎内部的 Shadow 应用,由外层(MixedEngine)统一处理
3131
- `HandleTopCode(input string)` 处理五码输入:截取前四码查找候选,剩余一码作为新输入

wind_input/internal/engine/codetable/codetable.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type Config struct {
4343
SingleCodeComplete bool // 精确匹配空码补全:精确匹配模式下无候选时,从更长编码中取首个候选
4444
DedupCandidates bool // 候选去重(内部开关,未来可能开放给用户)
4545
CandidateSortMode string // 候选排序模式:frequency(词频)、natural(自然顺序)
46-
ProtectTopN int // 首选保护:前 N 位锁定码表原始顺序
46+
ProtectTopN int // 首选保护:前 N 位锁定码表原始顺序(仅 convertCodetableOnly 纯码表路径生效;混输按 weight tier 重排不保留,详见 mixed.convertMixed)
4747
SkipShadow bool // 跳过 Shadow 规则应用(混输模式下由外层统一应用)
4848
SkipSingleCharFreq bool // 单字不自动调频
4949
WeightAsOrder bool // 权重仅表示同码内排序,前缀匹配时抹平权重差异

wind_input/internal/engine/mixed/mixed.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ func (e *Engine) convertMixedOverflow(input string, maxCandidates int) *ConvertR
608608
merged = append(merged, codetableCandidates...)
609609
merged = append(merged, pinyinCandidates...)
610610

611+
// 同 convertMixed:有意不补做 ProtectTopN,混输按 weight tier 重排(理由见 convertMixed)。
611612
sort.SliceStable(merged, func(i, j int) bool {
612613
return candidate.Better(merged[i], merged[j])
613614
})
@@ -774,7 +775,15 @@ func (e *Engine) convertMixed(input string, maxCandidates int) *ConvertResult {
774775
merged = append(merged, pinyinCandidates...)
775776
merged = append(merged, englishCandidates...)
776777

777-
// 按权重排序
778+
// 按权重排序。
779+
//
780+
// 设计取舍(方案 B,2026-06-07):此处【有意不补做】码表子引擎的 ProtectTopN(首选
781+
// 保护)。子引擎 ConvertEx 内部用 applyProtectTopN 把系统码表原始 top-N 锁到固定位置,
782+
// 但它只改位置、不改 weight;下面的纯 weight 重排会把它们还原回 weight 应在的位置。
783+
// 与 Shadow 不同(Shadow 会在 merged 上重新 ApplyShadowPins 补救),ProtectTopN 在混输
784+
// 路径不补救:混输的 tier/boost 体系(码表 +10M / phrase +1M / 拼音 0~100K)本身就是
785+
// 经过设计的优先级,再叠加位置锁定会与之冲突。故 ProtectTopN 仅在 convertCodetableOnly
786+
// (纯码表、短码 < MinPinyinLength)生效,多码混输不锁首选——这是有意设计,勿"修复"。
778787
sort.SliceStable(merged, func(i, j int) bool {
779788
return candidate.Better(merged[i], merged[j])
780789
})

wind_input/internal/schema/schema.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ type AutoPhraseSpec struct {
224224
// FreqSpec 自动调频配置
225225
type FreqSpec struct {
226226
Enabled bool `yaml:"enabled"` // 是否启用自动调频
227-
ProtectTopN int `yaml:"protect_top_n,omitempty"` // 锁定前 N 位候选的排序位置(默认 0 不锁定)
227+
ProtectTopN int `yaml:"protect_top_n,omitempty"` // 锁定前 N 位候选的排序位置(默认 0 不锁定;仅纯码表路径生效,混输按 weight tier 重排不锁首选
228228
HalfLife float64 `yaml:"half_life,omitempty"` // 半衰期(小时,默认 72)
229229
BoostMax int `yaml:"boost_max,omitempty"` // 加成上限(默认 2000)
230230
MaxRecency float64 `yaml:"max_recency,omitempty"` // 时间衰减峰值(默认 300)

0 commit comments

Comments
 (0)