package core import ( "encoding/json" "strings" "testing" ) // ★ ZCode 3012 的判据必须是**多形态**的,且误判不是"文案不好看"—— // 领取路径会据此**短路**(跳过本可领取的 plan),而限流与风控的用户动作 // **完全相反**(稍后重试 vs 别重试)。 // // 本判据逐行搬自参考 zcode-diagnostics.ts 的对抗性审计实测矩阵 // (2026-10-05 自审 + 审计打出的真实缺陷)。 // // 为什么用**共用模块**验:这段逻辑被领取路径(插件主体)与推理路径 // (channels-zcode 适配器)共用,任一侧漂移都会让"请勿连续重试"只出现在 // 一条路径上。判据直接打共用模块的导出,两边用的是同一份源码文本。 func TestZcode3012ClassificationMatrix(t *testing.T) { h := newZcodeIdentityHarness(t) cases := []struct { name string body string want bool }{ // ── 真风控(必须命中)── {"上游真实文案(带码)", `{"code":3012,"msg":"request has been blocked due to unusual activity."}`, true}, {"码是纯数字字符串", `{"code":"3012","msg":"x"}`, true}, {"仅正文语义(无数字)", `request has been blocked due to unusual activity.`, true}, {"3012 与 block 紧邻", `3012 blocked by waf`, true}, // ── 必须**不**命中(误判会让用户做错事)── {"13012 不是 3012", `{"code":13012}`, false}, {"标识符 plan-3012-trust", `plan-3012-trust`, false}, {"标识符 trust_3012", `trust_3012`, false}, {"字母包裹 x3012y", `x3012y`, false}, {"限流的毫秒数", `too many requests, retry after 3012 ms`, false}, {"HTML 里的 3012", `

Error 3012

