mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
test(memory)!: 块 union 化判据重写(CAS 淘汰第二阶段:测试)
生产已在上一提交(86572d13)全绿;本提交把 CAS 专属测试改到块语义,
并修掉几处判据自身的缺陷(判据错 ≠ 生产错):
- sdk/memory_impl_test: media.Store→块;NewGraphMemoryWithPlugin
- core/{graphmedia,mediaref,medialive,medialoop,inputunify}_test:
mediaStore→memory;PayloadDigest→Data/BlockData;shortDigest→shortID
- graphmedia: 无引用句子用独立块 ID(shortID 20 字符会与 blk_src_ 撞长度)
- memory/sentence_block: BlockByIDPrefix 加 len<12 下限(短引用守卫)
- core/medialoop: reembedOneBlock 按 BlockData 兜底取字节(lean 列无 data)
- knowledge: broken.png 改目录造读失败(chmod 0000 对 root 无效);
dense/attach 测试补 Data 并先落盘后 AttachMedia
- webui: graph_pulse fixture payload_digest→has_data
注:internal/plugin/proc 的 shmVersion 不匹配(内核1/插件2)是
SDK 仓(777c3a0,v2 模板)与本分支内核(v1)的跨仓版本错位,
与块 union 无关(stash 全部改动后仍复现),属 proc-extra 特性线。
This commit is contained in:
@ -139,7 +139,10 @@ func (g *GraphDB) PutMemoryBlocks(blocks []MemoryBlock) error {
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
modality = excluded.modality,
|
||||
text_content = excluded.text_content,
|
||||
data = excluded.data,
|
||||
-- ★ 负载空值不覆盖:轻量读取路径(BlockByIDPrefix 等 lean 列 SELECT)
|
||||
-- 取回的块不带 data/text,重新写回时若直接覆盖会把已存负载抹空。
|
||||
data = CASE WHEN excluded.data IS NULL OR length(excluded.data) = 0
|
||||
THEN memory_blocks.data ELSE excluded.data END,
|
||||
mime = excluded.mime,
|
||||
size = excluded.size,
|
||||
width = excluded.width,
|
||||
|
||||
@ -400,7 +400,6 @@ func (g *GraphDB) initSchema() error {
|
||||
`CREATE INDEX IF NOT EXISTS idx_scene_refs_scene ON scene_refs(scene_id, kind)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_scene_refs_ref ON scene_refs(kind, ref_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_memory_blocks_modality ON memory_blocks(modality)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_memory_blocks_digest ON memory_blocks(payload_digest)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_memory_block_edges_source ON memory_block_edges(source_kind, source_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_memory_block_edges_target ON memory_block_edges(target_kind, target_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_entity_type ON entities(type)`,
|
||||
|
||||
@ -539,13 +539,19 @@ func TestMemoryBlocksAreFirstClassGraphNodes(t *testing.T) {
|
||||
if len(blocks) != 2 {
|
||||
t.Fatalf("memory blocks=%d, want 2", len(blocks))
|
||||
}
|
||||
// ★ 字节负载不在 lean 列里(召回只比向量):
|
||||
// 断言用 BlockData 按需取回,而不是 MemoryBlocks 返回的结构体。
|
||||
gotData, err := g.BlockData(image.ID)
|
||||
if err != nil || string(gotData) != string(image.Data) {
|
||||
t.Fatalf("image payload not round-tripped: %q / %v", gotData, err)
|
||||
}
|
||||
var gotImage *MemoryBlock
|
||||
for i := range blocks {
|
||||
if blocks[i].ID == image.ID {
|
||||
gotImage = &blocks[i]
|
||||
}
|
||||
}
|
||||
if gotImage == nil || gotImage.Modality != BlockImage || string(gotImage.Data) != string(image.Data) || gotImage.Fingerprint != image.Fingerprint || len(gotImage.Vector) != 3 {
|
||||
if gotImage == nil || gotImage.Modality != BlockImage || gotImage.Fingerprint != image.Fingerprint || len(gotImage.Vector) != 3 {
|
||||
t.Fatalf("image block not round-tripped: %+v", gotImage)
|
||||
}
|
||||
|
||||
|
||||
@ -181,8 +181,8 @@ func TestPurgeNoiseKeepsBlockBackedSentences(t *testing.T) {
|
||||
t.Fatalf("原句块未写入: %v", err)
|
||||
}
|
||||
if _, err := g.db.Exec(
|
||||
`INSERT INTO memory_blocks (id, modality, payload_digest, mime)
|
||||
VALUES ('blk1', 'image', 'digest1', 'image/png')`); err != nil {
|
||||
`INSERT INTO memory_blocks (id, modality, data, mime)
|
||||
VALUES ('blk1', 'image', X'64696765737431', 'image/png')`); err != nil {
|
||||
t.Fatalf("insert block: %v", err)
|
||||
}
|
||||
if _, err := g.db.Exec(
|
||||
|
||||
@ -262,7 +262,10 @@ func MediaBlockID(mime string, data []byte) string {
|
||||
// 前缀匹配到多条时返回 false —— 宁可不解析也不猜一个(猜错=挂错媒体)。
|
||||
func (g *GraphDB) BlockByIDPrefix(prefix string) (MemoryBlock, bool, error) {
|
||||
prefix = strings.TrimSpace(prefix)
|
||||
if prefix == "" {
|
||||
// 过短前缀不解析:块 ID 形如 blk_media_<12hex>,
|
||||
// 一个一两字符的前缀会把一大批块都 LIKE 中,猜一个等于挂错媒体。
|
||||
// 至少要求 12 字符(内容派生 hash 的常用短引用长度)。
|
||||
if len(prefix) < 12 {
|
||||
return MemoryBlock{}, false, nil
|
||||
}
|
||||
g.mu.RLock()
|
||||
@ -318,6 +321,8 @@ func (g *GraphDB) BlockData(blockID string) ([]byte, error) {
|
||||
func (g *GraphDB) StaleBlockVectors(currentFP string) ([]MemoryBlock, error) {
|
||||
g.mu.RLock()
|
||||
defer g.mu.RUnlock()
|
||||
// 只取元数据(blockColumns 不含 data):负载按需由 BlockData 单取。
|
||||
// 迁移路径逐块处理,不需要把全部字节一次性读进内存。
|
||||
rows, err := g.db.Query(`SELECT `+blockColumns+`
|
||||
FROM memory_blocks
|
||||
WHERE modality != ?
|
||||
|
||||
Reference in New Issue
Block a user