From a7b54fef7fb92cf0d09a3135a601e5a92d41e912 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Sat, 5 Sep 2026 12:08:33 +0800 Subject: [PATCH] =?UTF-8?q?test(memory):=20=E4=BF=AE=E6=AD=A3=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=B8=A2=E5=A4=B1=E5=9B=9E=E5=BD=92=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=E7=9A=84=E6=9E=84=E9=80=A0=E2=80=94=E2=80=94=E5=AE=83=E8=A2=AB?= =?UTF-8?q?=E5=AA=92=E4=BD=93=E4=B8=89=E5=85=83=E7=BB=84=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9C=AC=E8=BA=AB=E5=BC=84=E5=A4=B1=E6=95=88=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两个修复之间产生了耦合:TestArchiveColdDocs_KeepsDocWhenGraphWriteEmpty 的前提是「三元组全被 validEntityName 拒绝」,而同批引入的 mediaTriplesFromText 会为正文里的 [image/png ] 标记产出合规的 「图片 」三元组,于是 ec=4 rc=2、绑定成功、释放引用变成正确行为, 用例的前提消失。 (注意当时 GC 断言并未触发——内容没丢,只是"引用被释放"这条断言不再 适用于该构造。) 改法:正文不再含媒体标记,媒体引用直接 AddRef 挂上。这模拟的是更危险的 组合——文档持有媒体引用,但正文里的媒体标记已在清洗中丢失,于是有引用 要释放却没有句子能承载它。那正是这个守卫要防的情形。 反向验证重做后仍成立:回退守卫 → FAIL(引用被释放 + GC 删掉了本该保留的 内容);恢复修复 → ok。 教训:只跑针对性测试不足以发现修复之间的耦合。提交前我跑的是 internal/agent/core 与 internal/memory,当时通过是因为缺陷二尚未修完; 两个修复都落地后的第一次全仓回归才暴露它。 --- internal/agent/core/graphmedia_test.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/agent/core/graphmedia_test.go b/internal/agent/core/graphmedia_test.go index 42f0f08..8044203 100644 --- a/internal/agent/core/graphmedia_test.go +++ b/internal/agent/core/graphmedia_test.go @@ -388,9 +388,14 @@ func TestArchiveColdDocs_KeepsDocWhenGraphWriteEmpty(t *testing.T) { // 用超长 Source 而不是指望 NLP 提取器:docToTriples 在 // Source != "context_archived" 时会写一条 {文档 -来源-> Source}, // Source 超过 validEntityName 的 50 字符上限 → Commit 静默跳过 - // → len(triples)==1 但 ec=0 rc=0。这正是生产上 456 字 LLM 描述 - // 造成的同一状态,但构造是确定的,不依赖提取器的具体行为 - //(提取器行为随版本变化,测试不该押在它身上)。 + // → len(triples)==1 但 ec=0 rc=0。构造是确定的,不依赖提取器的 + // 具体行为(提取器行为随版本变化,测试不该押在它身上)。 + // + // 正文里刻意**不放**媒体标记:mediaTriplesFromText 会为标记产出 + // 合规的「图片 」三元组,那样 ec/rc 就不为 0,这个用例 + // 也就测不到「全被拒绝」这个状态了。媒体引用直接用 AddRef 挂上, + // 模拟「文档持有媒体但正文的媒体标记已在清洗中丢失」这一情形—— + // 那正是最危险的组合:有引用要释放,却没有句子能承载它。 longSource := strings.Repeat("超长来源名", 20) // 100 字,远超 50 字符上限 // Summary 也必须超长:docToTriples 会为合理 summary 写一条 // {文档 -主题-> summary},那条能通过校验,ec/rc 就不为 0 了。 @@ -399,7 +404,7 @@ func TestArchiveColdDocs_KeepsDocWhenGraphWriteEmpty(t *testing.T) { doc := &document.Doc{ ID: "doc_keep", Summary: longSummary, - Content: "[image/png " + shortDigest(digest) + "] 一张图片的描述", + Content: "一段没有媒体标记的正文", Source: longSource, CreatedAt: time.Now().Add(-200 * time.Hour), LastAccess: time.Now().Add(-200 * time.Hour),