Shared memory and context tools for agentic work.
Code Rooms
/*
* useLiveRefresh core — the live-refresh debounce (HUMAN-LAYER-PRD §5.3).
*
* Verifies the pure heart of the "Living Tree goes live" path with fake timers
* (no React, no DOM — matches the repo's zero-extra-deps test style):
* - a BURST of graph_changed events collapses to ONE refetch (~500 ms debounce)
* - only the `graph_changed` SSE class drives a refetch (reads/persist do not)
* - a mocked EventSource-style feed of graph_changed triggers exactly one reload
*/
import { test, mock } from 'node:test';
import assert from 'node:assert/strict';
import {
createGraphChangeDebouncer,
isGraphChanged,
graphChangeConcernsBrain,
GRAPH_CHANGED_DEBOUNCE_MS,
} from './liveRefreshCore';
import type { SseEvent } from '../types';
test('a burst of graph_changed events debounces to a single refresh', () => {
mock.timers.enable({ apis: ['setTimeout'] });
try {
let refreshes = 0;
const d = createGraphChangeDebouncer(() => (refreshes += 1), GRAPH_CHANGED_DEBOUNCE_MS);
// Simulate an ingest fanning out 5 graph_changed events within the window.
for (let i = 0; i < 5; i++) {
d.fire();
mock.timers.tick(100); // 100 ms apart — inside the 500 ms window
}
assert.equal(refreshes, 0, 'no refresh while the burst is still arriving');
assert.equal(d.pending, true);
// Quiet period elapses → exactly one coalesced refresh.
mock.timers.tick(GRAPH_CHANGED_DEBOUNCE_MS);
assert.equal(refreshes, 1, 'the whole burst collapsed into one refetch');
assert.equal(d.pending, false);
} finally {
mock.timers.reset();
});
test('two bursts separated by a quiet gap yield two refreshes', () => {
assert.equal(refreshes, 1);
assert.equal(refreshes, 2);
test('cancel() disarms a pending refresh (teardown safety)', () => {
d.cancel();
mock.timers.tick(GRAPH_CHANGED_DEBOUNCE_MS * 2);
assert.equal(refreshes, 0, 'a cancelled debouncer never fires');
test('only the graph_changed SSE class triggers a refetch', () => {
const changed: SseEvent = { event_type: 'graph_changed', data: { event: 'memorize' } };
const activation: SseEvent = {
event_type: 'activation',
data: { agent_id: 'a', query: 'x', activated: [], top_k: 0 },
};
const persist: SseEvent = { event_type: 'persist', data: { generation: 3 } };
const ingest: SseEvent = {
event_type: 'ingest',
data: { agent_id: 'a', path: '/p', nodes_added: 1, edges_added: 1 },
assert.equal(isGraphChanged(changed), true);
assert.equal(isGraphChanged(activation), false, 'activation is not a refetch trigger');
assert.equal(isGraphChanged(persist), false, 'persist is not a refetch trigger');
assert.equal(isGraphChanged(ingest), false, 'raw ingest event is not the refetch trigger');
test('a mock EventSource feed of graph_changed drives exactly one reload', () => {
// A minimal EventSource stand-in: register named listeners, then emit.
type Listener = (e: { data: string }) => void;
const listeners = new Map<string, Listener[]>();
const es = {
addEventListener(type: string, fn: Listener) {
const arr = listeners.get(type) ?? [];
arr.push(fn);
listeners.set(type, arr);
},
emit(type: string, data: unknown) {
for (const fn of listeners.get(type) ?? []) fn({ data: JSON.stringify(data) });
let reloads = 0;
const d = createGraphChangeDebouncer(() => (reloads += 1), GRAPH_CHANGED_DEBOUNCE_MS);
// Wire the way useSSE does: a named `graph_changed` listener parses + dispatches.
es.addEventListener('graph_changed', (e) => {
const parsed = JSON.parse(e.data);
if (parsed && typeof parsed.event === 'string') d.fire();
es.emit('graph_changed', { event: 'ingest' });
es.emit('graph_changed', { event: 'memorize' });
assert.equal(reloads, 0, 'still debouncing during the burst');
assert.equal(reloads, 1, 'three server events → one snapshot refetch');
// ── §4A.9.6: brain-scoped refetch — only my brain's mutations disturb my tree ──
const BOUND = null; // the bound view's viewedRoot
const CHERRY = '/path/to/project-b';
const changedFor = (root?: string): SseEvent => ({
event_type: 'graph_changed',
data: root === undefined ? { event: 'memorize' } : { event: 'memorize', brain_root: root },
test('§4A.9.6: an UNSCOPED graph_changed (no brain_root) refetches any viewer (over-refetch on old owners)', () => {
assert.equal(graphChangeConcernsBrain(changedFor(), BOUND), true);
assert.equal(graphChangeConcernsBrain(changedFor(), CHERRY), true);
assert.equal(graphChangeConcernsBrain(changedFor(''), CHERRY), true, 'an empty brain_root is unscoped too');
test('§4A.9.6: a brain-scoped event refetches ONLY the viewer of that brain', () => {
// Viewing project-b: a project-b mutation refetches; a mutation for another brain does not.
assert.equal(graphChangeConcernsBrain(changedFor(CHERRY), CHERRY), true);
assert.equal(graphChangeConcernsBrain(changedFor('/some/other/repo'), CHERRY), false);
test('§4A.9.6: a hosted-brain mutation never disturbs the BOUND tree', () => {
// Bound view (viewedRoot=null): a project-b-scoped event is not for it.
assert.equal(graphChangeConcernsBrain(changedFor(CHERRY), BOUND), false);
test('§4A.9.6: a non-graph_changed event never concerns any brain', () => {
const persist: SseEvent = { event_type: 'persist', data: { generation: 1 } };
assert.equal(graphChangeConcernsBrain(persist, BOUND), false);
assert.equal(graphChangeConcernsBrain(persist, CHERRY), false);