package repo import ( "encoding/json" "fmt" "os" "path/filepath" "sort" "strings" "testing" ) /* 欠账的**单一余额**(pi 2026-09-14 裁定 §3)。 背景:到这轮为止已经有三笔不同类型、各自表达方式的欠账 —— 鸿蒙静态判据(`RESULT static=5`,有余额、有到期探针)、 `mails.status` 行级派生化(`t.Skip`,**原先无余额**)、 手势语义契约(登记的到期前提,**原先无余额**)。 三笔都"可判",但**没有一处能一眼看全**;而"欠账不显形就等于没有"。 所以:**登记在一处、可打印**。Go 这一侧打印在 TestMain 收尾, 跨端的净值同时登记在 `docs/DEBTS.json`(两端都能读,见该文件)。 */ type debt struct { ID string Count int Due string // 到期前提(什么时候该还清) Where string // 判据在哪 } var debts = map[string]debt{ "mails-status-derived": { ID: "mails-status-derived", Count: 0, // 由 mail_status_derived_test.go **实测**后标 1(不许手写:常量余额 = 永久 Skip 的死法) Due: "详情/线程改为按读者派生(readStateFor)之后 —— 那时 mail_status_derived_test.go 从 Skip 转实跑", Where: "server/internal/repo/mail_status_derived_test.go", }, "static-criteria": { ID: "static-criteria", Count: 5, Due: "本工作区能装、能点设备(探针三值转 true 时自动变红)", Where: "client/electron/test/run-all.mjs(STATIC_ONLY)", }, "gesture-semantics": { ID: "gesture-semantics", Count: 1, Due: "P6 第 3 步:鸿蒙侧出现滑动手势代码时立即建(此前建 = 只有一端存在的假判据)", Where: "docs/HARMONY-ALIGN-PLAN.md P6 段", }, } // debtMark 由各条欠账的判据在"确认未清"时调用(余额来自**测量**,不是常量)。 func debtMark(id string) { d := debts[id] d.Count = 1 debts[id] = d } type debtLedger struct { Debts []struct { ID string `json:"id"` Count int `json:"count"` Due string `json:"due"` Where string `json:"where"` } `json:"debts"` } // loadDebts 读**那一份**登记(docs/DEBTS.json):两端的余额必须来自同一处。 func loadDebts(t *testing.T) debtLedger { t.Helper() b, err := os.ReadFile(filepath.Join("..", "..", "..", "docs", "DEBTS.json")) if err != nil { t.Fatalf("读欠账登记 docs/DEBTS.json 失败:%v(登记丢了 = 欠账不显形)", err) } var l debtLedger if err := json.Unmarshal(b, &l); err != nil { t.Fatalf("欠账登记不是合法 JSON:%v", err) } return l } /* ★ 登记与**实测**必须一致(pi 2026-09-14 裁定 §1:Skip 的条件要是测量结果,"跳过"要进余额)。 这条判据挡的是两种死法: ① 条件被写死:余额不是从测量来的,而是某人抄的数字 ⇒ 这里用 debtMark 的实测值比对; ② 跳过不可数:`go test` 对 Skip 是退出码 0、`--- SKIP` 只是一行输出 (而且**跑得通时 go test 根本不打印包的输出** —— 我第一次就把余额打在 TestMain 里, 结果常态运行时一个字都看不见,正是"不显形")。所以可见的那份在 electron 套件的 RESULT 行(它读同一个文件),这里保证两处**同源**。 */ func TestDebtLedgerMatchesMeasurement(t *testing.T) { l := loadDebts(t) seen := map[string]bool{} for _, d := range l.Debts { seen[d.ID] = true if d.Due == "" || d.Where == "" { t.Fatalf("欠账 %s 必须写明到期前提与判据位置(否则它只是「存在」,不是「欠账」)", d.ID) } } for _, id := range []string{"static-criteria", "mails-status-derived", "gesture-semantics"} { if !seen[id] { t.Fatalf("欠账登记里缺 %s —— 三笔必须同处登记,否则审计只会找到一处就当全部", id) } } // 本包能实测的那一笔:**自己测**(不依赖别的测试先跑过 —— 排序依赖是隐蔽的假绿) var want int for _, d := range l.Debts { if d.ID == "mails-status-derived" { want = d.Count } } outstanding, detail, derived := measureMailStatusDebt(t) got := 0 if outstanding { got = 1 } if got != want { if got == 0 { t.Fatalf("**欠账已还清**(详情 %q 已等于按读者派生 %q),但 docs/DEBTS.json 还记着 %d —— "+ "还清是可测事件,登记要跟着清(这正是这条判据存在的意义)", detail, derived, want) } t.Fatalf("mails-status-derived 的余额:登记说 %d,实测说 %d —— 登记与测量分叉了", want, got) } } // debtSummary 供 TestMain 打印:一处能看全的余额 + 到期前提。 func debtSummary() string { ids := make([]string, 0, len(debts)) total := 0 for id, d := range debts { if d.Count > 0 { ids = append(ids, id) total += d.Count } } if len(ids) == 0 { return " debts=0(全部还清)" } sort.Strings(ids) var b strings.Builder fmt.Fprintf(&b, "\n======= 欠账余额 debts=%d =======", total) for _, id := range ids { d := debts[id] fmt.Fprintf(&b, "\n · %s ×%d\n 判据:%s\n 到期:%s", d.ID, d.Count, d.Where, d.Due) } fmt.Fprintf(&b, "\n(三笔合在一处看全:分散登记时,审计只会找到一处就当全部)") return b.String() }