diff --git a/mateclaw-server/src/test/java/vip/mate/channel/wecom/cards/tool_guard/ToolGuardCardHandlerTest.java b/mateclaw-server/src/test/java/vip/mate/channel/wecom/cards/tool_guard/ToolGuardCardHandlerTest.java index d1873f62..77c8b6eb 100644 --- a/mateclaw-server/src/test/java/vip/mate/channel/wecom/cards/tool_guard/ToolGuardCardHandlerTest.java +++ b/mateclaw-server/src/test/java/vip/mate/channel/wecom/cards/tool_guard/ToolGuardCardHandlerTest.java @@ -130,8 +130,8 @@ class ToolGuardCardHandlerTest { } @Test - @DisplayName("system-owned pending allows ANY clicker (no original requester)") - void systemPendingAcceptsAnyClicker() { + @DisplayName("system-owned pending rejects a group clicker (fail-closed → admin console)") + void systemPendingRejectsGroupClicker() { PendingApproval pending = pendingFor("pid_sys", "system", "shell_exec"); when(approvalService.getPending("pid_sys")).thenReturn(Optional.of(pending)); @@ -139,7 +139,11 @@ class ToolGuardCardHandlerTest { ToolGuardButtonKey.Action.APPROVE, "pid_sys", "shell_exec", "MEDIUM")); handler.handle(adapter, frame, tce(frame), fromBlock("anyone")); - verify(adapter).injectSyntheticMessage(any(ChannelMessage.class)); + // A "system"/cron-owned approval has no human requester to match the + // clicker against, so a group button click is rejected (fail-closed) and + // never injected for execution — these resolve through the admin console. + verify(adapter, never()).injectSyntheticMessage(any(ChannelMessage.class)); + verify(adapter).updateTemplateCard(eq("evt_req_5"), any()); } @Test diff --git a/mateclaw-server/src/test/java/vip/mate/memory/service/MemorySummarizationStructuredRoutingTest.java b/mateclaw-server/src/test/java/vip/mate/memory/service/MemorySummarizationStructuredRoutingTest.java index 92714ce5..b8720274 100644 --- a/mateclaw-server/src/test/java/vip/mate/memory/service/MemorySummarizationStructuredRoutingTest.java +++ b/mateclaw-server/src/test/java/vip/mate/memory/service/MemorySummarizationStructuredRoutingTest.java @@ -36,12 +36,13 @@ class MemorySummarizationStructuredRoutingTest { structured); } - private void invokeApply(MemorySummarizationService svc, long agentId, String entriesJson) throws Exception { + private void invokeApply(MemorySummarizationService svc, long agentId, String ownerKey, String entriesJson) + throws Exception { JsonNode node = mapper.readTree(entriesJson); Method m = MemorySummarizationService.class - .getDeclaredMethod("applyStructuredEntries", Long.class, JsonNode.class); + .getDeclaredMethod("applyStructuredEntries", Long.class, JsonNode.class, String.class); m.setAccessible(true); - m.invoke(svc, agentId, node); + m.invoke(svc, agentId, node, ownerKey); } @Test @@ -50,15 +51,15 @@ class MemorySummarizationStructuredRoutingTest { StructuredMemoryService structured = mock(StructuredMemoryService.class); MemorySummarizationService svc = newService(structured); - invokeApply(svc, 1000000001L, """ + invokeApply(svc, 1000000001L, "owner-1", """ [ {"type": "project", "key": "project_codename", "content": "项目代号:云梯计划"}, {"type": "user", "key": "preferred_output_format", "content": "偏好表格输出"} ] """); - verify(structured).remember(1000000001L, "project", "project_codename", "项目代号:云梯计划", "auto-summary"); - verify(structured).remember(1000000001L, "user", "preferred_output_format", "偏好表格输出", "auto-summary"); + verify(structured).remember(1000000001L, "project", "project_codename", "项目代号:云梯计划", "auto-summary", "owner-1"); + verify(structured).remember(1000000001L, "user", "preferred_output_format", "偏好表格输出", "auto-summary", "owner-1"); verifyNoMoreInteractions(structured); } @@ -68,7 +69,7 @@ class MemorySummarizationStructuredRoutingTest { StructuredMemoryService structured = mock(StructuredMemoryService.class); MemorySummarizationService svc = newService(structured); - invokeApply(svc, 1000000001L, """ + invokeApply(svc, 1000000001L, "owner-1", """ [ {"type": "secret", "key": "k", "content": "bad type"}, {"type": "project", "key": "", "content": "missing key"}, @@ -78,7 +79,7 @@ class MemorySummarizationStructuredRoutingTest { """); // Only the last, fully-valid entry is written. - verify(structured).remember(1000000001L, "project", "good", "kept", "auto-summary"); + verify(structured).remember(1000000001L, "project", "good", "kept", "auto-summary", "owner-1"); verifyNoMoreInteractions(structured); } @@ -88,9 +89,9 @@ class MemorySummarizationStructuredRoutingTest { StructuredMemoryService structured = mock(StructuredMemoryService.class); MemorySummarizationService svc = newService(structured); - invokeApply(svc, 1000000001L, "null"); - invokeApply(svc, 1000000001L, "\"not-an-array\""); - invokeApply(svc, 1000000001L, "[]"); + invokeApply(svc, 1000000001L, "owner-1", "null"); + invokeApply(svc, 1000000001L, "owner-1", "\"not-an-array\""); + invokeApply(svc, 1000000001L, "owner-1", "[]"); verifyNoInteractions(structured); }