把老且长期不活跃的意图/事实折叠成 digest 节点进 graph_overview 展示, 原始节点永久保留、按 id 可完整还原(存储无损、只压呈现、折叠可逆)。 - 数据模型:KindDigest 节点 + RelCovers 边(真相源);新列 content_version、 cold_since_round(节点级)、round_no(任务级 planner 轮次);均带旧库迁移。 - 纯算法(coldgraph.go):冷热判定(逆向可达 + 任一活分支即热) + R=6 轮防抖 + 连通分量分组(§3) + §3.1 同父兄弟归组(救"热 hub+扁平死叶") + §5.3 签名。 - 后台压缩(compaction.go):minor 折未覆盖冷块(tiered)、major 回源重压合并碎片; 签名幂等复用 body;提交时活跃度复核(绝不覆盖已复活节点);60s 冷却 + 互斥。 - 概览折叠(§6):recent_* 剔除已折成员 + 渲染时复活检查;cold_digests + 按资产 索引 cold_index(§6.2);expand_digest/expand_index 还原;covered_members 反查 悬空血缘 id;60 兜底截断均衡保 live。 - planner 每轮 OnPlannerRound 维护戳记并触发后台压缩,绝不上热路径。 纯算法单测覆盖 §附/§3.1/§2.3/§5.3;已对 437 节点真实图验证:热 86、冷候选 324、 §3.1 分组 47 块 + 14 孤立冷点(对齐设计文档实测校验)。
36 lines
1.2 KiB
Go
36 lines
1.2 KiB
Go
package agent
|
|
|
|
import "testing"
|
|
|
|
func TestBalancedCap(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
done, facts, cap int
|
|
wantDone, wantFacts int
|
|
wantTrunc bool
|
|
}{
|
|
{"under cap", 15, 20, 60, 15, 20, false},
|
|
{"exactly cap", 30, 30, 60, 30, 30, false},
|
|
{"both large → even split", 86, 40, 60, 30, 30, true},
|
|
{"intents dominate, facts small kept whole", 86, 5, 60, 55, 5, true},
|
|
{"facts dominate, intents small kept whole", 3, 200, 60, 3, 57, true},
|
|
{"both huge → half/half", 500, 500, 60, 30, 30, true},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
gotDone, gotFacts, trunc := balancedCap(c.done, c.facts, c.cap)
|
|
if gotDone != c.wantDone || gotFacts != c.wantFacts || trunc != c.wantTrunc {
|
|
t.Fatalf("balancedCap(%d,%d,%d) = (%d,%d,%v), want (%d,%d,%v)",
|
|
c.done, c.facts, c.cap, gotDone, gotFacts, trunc, c.wantDone, c.wantFacts, c.wantTrunc)
|
|
}
|
|
if trunc && gotDone+gotFacts > c.cap {
|
|
t.Fatalf("kept %d+%d exceeds cap %d", gotDone, gotFacts, c.cap)
|
|
}
|
|
// never starve a non-empty side to zero when it had items
|
|
if trunc && c.facts > 0 && gotFacts == 0 {
|
|
t.Fatalf("facts starved to 0")
|
|
}
|
|
})
|
|
}
|
|
}
|