Skip to content

Commit bc8826a

Browse files
test(provenance): cover the enforced branch of the agent memory surface (#6497)
The agent's stored-memory read was the only durable-provenance check site with no test of its enforced path, and the only one whose control flow was restructured by hand. Pin both directions against the shape that failed in production: an unrecorded memory reads through and reports, and the same memory refuses once the memory surface is closed. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 52ee2a5 commit bc8826a

1 file changed

Lines changed: 55 additions & 3 deletions

File tree

apps/sim/executor/handlers/agent/memory.test.ts

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
import { loggerMock } from '@sim/testing'
22
import { beforeEach, describe, expect, it, vi } from 'vitest'
33

4-
const { mockDecryptSecret, mockRedactObjectStrings } = vi.hoisted(() => ({
5-
mockDecryptSecret: vi.fn(),
6-
mockRedactObjectStrings: vi.fn(async (value: unknown) => value),
4+
const { mockDecryptSecret, mockRedactObjectStrings, mockIsEnforced, mockReportUnrecorded } =
5+
vi.hoisted(() => ({
6+
mockDecryptSecret: vi.fn(),
7+
mockRedactObjectStrings: vi.fn(async (value: unknown) => value),
8+
mockIsEnforced: vi.fn(() => false),
9+
mockReportUnrecorded: vi.fn(),
10+
}))
11+
12+
vi.mock('@/lib/execution/durable-secret-provenance-enforcement', () => ({
13+
DURABLE_SECRET_PROVENANCE_SURFACES: ['memory', 'table-row', 'knowledge'],
14+
isDurableSecretProvenanceEnforced: mockIsEnforced,
15+
reportUnrecordedDurableProvenance: mockReportUnrecorded,
716
}))
817

918
vi.mock('@/lib/core/security/encryption', () => ({
@@ -35,6 +44,7 @@ describe('Memory', () => {
3544

3645
beforeEach(() => {
3746
vi.clearAllMocks()
47+
mockIsEnforced.mockReturnValue(false)
3848
mockDecryptSecret.mockImplementation(async (encryptedValue: string) => ({
3949
decrypted: `decrypted:${encryptedValue}`,
4050
}))
@@ -503,6 +513,48 @@ describe('Memory', () => {
503513
expect(messages).toEqual([retainedPublicMessage])
504514
expect(mockDecryptSecret).not.toHaveBeenCalled()
505515
})
516+
517+
/** Trace 2's shape: a stored memory a previous run could not vouch for. */
518+
it('reads a memory with unrecorded provenance while the surface stays open', async () => {
519+
const registry = new ResolvedSecretTraceRegistry([], {
520+
userId: 'user-1',
521+
workspaceId: 'workspace-1',
522+
})
523+
vi.spyOn(memoryService as any, 'fetchMemory').mockResolvedValueOnce({
524+
messages: [{ role: 'user', content: 'how do i see my tickets?' }],
525+
provenance: { status: 'unknown' },
526+
})
527+
528+
const messages = await memoryService.fetchMemoryMessages(
529+
createContext(registry) as never,
530+
inputs
531+
)
532+
533+
expect(messages).toEqual([{ role: 'user', content: 'how do i see my tickets?' }])
534+
expect(registry.isPermanentlyIncomplete()).toBe(false)
535+
expect(mockReportUnrecorded).toHaveBeenCalledWith({
536+
surface: 'memory',
537+
cause: 'stored-memory-provenance-unknown',
538+
workspaceId: 'workspace-1',
539+
})
540+
})
541+
542+
it('refuses that same memory once the memory surface is closed', async () => {
543+
mockIsEnforced.mockReturnValue(true)
544+
const registry = new ResolvedSecretTraceRegistry([], {
545+
userId: 'user-1',
546+
workspaceId: 'workspace-1',
547+
})
548+
vi.spyOn(memoryService as any, 'fetchMemory').mockResolvedValueOnce({
549+
messages: [{ role: 'user', content: 'how do i see my tickets?' }],
550+
provenance: { status: 'unknown' },
551+
})
552+
553+
await expect(
554+
memoryService.fetchMemoryMessages(createContext(registry) as never, inputs)
555+
).rejects.toThrow()
556+
expect(mockReportUnrecorded).not.toHaveBeenCalled()
557+
})
506558
})
507559

508560
describe('secret-safe diagnostics', () => {

0 commit comments

Comments
 (0)