mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-05 16:57:32 +00:00
记忆层: - MemoryBlock 承载 FrameTS/PageSeq/PageKind/BlockRole/CallID - coldcontext 归档与回填按完整页传递,工具调用参数和配对键不丢失 - 召回先估算总 token,超预算时按全局页相似度标记 inactive - inactive 仅是 context 渲染期状态,不落盘、不进入 coldcontext,Prune 后重置 - Peek/确认/Remove 两阶段召回,失败保留冷上下文副本 - stablemem 记录 last_recalled_at,删块连带清理边 命名: - internal/memory/document → internal/memory/coldcontext - Doc/DocEvent/DocHit → ColdDoc/ColdEvent/ColdHit - ContextToColdContext/RecentColdContexts/FindColdContexts - 保留既有 JSON 标签、doc_ 文件前缀与 doc_count 状态键,兼容存量数据 安全治理: - 工具策略门禁、安全配置、事件总线发布者身份与入站脱敏 - 声明式 SecurityAPI 与 QQ owner/guest profile - 日志保留策略与相关 e2e/回归判据 验证:go build ./...、go vet ./...、go test ./...(62 包); 生产副本 e2e:7013 块迁移后 ID/向量/指纹 0 变化、0 缺失。
126 lines
3.7 KiB
Go
126 lines
3.7 KiB
Go
package main
|
||
|
||
// 停机**两条路径对称性**的判据(2026-10-17)。
|
||
//
|
||
// ## 缺陷(实测发现)
|
||
//
|
||
// `main()` 里有 `defer ks.CloseAll()`,但 `waitForShutdown` 在重启路径上
|
||
// 调用 `os.Exit(exitRestartRequested)` —— **os.Exit 不跑 defer**。
|
||
// ⇒ 两条退出路径的资源清理**不对称**:
|
||
//
|
||
// 路径 A(SIGTERM): return 到 main → defer CloseAll ✓
|
||
// 路径 B(exit 42): os.Exit 跳过 defer ✗
|
||
//
|
||
// 而路径 B 是**每次热更新都走**的(guard 靠 exit 42 判定"主动重启")。
|
||
// 后果是这些写者从不 flush:
|
||
// · coldcontextStore.Stop() → flush() 文档索引可能陈旧
|
||
// · distiller.Stop() → flush() 待蒸馏规则丢失
|
||
// · textMem.Stop() → Close() 文本记忆未落盘
|
||
//
|
||
// ## 判据怎么咬
|
||
//
|
||
// 不能靠"源码里有 os.Exit 吗"(写意不写实)。这里用 **AST** 检查
|
||
// `waitForShutdown` 函数体里**在 os.Exit 之前**确实调用了传入的
|
||
// stopKernelModules 形参 —— 即"退出前显式关闭",而不是靠 defer。
|
||
|
||
import (
|
||
"go/ast"
|
||
"go/parser"
|
||
"go/token"
|
||
"testing"
|
||
)
|
||
|
||
// ★★★ 判据:waitForShutdown 在 os.Exit 之前显式调用 stopKernelModules。
|
||
func TestWaitForShutdownClosesModulesBeforeExit(t *testing.T) {
|
||
fset := token.NewFileSet()
|
||
f, err := parser.ParseFile(fset, "bootstrap.go", nil, 0)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
var fn *ast.FuncDecl
|
||
for _, d := range f.Decls {
|
||
if fd, ok := d.(*ast.FuncDecl); ok && fd.Name.Name == "waitForShutdown" {
|
||
fn = fd
|
||
}
|
||
}
|
||
if fn == nil {
|
||
t.Fatal("找不到 waitForShutdown")
|
||
}
|
||
|
||
// 找 os.Exit 与 stopKernelModules() 调用的相对位置(按字节偏移)
|
||
exitPos := token.NoPos
|
||
closePos := token.NoPos
|
||
ast.Inspect(fn, func(n ast.Node) bool {
|
||
call, ok := n.(*ast.CallExpr)
|
||
if !ok {
|
||
return true
|
||
}
|
||
if sel, ok := call.Fun.(*ast.SelectorExpr); ok {
|
||
if id, ok := sel.X.(*ast.Ident); ok && id.Name == "os" && sel.Sel.Name == "Exit" {
|
||
if !exitPos.IsValid() {
|
||
exitPos = call.Pos()
|
||
}
|
||
}
|
||
}
|
||
if id, ok := call.Fun.(*ast.Ident); ok && id.Name == "stopKernelModules" {
|
||
if !closePos.IsValid() {
|
||
closePos = call.Pos()
|
||
}
|
||
}
|
||
return true
|
||
})
|
||
|
||
if !exitPos.IsValid() {
|
||
t.Fatal("waitForShutdown 里没有 os.Exit(重启路径怎么退出的?)")
|
||
}
|
||
if !closePos.IsValid() {
|
||
t.Fatal("★ waitForShutdown 从未调用 stopKernelModules ⇒ " +
|
||
"热更新路径(os.Exit 跳过 defer)下模块关闭/落盘全部被跳过")
|
||
}
|
||
if closePos > exitPos {
|
||
t.Fatal("★ stopKernelModules 在 os.Exit **之后** ⇒ 永远不会执行" +
|
||
"(os.Exit 立即终止进程)")
|
||
}
|
||
}
|
||
|
||
// ★★★ 判据:main 必须把真实的 ks.CloseAll 传给 waitForShutdown(不是空函数)。
|
||
func TestMainWiresRealCloseAllIntoShutdown(t *testing.T) {
|
||
fset := token.NewFileSet()
|
||
f, err := parser.ParseFile(fset, "main.go", nil, 0)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
found := false
|
||
ast.Inspect(f, func(n ast.Node) bool {
|
||
call, ok := n.(*ast.CallExpr)
|
||
if !ok {
|
||
return true
|
||
}
|
||
id, ok := call.Fun.(*ast.Ident)
|
||
if !ok || id.Name != "waitForShutdown" {
|
||
return true
|
||
}
|
||
// 最后一个实参必须是含有 CloseAll 调用的函数字面量
|
||
for _, a := range call.Args {
|
||
lit, ok := a.(*ast.FuncLit)
|
||
if !ok {
|
||
continue
|
||
}
|
||
ast.Inspect(lit, func(m ast.Node) bool {
|
||
if c, ok := m.(*ast.CallExpr); ok {
|
||
if sel, ok := c.Fun.(*ast.SelectorExpr); ok && sel.Sel.Name == "CloseAll" {
|
||
found = true
|
||
}
|
||
}
|
||
return true
|
||
})
|
||
}
|
||
return true
|
||
})
|
||
if !found {
|
||
t.Fatal("★ main 传给 waitForShutdown 的 stopKernelModules 里没有 CloseAll ⇒ " +
|
||
"热更新路径下模块不会被关闭(传了个空函数?)")
|
||
}
|
||
}
|