diff --git a/packages/agent/test/context-graph-public-meta-proof.test.ts b/packages/agent/test/context-graph-public-meta-proof.test.ts index 582b1a210f..e31b48eed7 100644 --- a/packages/agent/test/context-graph-public-meta-proof.test.ts +++ b/packages/agent/test/context-graph-public-meta-proof.test.ts @@ -83,6 +83,14 @@ describe('authoritative public metadata proof', () => { })), expected: false, }, + { + name: 'definition stored outside the root metadata graph', + mutate: (quads: Quad[]) => quads.map((quad) => ({ + ...quad, + graph: quad.subject, + })), + expected: false, + }, ]; for (const [index, proofCase] of cases.entries()) { diff --git a/packages/cli/test/context-graph-subscribe-readiness.test.ts b/packages/cli/test/context-graph-subscribe-readiness.test.ts index 65549e02fc..6eac7e0137 100644 --- a/packages/cli/test/context-graph-subscribe-readiness.test.ts +++ b/packages/cli/test/context-graph-subscribe-readiness.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it } from 'vitest'; import { createServer, type Server } from 'node:http'; -import type { CatchupJobResult } from '../src/catchup-runner.js'; +import type { CatchupJobResult, CatchupRunRequest } from '../src/catchup-runner.js'; import { handleContextGraphRoutes } from '../src/daemon/routes/context-graph.js'; import { handleQueryRoutes } from '../src/daemon/routes/query.js'; import { daemonState } from '../src/daemon/state.js'; @@ -155,6 +155,7 @@ describe('context graph subscribe readiness requires authoritative metadata', () response: any; job: any; runCalls: number; + runRequests: CatchupRunRequest[]; state: Record; patches: Array>; readiness: Record | undefined; @@ -169,13 +170,15 @@ describe('context graph subscribe readiness requires authoritative metadata', () latestByContextGraph: new Map(), }; let runCalls = 0; + const runRequests: CatchupRunRequest[] = []; let readiness = opts.readiness ? { ...opts.readiness, updatedAt: opts.readiness.updatedAt ?? Date.now() } : undefined; daemonState.catchupRunner = { - run: async () => { + run: async (request) => { runCalls += 1; + runRequests.push(request); return opts.result ?? cleanEmptyResult(); }, close: async () => {}, @@ -279,6 +282,7 @@ describe('context graph subscribe readiness requires authoritative metadata', () response, job: catchupTracker.jobs.get(jobId), runCalls, + runRequests, state: state.get(contextGraphId) ?? {}, patches, readiness, @@ -498,6 +502,10 @@ describe('context graph subscribe readiness requires authoritative metadata', () status: 'queued', jobId: expect.any(String), }); + expect(result.runRequests).toEqual([{ + contextGraphId: result.response.subscribed, + includeSharedMemory: true, + }]); expect(result.statusResponse).toMatchObject({ jobId: result.response.catchup.jobId, status: 'done', diff --git a/packages/node-ui/src/ui/components/Shell/PanelLeft.tsx b/packages/node-ui/src/ui/components/Shell/PanelLeft.tsx index 690df4e66b..d6d7dc3b7d 100644 --- a/packages/node-ui/src/ui/components/Shell/PanelLeft.tsx +++ b/packages/node-ui/src/ui/components/Shell/PanelLeft.tsx @@ -421,6 +421,7 @@ export function PanelLeft() { cg={cg} isBrowsing={activeTabId === `project:${cg.id}`} onBrowse={() => { + setActiveProject(null); openTab({ id: `project:${cg.id}`, label: cg.name || cg.id.slice(0, 16), diff --git a/packages/node-ui/test/panel-left.test.ts b/packages/node-ui/test/panel-left.test.ts index 341ffc98a0..e7d764696b 100644 --- a/packages/node-ui/test/panel-left.test.ts +++ b/packages/node-ui/test/panel-left.test.ts @@ -278,21 +278,31 @@ describe('PanelLeft — sidebar cleanup + collapsible sections', () => { expect(container.textContent).toContain('Public Ready Graph'); }); - it('keeps a passive public catalogue result separate from project activation', async () => { + it('clears the previous project target when browsing a passive public catalogue result', async () => { const { container } = await renderPanel(); const { useProjectsStore } = await import('../src/ui/stores/projects.js'); const { useTabsStore } = await import('../src/ui/stores/tabs.js'); act(() => { useProjectsStore.setState({ - contextGraphs: [{ - id: 'public-passive', - name: 'Passive Public Graph', - accessPolicy: 'public', - callerInvolved: false, - subscribed: false, - synced: false, - } as any], - activeProjectId: null, + contextGraphs: [ + { + id: 'private-active', + name: 'Previously Active Private Graph', + accessPolicy: 'private', + callerInvolved: true, + subscribed: true, + synced: true, + } as any, + { + id: 'public-passive', + name: 'Passive Public Graph', + accessPolicy: 'public', + callerInvolved: false, + subscribed: false, + synced: false, + } as any, + ], + activeProjectId: 'private-active', }); useTabsStore.setState({ tabs: [{ id: 'dashboard', label: 'Dashboard', closable: false }],