upstream connect timeout`, false}, {"限流+block 距 14", `rate limited: request blocked, retry after 3012 ms`, false}, {"block 距 12", `temporarily blocked; see error 3012`, false}, {"额度码 1005", `{"code":1005,"msg":"quota"}`, false}, // ── 隔离「词边界」规则:这些用例同时满足"block 紧邻", // 只有词边界能区分 ⇒ 裸子串实现会把前三个判成风控。 // (最初的矩阵没覆盖这一组,变异测试因此没咬住 —— 补上后才有效。) {"标识符+block 紧邻", `plan-3012 blocked`, false}, {"字母包裹+block 紧邻", `x3012 blocked`, false}, {"下划线+block 紧邻", `trust_3012 blocked`, false}, {"独立词+block 紧邻", `3012 blocked`, true}, {"13012 里的片段+block 紧邻", `13012 blocked`, false}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got := h.callZD("hasUnusualActivity", tc.body) if got != tc.want { t.Errorf("hasUnusualActivity(%q) = %v, want %v\n"+ "(误判的后果不是文案问题:领取路径会据此短路,且限流='稍后重试'、\n"+ " 风控='别重试',两者用户动作完全相反)", tc.body, got, tc.want) } }) } } // ★ 时间差格式化必须逐档单独算:参考初版把分钟档写成 `floor(seconds % 60)`, // 于是 90 秒被渲染成「30分30秒」(分位取的是**秒的余数**)。 // 该错误是在**真实探针输出**里发现的,纯函数单测当时没覆盖 ≥60 秒的区间。 func TestZcodeFormatGapDoesNotMisrenderMinutes(t *testing.T) { h := newZcodeIdentityHarness(t) for _, tc := range []struct { ms int want string }{ {90000, "1分30秒"}, // 参考踩过的坑:错法会得到 "30分30秒" {59000, "59.0s"}, // 不足一分钟 {60000, "1分"}, // 整分钟 {3600000, "1小时"}, // 整小时 {3900000, "1小时5分"}, // 小时+分 {500, "500ms"}, } { got := h.callZDString("formatGap", tc.ms) if got != tc.want { t.Errorf("formatGap(%d) = %q, want %q", tc.ms, got, tc.want) } } } // ★ 诊断行**绝不能含凭据片段**(参考的设计红线之一)。 // // 账号只以"进程内自增序号"出现。判据用「传入的账号 id 的每个子串都不得出现在 // 文案里」来钉死这条 —— 不是"看起来没有"。 func TestZcodeDiagnosticLeaksNoCredentials(t *testing.T) { h := newZcodeIdentityHarness(t) const secretID = "zcode-abcdef1234567890-SECRET" h.callZDAction("accountOrdinal", secretID) h.callZDAction2("noteRequestSent", secretID, 1000) h.callZDAction2("noteRequestOk", secretID, 1100) diag := h.callZDString("formatDiagnostic", map[string]interface{}{ "accountId": secretID, "sentAt": 1200, "now": 1300, "status": 405, }) if diag == "" { t.Fatal("formatDiagnostic 返回空") } // 账号 id 的每个 >=4 字符子串都不得出现 for i := 0; i+4 <= len(secretID); i++ { if strings.Contains(diag, secretID[i:i+4]) { t.Fatalf("诊断行泄漏账号 id 片段 %q:%s", secretID[i:i+4], diag) } } if !strings.Contains(diag, "账号#") { t.Fatalf("诊断行应含「账号#序号」形态:%s", diag) } t.Logf("✓ 诊断行无凭据片段: %s", diag) } // ★ 3012 的文案必须**共用**(推理 + 领取两条路径),且必须含"请勿连续重试"。 // // 3012 不是"重试就能过"(那是 3007),而是**有账号冷却惩罚**: // 30 分钟起步,反复触发升级到 24 小时乃至停用。 func TestZcode3012MessageIsSharedAndWarnsAboutRetries(t *testing.T) { h := newZcodeIdentityHarness(t) msg := h.callZDString("formatUnusualActivityMessage", map[string]interface{}{ "subject": "领取 plan-x", "rawResponse": "request has been blocked", }) for _, want := range []string{"3012", "请勿连续重试", "冷却惩罚", "领取 plan-x"} { if !strings.Contains(msg, want) { t.Fatalf("风控文案缺 %q:%s", want, msg) } } // 空 subject/diagnostic/rawResponse 时不得留下空壳("本机诊断:"后面啥都没有) bare := h.callZDString("formatUnusualActivityMessage", map[string]interface{}{}) if strings.Contains(bare, "本机诊断:\n") || strings.Contains(bare, "原始响应:\n") { t.Fatalf("空参数不应留下空壳段:%q", bare) } t.Logf("✓ 文案: %s", strings.SplitN(msg, "\n", 2)[0]) } // ★ 请求体形态诊断必须读**真正要发出去的对象**,而不是常量。 // // 常量只能证明"源码里写了多少字",证明不了"线上发出去多少字"。 // 两者一旦不一致(例如某条改动把 system 顶掉了),只有读实际值才看得出来 // —— 它会**如实显示 0 字符**,而不是拿常量里的 2898 把问题盖住。 func TestZcodeRequestShapeReadsActualObject(t *testing.T) { h := newZcodeIdentityHarness(t) // 用真实的适配器产出 → 再诊断它(而不是手搓一个假 system) out, err := h.transformRequest(`{"model":"m","messages":[{"role":"user","content":"hi"}]}`) if err != nil { t.Fatal(err) } var req map[string]interface{} if err := jsonUnmarshal(out, &req); err != nil { t.Fatal(err) } shape := h.callZDMap("describeRequestShape", req["system"], req["messages"]) if shape == nil { t.Fatal("describeRequestShape 返回空") } chars, _ := shape["identityChars"].(float64) if chars < 2800 { t.Fatalf("身份块实测字符数 %v < 2800(诊断必须读实际值)", chars) } if shape["hasDateBlock"] != true { t.Fatalf("应检测到日期块,实得 %v", shape["hasDateBlock"]) } if shape["firstRole"] != "user" { t.Fatalf("firstRole 应为 user,实得 %v", shape["firstRole"]) } t.Logf("✓ 形态诊断: 块数=%v 身份块=%v 日期块=%v role=%v", shape["systemBlocks"], chars, shape["hasDateBlock"], shape["firstRole"]) // 反例:空 system ⇒ 必须**如实显示 0**(不能被常量盖住) empty := h.callZDMap("describeRequestShape", []interface{}{}, req["messages"]) if c, _ := empty["identityChars"].(float64); c != 0 { t.Fatalf("空 system 时 identityChars 必须为 0(如实反映实际值),实得 %v", c) } } // ── harness 助手:经共用的探针打**那一份** ZD 实现 ── // // 走探针而不是让测试自己 load 一份副本:判据必须打真实被两条路径共用的实现, // 自己 load 副本会退化成"各自测各自的",共用一旦漂移就测不出来。 func (h *zcodeIdentityHarness) callZD(fn string, a interface{}) bool { h.t.Helper() res, err := h.ps.Call("channels", "__zcode_diag_probe", map[string]interface{}{"fn": fn, "a": a}) if err != nil { h.t.Fatalf("__zcode_diag_probe(%s): %v", fn, err) } m := res.(map[string]interface{})["json"].(map[string]interface{}) if e, ok := m["error"]; ok { h.t.Fatalf("探针错误(%s): %v", fn, e) } v, ok := m["result"].(bool) if !ok { h.t.Fatalf("%s 返回非布尔: %#v", fn, m["result"]) } return v } func (h *zcodeIdentityHarness) callZDString(fn string, a interface{}) string { h.t.Helper() var res interface{} var err error if opts, ok := a.(map[string]interface{}); ok { res, err = h.ps.Call("channels", "__zcode_diag_probe", map[string]interface{}{"fn": fn, "opts": opts}) } else if fn == "formatGap" { res, err = h.ps.Call("channels", "__zcode_diag_probe", map[string]interface{}{"fn": fn, "a": a}) } else { res, err = h.ps.Call("channels", "__zcode_diag_probe", map[string]interface{}{"fn": fn, "a": a}) } if err != nil { h.t.Fatalf("__zcode_diag_probe(%s): %v", fn, err) } m := res.(map[string]interface{})["json"].(map[string]interface{}) if e, ok := m["error"]; ok { h.t.Fatalf("探针错误(%s): %v", fn, e) } s, _ := m["result"].(string) return s } // callZDAction / callZDAction2:调"动作型"探针(不返回结果,只看没报错)。 func (h *zcodeIdentityHarness) callZDAction(fn string, a interface{}) { h.t.Helper() res, err := h.ps.Call("channels", "__zcode_diag_probe", map[string]interface{}{"fn": fn, "a": a}) if err != nil { h.t.Fatalf("__zcode_diag_probe(%s): %v", fn, err) } if m := res.(map[string]interface{})["json"].(map[string]interface{}); m["error"] != nil { h.t.Fatalf("探针错误(%s): %v", fn, m["error"]) } } func (h *zcodeIdentityHarness) callZDAction2(fn string, a interface{}, a2 int) { h.t.Helper() res, err := h.ps.Call("channels", "__zcode_diag_probe", map[string]interface{}{"fn": fn, "a": a, "a2": a2}) if err != nil { h.t.Fatalf("__zcode_diag_probe(%s): %v", fn, err) } if m := res.(map[string]interface{})["json"].(map[string]interface{}); m["error"] != nil { h.t.Fatalf("探针错误(%s): %v", fn, m["error"]) } } func (h *zcodeIdentityHarness) callZDMap(fn string, args ...interface{}) map[string]interface{} { h.t.Helper() var res interface{} var err error if len(args) == 2 { res, err = h.ps.Call("channels", "__zcode_diag_probe", map[string]interface{}{"fn": fn, "system": args[0], "messages": args[1]}) } else { res, err = h.ps.Call("channels", "__zcode_diag_probe", map[string]interface{}{"fn": fn, "a": args[0]}) } if err != nil { h.t.Fatalf("__zcode_diag_probe(%s): %v", fn, err) } m := res.(map[string]interface{})["json"].(map[string]interface{}) if e, ok := m["error"]; ok { h.t.Fatalf("探针错误(%s): %v", fn, e) } out, _ := m["result"].(map[string]interface{}) return out } // jsonUnmarshal 是本文件用的小助手(避免与其它测试文件的导入冲突)。 func jsonUnmarshal(s string, v interface{}) error { return json.Unmarshal([]byte(s), v) }