@@ -196,6 +196,95 @@ def test_validate_receipt_flags_duplicate_only_reflection_memory_writes(tmp_path
196196 ]
197197
198198
199+ def test_validate_receipt_flags_duplicate_reflection_refs_without_fixed_noop_phrase (tmp_path : Path ) -> None :
200+ """Reflection refs that only say candidates are duplicate should not be durable memory."""
201+ memory_root = tmp_path / "project" / "memory"
202+ ref = memory_root / "refs" / "20260519T113111Z-csep-memory-skills-duplicate.md"
203+ ref .parent .mkdir (parents = True )
204+ ref .write_text (
205+ "## CSEP 反思作业\n \n "
206+ "本轮 `memory and skills` 复盘复用既有 `csep-reflect-session-receipt` 流程。\n \n "
207+ "- memory 候选:没有新的长期 fact、rule、preference。\n "
208+ "- skill 候选:workflow 路径与既有 skill 等价,判定为 duplicate。\n "
209+ "- durable 变更:仅记录本轮复盘摘要和 receipt.json。\n " ,
210+ encoding = "utf-8" ,
211+ )
212+ receipt = tmp_path / "receipt.json"
213+ _write_receipt (
214+ receipt ,
215+ memory_changes = [{"path" : str (ref ), "action" : "add" }],
216+ skill_changes = [],
217+ )
218+
219+ result = validate_receipt (
220+ receipt ,
221+ memory_roots = [memory_root ],
222+ skills_root = tmp_path / "skills" ,
223+ skill_prefix = "csep-reflect-" ,
224+ )
225+
226+ assert result ["status" ] == "partial"
227+ assert result ["low_value_memory_writes" ] == [{"reason" : "memory_reflection_noop_ref" , "path" : str (ref )}]
228+
229+
230+ def test_validate_receipt_flags_no_writable_memory_reflection_refs (tmp_path : Path ) -> None :
231+ """No-writable-memory reflection refs are duplicate ledgers even without filename markers."""
232+ memory_root = tmp_path / "project" / "memory"
233+ ref = memory_root / "refs" / "20260519T090154Z-39cbc123.md"
234+ ref .parent .mkdir (parents = True )
235+ ref .write_text (
236+ "# CSEP 复盘记录\n \n "
237+ "- 任务范围:memory and skills。\n "
238+ "- 结果:未发现可写入长期 MEMORY 的新 fact/rule/preference。\n "
239+ "- 判定:继续复用现有 workflow,命中 `csep-reflect-session-receipt`。\n "
240+ "- 处理:本次无生产代码/配置改动、无新技能落地。\n " ,
241+ encoding = "utf-8" ,
242+ )
243+ receipt = tmp_path / "receipt.json"
244+ _write_receipt (
245+ receipt ,
246+ memory_changes = [{"path" : str (ref ), "action" : "add" }],
247+ skill_changes = [],
248+ )
249+
250+ result = validate_receipt (
251+ receipt ,
252+ memory_roots = [memory_root ],
253+ skills_root = tmp_path / "skills" ,
254+ skill_prefix = "csep-reflect-" ,
255+ )
256+
257+ assert result ["status" ] == "partial"
258+ assert result ["low_value_memory_writes" ] == [{"reason" : "memory_reflection_noop_ref" , "path" : str (ref )}]
259+
260+
261+ def test_validate_receipt_allows_non_reflection_duplicate_memory (tmp_path : Path ) -> None :
262+ """Domain notes may mention duplicate behavior without being reflection noise."""
263+ memory_root = tmp_path / "project" / "memory"
264+ ref = memory_root / "refs" / "order-idempotency.md"
265+ ref .parent .mkdir (parents = True )
266+ ref .write_text (
267+ "订单接口会把 duplicate request id 作为幂等重试处理,调用方可以复用同一个 request id 查询结果。\n " ,
268+ encoding = "utf-8" ,
269+ )
270+ receipt = tmp_path / "receipt.json"
271+ _write_receipt (
272+ receipt ,
273+ memory_changes = [{"path" : str (ref ), "action" : "add" }],
274+ skill_changes = [],
275+ )
276+
277+ result = validate_receipt (
278+ receipt ,
279+ memory_roots = [memory_root ],
280+ skills_root = tmp_path / "skills" ,
281+ skill_prefix = "csep-reflect-" ,
282+ )
283+
284+ assert result ["status" ] == "succeeded"
285+ assert result ["low_value_memory_writes" ] == []
286+
287+
199288def test_validate_receipt_rejects_legacy_user_memory (tmp_path : Path ) -> None :
200289 """Legacy USER.md is retained on disk but is no longer writable memory."""
201290 memory = tmp_path / "project" / "memory" / "USER.md"
0 commit comments