File size: 1,413 Bytes
7a1ad33 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | /**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import type { ConcreteNode } from '../graph/types.js';
import { debugLogger } from '../../utils/debugLogger.js';
/**
* Validates structural and logical invariants of the Episodic Context Graph.
* Primarily used in debug mode to identify "smelly" states before they reach the LLM.
*/
export function checkContextInvariants(
nodes: readonly ConcreteNode[],
context: string,
): void {
const seenIds = new Set<string>();
const duplicates = new Set<string>();
for (const node of nodes) {
if (seenIds.has(node.id)) {
duplicates.add(node.id);
}
seenIds.add(node.id);
}
if (duplicates.size > 0) {
debugLogger.warn(
`[InvariantCheck][${context}] Detected ${duplicates.size} duplicate nodes by ID: ${Array.from(duplicates).join(', ')}`,
);
}
// Check for orphan logic (nodes without turn association)
const orphans = nodes.filter((n) => !n.turnId);
if (orphans.length > 0) {
debugLogger.warn(
`[InvariantCheck][${context}] Detected ${orphans.length} nodes without turnId.`,
);
}
// Check for timestamp linearity
for (let i = 1; i < nodes.length; i++) {
if (nodes[i].timestamp < nodes[i - 1].timestamp) {
debugLogger.warn(
`[InvariantCheck][${context}] Non-linear timestamps detected at index ${i}.`,
);
break;
}
}
}
|