mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
## 真实缺陷(v2.0.33 上线后在截图里看到) 日志尾显示成:`能力增强不�` 根因:`tostring(cerr):sub(1, 120)` —— **Lua 的 sub 按字节切**,而中文占 3 字节 ⇒ 切在字符中间产生**替换字符 U+FFFD**。一句本来完整的诊断("…能力增强不可用, 已退回兜底表")看起来像**数据损坏**,实际只是截断方式错。 生产实测复现:该条 120 字节截断后,末尾正好落在"不"字的第 1 字节上, python 侧解码得到 `…能力增强不\ufffd`。**修法**:`plugin.utf8Clip(s, maxBytes)` 先按字节切、再回退到最后一个完整 UTF-8 序列边界(最多退 2 字节)。 三处中文文案截断全部改用它。 ## 判据(1 条静态 + 1 条行为 + 变异 1/1) - `TestLogTruncationIsUTF8Safe`(静态):助手存在 / 三处中文截断不再用裸 sub / 未超长时原样返回 / 回退逻辑处理孤立首字节 - `TestUtf8ClipBehaviour`(**行为**,经 `plugin.__utf8_clip_probe` 走真实函数): 对 6 个长度断言 `utf8.ValidString(out)` 且不超字节上限。静态断言看不出 "结果是否真的合法 UTF-8",所以必须有这一条 —— 实测 n=120 从 `…能力增强不�`(非法)变为 `…能力增强不`(合法) - 变异:把 utf8Clip 换回裸 sub → 报红 ## 排版抛光(截图里可见的三处) - 头部控件原用 `<h2>` + flex,checkbox 被挤到换行且文字竖排 ⇒ 改 `<b>` + 独立 flex 行 + `white-space:nowrap` - 长诊断在窄卡片里被**截断**(而截断的尾巴正是最该看的部分)⇒ `word-break` - 列表加 `line-height`,可读性 ## 兼容性 历史 state 里的 41 条老条目没有 `level` 字段 —— 前端 `e.level || "info"` 已容忍,**不需要数据迁移**(判据亦未假设字段必然存在)。
39 lines
1.1 KiB
Go
39 lines
1.1 KiB
Go
package core
|
||
|
||
import (
|
||
"testing"
|
||
"unicode/utf8"
|
||
)
|
||
|
||
// 行为验证(不只是静态断言):utf8Clip 对中文截断后必须是合法 UTF-8。
|
||
func TestUtf8ClipBehaviour(t *testing.T) {
|
||
c := kernelTestCore(t)
|
||
ps := c.Plugins()
|
||
src, err := readBundledChannels(t)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := ps.LoadSource("channels", src); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
s := "能力元数据源 5.6MB 超过内核 4MiB 响应上限(刻意的堆保护,不为此放宽)—— 能力增强不可用,已退回兜底表"
|
||
for _, n := range []int{10, 40, 119, 120, 121, 400} {
|
||
out, err := ps.Call("channels", "__utf8_clip_probe", map[string]interface{}{"s": s, "n": n})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
got, _ := jsonOf(t, out)["out"].(string)
|
||
if !utf8.ValidString(got) {
|
||
t.Errorf("n=%d 结果不是合法 UTF-8: %q", n, got)
|
||
}
|
||
if n < len(s) && len(got) > n {
|
||
t.Errorf("n=%d 结果超出字节上限: %d", n, len(got))
|
||
}
|
||
if n >= len(s) && got != s {
|
||
t.Errorf("n=%d 未超长时应原样返回", n)
|
||
}
|
||
t.Logf("n=%-4d → %q (valid=%v, bytes=%d)", n, got, utf8.ValidString(got), len(got))
|
||
}
|
||
}
|