@modernrelay/orbit-core 0.13.5 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/testing/FakeEngine.ts","../src/testing/rafAudit.ts","../src/testing/workerDouble.ts"],"names":[],"mappings":"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","file":"testing.js","sourcesContent":["/**\n * FakeEngine — the public headless test seam (§18 /testing, §19).\n *\n * Implements the full GraphEngine adapter contract with zero DOM/WebGL access\n * so consumer suites can run under node/jsdom. Every public method call is\n * recorded to `calls` in order; commits and camera calls get typed convenience\n * views. Test-only helpers (`stepFrame`, `nudgePositions`, `inject*`) let\n * suites observe applied-revision lag, simulate position drift, and drive\n * host events.\n *\n * The state MIRRORS (`pinnedIndices`, `selectedIndices`, `lastStructure`,\n * `lastBuffer`) answer \"what does the engine currently hold?\", which the raw\n * `calls`/`commits` logs cannot: pins, highlight, structure and each buffer\n * channel are committed on independent schedules, so the newest entry is\n * rarely the newest value for a given channel.\n */\n\nimport type {\n EngineCapabilities,\n EngineCommit,\n EngineDiagnostic,\n EngineHostEvents,\n FitViewOptions,\n GraphEngine,\n} from '../engine/index';\nimport type { ViewportState } from '../types';\n\nexport interface FakeEngineOptions {\n /** Overrides merged over the defaults (linkPicking/trackedPositions false, rangeUpdates [], simulation true). */\n capabilities?: Partial<EngineCapabilities>;\n /**\n * When true, commits queue instead of applying immediately; `stepFrame()`\n * applies the oldest queued commit. Lets tests observe the lag between the\n * desired-render revision and `appliedRevision()`.\n */\n manualFrames?: boolean;\n /**\n * When set, `mount()` records the call, does NOT store the host events, and\n * rejects with this error — simulates an engine that cannot initialize.\n */\n mountError?: Error;\n /** Resolved by `captureScreenshot()`; default null (unsupported/not ready). */\n screenshot?: Blob | null;\n}\n\n/** One recorded public method invocation. */\nexport interface RecordedCall {\n method: string;\n args: readonly unknown[];\n}\n\nconst DEFAULT_CAPABILITIES: EngineCapabilities = {\n linkPicking: false,\n rangeUpdates: [],\n trackedPositions: false,\n simulation: true,\n // §17: the FakeEngine schedules nothing on its own — frames exist only\n // when a test calls stepFrame()/emitFrame() — so it is quiescent by\n // construction, and those calls apply-then-emit, which is genuinely\n // post-draw.\n idleFrames: 'stops',\n postDrawFrames: true,\n};\n\nconst CAMERA_METHODS: ReadonlySet<string> = new Set([\n 'fitView',\n 'zoom',\n 'setViewport',\n 'zoomToIndex',\n]);\n\n/** Deterministic seed for an unknown (NaN) position: a 10px grid, 100 per row. */\nfunction seedPosition(index: number): readonly [number, number] {\n return [(index % 100) * 10, Math.floor(index / 100) * 10];\n}\n\n/** Standard even-odd ray cast (screen == space in the FakeEngine). */\nfunction pointInPolygon(x: number, y: number, polygon: readonly [number, number][]): boolean {\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const [xi, yi] = polygon[i]!;\n const [xj, yj] = polygon[j]!;\n const crosses = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;\n if (crosses) inside = !inside;\n }\n return inside;\n}\n\nexport class FakeEngine implements GraphEngine {\n readonly capabilities: EngineCapabilities;\n\n /** Every public method call, in order. */\n readonly calls: RecordedCall[] = [];\n /** Every commit passed to `commit()`, in call order (queued or applied). */\n readonly commits: EngineCommit[] = [];\n /** The fitView/zoom/setViewport/zoomToIndex entries of `calls`, in order. */\n readonly cameraCalls: RecordedCall[] = [];\n\n private readonly manualFrames: boolean;\n private readonly mountError: Error | null;\n private readonly screenshot: Blob | null;\n private events: EngineHostEvents | null = null;\n /** Auto-advancing activity clock for emitFrame()/stepFrame() (ms). */\n private frameClock = 0;\n private destroyedFlag = false;\n private viewport: ViewportState = { x: 0, y: 0, zoom: 1 };\n private applied: number | null = null;\n private positions: Float32Array | null = null;\n /** Links of the most recent structure-bearing commit (commit-time, even in\n * manualFrames mode) — the adjacency source for neighborIndices(). */\n private lastLinks: Uint32Array | null = null;\n private pinned: readonly number[] | null = null;\n private selected: readonly number[] | null = null;\n /** Commits awaiting stepFrame() in manualFrames mode (oldest first). */\n private readonly pendingFrames: EngineCommit[] = [];\n\n constructor(options: FakeEngineOptions = {}) {\n this.capabilities = { ...DEFAULT_CAPABILITIES, ...options.capabilities };\n this.manualFrames = options.manualFrames ?? false;\n this.mountError = options.mountError ?? null;\n this.screenshot = options.screenshot ?? null;\n }\n\n /** Most recent commit, if any. */\n get lastCommit(): EngineCommit | undefined {\n return this.commits[this.commits.length - 1];\n }\n\n get destroyed(): boolean {\n return this.destroyedFlag;\n }\n\n /** Last setPinnedIndices() value (null = unpinned / never pinned). */\n get pinnedIndices(): readonly number[] | null {\n return this.pinned;\n }\n\n /** Last setSelectedIndices() value (null = cleared / never selected) — the\n * §9.1 highlight mirror of {@link pinnedIndices}. */\n get selectedIndices(): readonly number[] | null {\n return this.selected;\n }\n\n /**\n * Structure of the most recent structure-bearing commit — the geometry the\n * engine currently holds. Buffer channels commit independently of structure\n * (§9.1 mask fast path), so the newest commit often carries none.\n */\n get lastStructure(): NonNullable<EngineCommit['structure']> | undefined {\n for (let i = this.commits.length - 1; i >= 0; i--) {\n const structure = this.commits[i]!.structure;\n if (structure !== undefined) return structure;\n }\n return undefined;\n }\n\n /**\n * Most recently committed value of ONE buffer channel — the engine's current\n * content for it. Channels are committed independently (a mask drain may\n * carry `pointColor` alone), so scanning back per channel is the only way to\n * read composed state; the newest commit alone is not the whole picture.\n */\n lastBuffer(channel: keyof NonNullable<EngineCommit['buffers']>): Float32Array | undefined {\n // Newest FULL upload seeds the channel; any LATER ranged patches replay\n // over a copy in commit order (S13-T04) — the return is what the engine\n // currently holds either way.\n let baseIndex = -1;\n let base: Float32Array | undefined;\n for (let i = this.commits.length - 1; i >= 0; i--) {\n const value = this.commits[i]!.buffers?.[channel];\n if (value !== undefined) {\n baseIndex = i;\n base = value;\n break;\n }\n }\n if (base === undefined) return undefined;\n let out = base;\n let copied = false;\n for (let i = baseIndex + 1; i < this.commits.length; i++) {\n const patches = this.commits[i]!.bufferPatches?.[channel];\n if (patches === undefined) continue;\n if (!copied) {\n out = out.slice();\n copied = true;\n }\n for (const patch of patches) out.set(patch.data, patch.start);\n }\n return out;\n }\n\n // --- GraphEngine contract ---\n\n /** Headless: never touches `container` — a dummy cast works under node. */\n mount(container: HTMLElement, events: EngineHostEvents): Promise<void> {\n this.record('mount', [container, events]);\n if (this.mountError !== null) return Promise.reject(this.mountError);\n this.events = events;\n return Promise.resolve();\n }\n\n commit(update: EngineCommit): void {\n if (this.destroyedFlag) {\n throw new Error('FakeEngine: commit() called after destroy()');\n }\n // S13-T04 tripwires: ranged patches are legal only on DECLARED channels,\n // never alongside a full buffer for the same channel in one commit, and\n // only after a full upload seeded the channel. Each is a producer bug —\n // fail the test loudly instead of rendering stale state silently.\n if (update.bufferPatches !== undefined) {\n for (const [channel, patches] of Object.entries(update.bufferPatches)) {\n if (patches === undefined) continue;\n const ch = channel as keyof NonNullable<EngineCommit['buffers']>;\n if (!this.capabilities.rangeUpdates.includes(ch)) {\n throw new Error(`FakeEngine: bufferPatches.${channel} without the declared capability`);\n }\n if (update.buffers?.[ch] !== undefined) {\n throw new Error(\n `FakeEngine: commit carries BOTH buffers.${channel} and bufferPatches.${channel}`,\n );\n }\n const seeded = this.commits.some((c) => c.buffers?.[ch] !== undefined);\n if (!seeded) {\n throw new Error(\n `FakeEngine: bufferPatches.${channel} before any full upload seeded the channel`,\n );\n }\n }\n }\n this.record('commit', [update]);\n this.commits.push(update);\n if (update.structure !== undefined) this.lastLinks = update.structure.links;\n if (this.manualFrames) {\n this.pendingFrames.push(update);\n } else {\n this.apply(update);\n }\n }\n\n appliedRevision(): number | null {\n this.record('appliedRevision', []);\n return this.applied;\n }\n\n fitView(opts?: FitViewOptions): void {\n this.record('fitView', [opts]);\n }\n\n zoom(factor: number, durationMs?: number): void {\n this.record('zoom', [factor, durationMs]);\n }\n\n setViewport(v: Partial<ViewportState>, opts?: { durationMs?: number }): void {\n this.record('setViewport', [v, opts]);\n this.viewport = { ...this.viewport, ...v };\n }\n\n getViewport(): ViewportState | null {\n this.record('getViewport', []);\n return { ...this.viewport };\n }\n\n zoomToIndex(index: number, durationMs?: number): void {\n this.record('zoomToIndex', [index, durationMs]);\n }\n\n start(alpha?: number): void {\n this.record('start', [alpha]);\n }\n\n pause(): void {\n this.record('pause', []);\n }\n\n setSelectedIndices(indices: readonly number[] | null): void {\n this.record('setSelectedIndices', [indices]);\n this.selected = indices === null ? null : [...indices];\n }\n\n setFocusedIndex(index: number | null): void {\n this.record('setFocusedIndex', [index]);\n }\n\n /** Screen == space in the FakeEngine: ray-cast over current positions,\n * skipping NaN pairs (not-yet-applied structure in manualFrames mode). */\n pointsInPolygon(screenPolygon: readonly [number, number][]): number[] {\n this.record('pointsInPolygon', [screenPolygon]);\n const pos = this.positions;\n const out: number[] = [];\n if (pos === null || screenPolygon.length < 3) return out;\n for (let i = 0; i < pos.length / 2; i++) {\n const x = pos[2 * i]!;\n const y = pos[2 * i + 1]!;\n if (Number.isNaN(x) || Number.isNaN(y)) continue;\n if (pointInPolygon(x, y, screenPolygon)) out.push(i);\n }\n return out;\n }\n\n /** Screen == space: point indices inside `[x0, y0, x1, y1]` (bounds\n * normalized), skipping NaN pairs (not-yet-applied structure). */\n pointsInRect(screenRect: readonly [number, number, number, number]): number[] {\n this.record('pointsInRect', [screenRect]);\n const pos = this.positions;\n const out: number[] = [];\n if (pos === null) return out;\n const minX = Math.min(screenRect[0], screenRect[2]);\n const maxX = Math.max(screenRect[0], screenRect[2]);\n const minY = Math.min(screenRect[1], screenRect[3]);\n const maxY = Math.max(screenRect[1], screenRect[3]);\n for (let i = 0; i < pos.length / 2; i++) {\n const x = pos[2 * i]!;\n const y = pos[2 * i + 1]!;\n if (Number.isNaN(x) || Number.isNaN(y)) continue;\n if (x >= minX && x <= maxX && y >= minY && y <= maxY) out.push(i);\n }\n return out;\n }\n\n /** Resolves the constructor's `screenshot` option (null by default). */\n captureScreenshot(): Promise<Blob | null> {\n this.record('captureScreenshot', []);\n return Promise.resolve(this.screenshot);\n }\n\n /** 1-hop adjacency from the last committed links (self-loops excluded). */\n neighborIndices(index: number): number[] {\n this.record('neighborIndices', [index]);\n const links = this.lastLinks;\n if (links === null) return [];\n const out = new Set<number>();\n for (let k = 0; k < links.length; k += 2) {\n const s = links[k]!;\n const t = links[k + 1]!;\n if (s === index && t !== index) out.add(t);\n if (t === index && s !== index) out.add(s);\n }\n return [...out];\n }\n\n /** Identity transform: FakeEngine screen coordinates ARE space coordinates. */\n screenToSpace(p: readonly [number, number]): [number, number] | null {\n this.record('screenToSpace', [p]);\n return [p[0], p[1]];\n }\n\n /** Identity transform: FakeEngine screen coordinates ARE space coordinates. */\n spaceToScreen(p: readonly [number, number]): [number, number] | null {\n this.record('spaceToScreen', [p]);\n return [p[0], p[1]];\n }\n\n setPinnedIndices(indices: readonly number[] | null): void {\n this.record('setPinnedIndices', [indices]);\n this.pinned = indices === null ? null : [...indices];\n }\n\n getPositions(): Float32Array | null {\n this.record('getPositions', []);\n return this.positions === null ? null : new Float32Array(this.positions);\n }\n\n destroy(): void {\n this.record('destroy', []);\n this.destroyedFlag = true;\n this.events = null;\n }\n\n // --- test helpers (not part of GraphEngine) ---\n\n /**\n * manualFrames mode: apply the oldest queued commit, making its revision\n * visible via appliedRevision(). No-op on the queue when empty. A drawn\n * frame is also an activity-clock sample, so a mounted engine gets an\n * `onFrame` tick (§13 overlay/activity clock).\n */\n stepFrame(): void {\n this.record('stepFrame', []);\n const next = this.pendingFrames.shift();\n if (next !== undefined) this.apply(next);\n if (this.events !== null) {\n this.frameClock += 16;\n this.events.onFrame?.(this.frameClock);\n }\n }\n\n /**\n * Drive the host `onFrame` activity clock. `timeMs` sets the clock\n * explicitly; omitted, the clock auto-advances by 16ms per call.\n */\n emitFrame(timeMs?: number): void {\n const events = this.requireMounted('emitFrame');\n this.frameClock = timeMs ?? this.frameClock + 16;\n this.record('emitFrame', [this.frameClock]);\n events.onFrame?.(this.frameClock);\n }\n\n /** Simulate simulation drift: shift every current position by (dx, dy). */\n nudgePositions(dx: number, dy: number): void {\n this.record('nudgePositions', [dx, dy]);\n const pos = this.positions;\n if (pos === null) return;\n for (let i = 0; i < pos.length; i += 2) {\n pos[i] = pos[i]! + dx;\n pos[i + 1] = pos[i + 1]! + dy;\n }\n }\n\n injectPointClick(index: number | null, modifiers?: { metaKey: boolean; shiftKey: boolean }): void {\n const events = this.requireMounted('injectPointClick');\n this.record('injectPointClick', [index, modifiers]);\n events.onPointClick?.(index, modifiers);\n }\n\n injectPointHover(index: number | null): void {\n const events = this.requireMounted('injectPointHover');\n this.record('injectPointHover', [index]);\n events.onPointHover?.(index);\n }\n\n injectLinkClick(linkIndex: number): void {\n const events = this.requireMounted('injectLinkClick');\n this.record('injectLinkClick', [linkIndex]);\n events.onLinkClick?.(linkIndex);\n }\n\n injectLinkHover(linkIndex: number | null): void {\n const events = this.requireMounted('injectLinkHover');\n this.record('injectLinkHover', [linkIndex]);\n events.onLinkHover?.(linkIndex);\n }\n\n injectDragStart(index: number): void {\n const events = this.requireMounted('injectDragStart');\n this.record('injectDragStart', [index]);\n events.onDragStart?.(index);\n }\n\n injectDragEnd(index: number, x: number, y: number): void {\n const events = this.requireMounted('injectDragEnd');\n this.record('injectDragEnd', [index, x, y]);\n events.onDragEnd?.(index, x, y);\n }\n\n injectContextMenu(index: number | null, screen: readonly [number, number]): void {\n const events = this.requireMounted('injectContextMenu');\n this.record('injectContextMenu', [index, screen]);\n events.onContextMenu?.(index, screen);\n }\n\n injectViewportChange(v: ViewportState): void {\n const events = this.requireMounted('injectViewportChange');\n this.record('injectViewportChange', [v]);\n this.viewport = { ...v };\n events.onViewportChange?.(v);\n }\n\n injectSimulationEnd(): void {\n const events = this.requireMounted('injectSimulationEnd');\n this.record('injectSimulationEnd', []);\n events.onSimulationEnd?.();\n }\n\n injectError(error: Error): void {\n const events = this.requireMounted('injectError');\n this.record('injectError', [error]);\n events.onError?.(error);\n }\n\n injectContextLost(): void {\n const events = this.requireMounted('injectContextLost');\n this.record('injectContextLost', []);\n events.onContextEvent?.({ type: 'lost' });\n }\n\n injectContextRestored(): void {\n const events = this.requireMounted('injectContextRestored');\n this.record('injectContextRestored', []);\n events.onContextEvent?.({ type: 'restored' });\n }\n\n injectContextFailed(error: Error): void {\n const events = this.requireMounted('injectContextFailed');\n this.record('injectContextFailed', [error]);\n events.onContextEvent?.({ type: 'failed', error });\n }\n\n injectEngineDiagnostic(d: EngineDiagnostic): void {\n const events = this.requireMounted('injectEngineDiagnostic');\n this.record('injectEngineDiagnostic', [d]);\n events.onDiagnostic?.(d);\n }\n\n // --- internals ---\n\n private record(method: string, args: unknown[]): void {\n // Trim trailing omitted optionals so `args` matches the caller's shape.\n while (args.length > 0 && args[args.length - 1] === undefined) args.pop();\n const call: RecordedCall = { method, args };\n this.calls.push(call);\n if (CAMERA_METHODS.has(method)) this.cameraCalls.push(call);\n }\n\n private requireMounted(helper: string): EngineHostEvents {\n const events = this.events;\n if (events === null) {\n throw new Error(`FakeEngine: ${helper}() requires a mounted engine — call mount() first`);\n }\n return events;\n }\n\n /**\n * Make a commit visible: rebuild positions when structure is present (NaN\n * pairs seeded deterministically, known coordinates kept verbatim) and\n * advance the applied revision.\n */\n private apply(update: EngineCommit): void {\n const structure = update.structure;\n if (structure !== undefined) {\n const { pointCount, positions } = structure;\n const next = new Float32Array(2 * pointCount);\n for (let i = 0; i < pointCount; i++) {\n const x = positions[2 * i]!;\n const y = positions[2 * i + 1]!;\n if (Number.isNaN(x) || Number.isNaN(y)) {\n const [sx, sy] = seedPosition(i);\n next[2 * i] = sx;\n next[2 * i + 1] = sy;\n } else {\n next[2 * i] = x;\n next[2 * i + 1] = y;\n }\n }\n this.positions = next;\n }\n this.applied = update.revision;\n }\n}\n","/**\n * §17/S13-T06 requestAnimationFrame audit — the quiescence instrument.\n *\n * Wraps a window's `requestAnimationFrame` and counts SCHEDULING calls\n * (registrations) separately from delivered ticks: the stop-at-rest claim is\n * about registrations — a truly stopped loop schedules nothing at all, while\n * tick counts alone can read zero under fake timers even though a loop is\n * still re-arming itself.\n *\n * Used three ways: core/react quiescence tests (install, drive the instance,\n * assert `registrations() === 0` over a settled window), the demo e2e's\n * page-side counterpart (same shape, injected via addInitScript), and the\n * dev-mode runtime assertion in the instance. The M0 spike's instrument.ts\n * pioneered the wrapper; this is its reusable, uninstallable form.\n */\n\nexport interface RafAudit {\n /** requestAnimationFrame CALLS observed since install (scheduling). */\n registrations(): number;\n /** Callbacks actually delivered since install (ticks). */\n ticks(): number;\n /** Zero both counters without uninstalling. */\n reset(): void;\n /** Restore the original requestAnimationFrame. Idempotent. */\n uninstall(): void;\n}\n\n/**\n * Install the audit on `win` (default: globalThis). Under jsdom + vitest\n * fake timers, rAF is timer-backed, so `vi.advanceTimersByTime` drives\n * deliveries — registrations count regardless. In a rAF-less environment\n * (plain-Node core tests) a 16ms setTimeout shim delivers: without the\n * audit, any rAF call there would simply crash — with it, the call is\n * COUNTED, which is exactly the evidence a quiescence test wants.\n */\nexport function installRafAudit(win: Window = globalThis as unknown as Window): RafAudit {\n const target = win as Window & {\n requestAnimationFrame?: typeof requestAnimationFrame;\n };\n const original = target.requestAnimationFrame;\n const native: typeof requestAnimationFrame =\n original !== undefined\n ? original.bind(target)\n : (cb) => setTimeout(() => cb(performance.now()), 16) as unknown as number;\n let registrations = 0;\n let ticks = 0;\n let installed = true;\n\n const wrapper = (callback: FrameRequestCallback): number => {\n registrations += 1;\n return native((time) => {\n ticks += 1;\n callback(time);\n });\n };\n target.requestAnimationFrame = wrapper;\n\n return {\n registrations: () => registrations,\n ticks: () => ticks,\n reset: () => {\n registrations = 0;\n ticks = 0;\n },\n uninstall: () => {\n if (!installed) return;\n installed = false;\n // Only restore if nobody else re-wrapped after us — otherwise leave\n // the newer wrapper in place and simply stop counting (native is\n // already bound into it).\n if (target.requestAnimationFrame === wrapper) {\n if (original !== undefined) target.requestAnimationFrame = original;\n else Reflect.deleteProperty(target, 'requestAnimationFrame');\n }\n },\n };\n}\n","/**\n * In-process worker transport double (ADR-006 D2/D5) — drives the REAL\n * runtime module through the REAL codec, asynchronously (microtask), with\n * REAL transfer semantics: payloads round through `structuredClone` with\n * the declared transfer list, so a wrong transfer set detaches something\n * the sender still needs and fails the suite loudly — exactly what a live\n * thread would do, minus the scheduling.\n */\n\nimport { EnvelopeSequencer } from '../workerProtocol';\nimport type { WorkerEnvelope } from '../workerProtocol';\nimport { handleWorkerRequest } from '../worker/runtime';\nimport type { WorkerTransport } from '../worker/lane';\n\nexport interface WorkerDouble extends WorkerTransport {\n /** Requests handled so far (post-clone shapes, in arrival order). */\n readonly handled: WorkerEnvelope[];\n}\n\nexport function createWorkerDouble(): WorkerDouble {\n const sequencer = new EnvelopeSequencer();\n const handled: WorkerEnvelope[] = [];\n let deliver: ((reply: WorkerEnvelope) => void) | null = null;\n return {\n handled,\n post(envelope, transfers) {\n // REAL transfer semantics: the sender's views detach here.\n const received = structuredClone(envelope, {\n transfer: [...transfers],\n }) as WorkerEnvelope;\n queueMicrotask(() => {\n handled.push(received);\n const { reply, transfers: replyTransfers } = handleWorkerRequest(received, sequencer);\n const delivered = structuredClone(reply, {\n transfer: [...replyTransfers],\n }) as WorkerEnvelope;\n deliver?.(delivered);\n });\n },\n onReply(cb) {\n deliver = cb;\n },\n terminate() {\n deliver = null;\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/testing/FakeEngine.ts","../src/testing/rafAudit.ts","../src/worker/runtime.ts","../src/testing/workerDouble.ts"],"names":["reply"],"mappings":"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","file":"testing.js","sourcesContent":["/**\n * FakeEngine — the public headless test seam.\n *\n * Implements the full GraphEngine adapter contract with zero DOM/WebGL access\n * so consumer suites can run under node/jsdom. Every public method call is\n * recorded to `calls` in order; commits and camera calls get typed convenience\n * views. Test-only helpers (`stepFrame`, `nudgePositions`, `inject*`) let\n * suites observe applied-revision lag, simulate position drift, and drive\n * host events.\n *\n * The state MIRRORS (`pinnedIndices`, `selectedIndices`, `lastStructure`,\n * `lastBuffer`) answer \"what does the engine currently hold?\", which the raw\n * `calls`/`commits` logs cannot: pins, highlight, structure and each buffer\n * channel are committed on independent schedules, so the newest entry is\n * rarely the newest value for a given channel.\n */\n\nimport type {\n EngineCapabilities,\n EngineCommit,\n EngineDiagnostic,\n EngineHostEvents,\n FitViewOptions,\n GraphEngine,\n} from '../engine/index';\nimport type { ViewportState } from '../types';\n\nexport interface FakeEngineOptions {\n /** Overrides merged over the defaults (linkPicking/trackedPositions false, rangeUpdates [], simulation true). */\n capabilities?: Partial<EngineCapabilities>;\n /**\n * When true, commits queue instead of applying immediately; `stepFrame`\n * applies the oldest queued commit. Lets tests observe the lag between the\n * desired-render revision and `appliedRevision`.\n */\n manualFrames?: boolean;\n /**\n * When set, `mount` records the call, does NOT store the host events, and\n * rejects with this error — simulates an engine that cannot initialize.\n */\n mountError?: Error;\n /** Resolved by `captureScreenshot`; default null (unsupported/not ready). */\n screenshot?: Blob | null;\n}\n\n/** One recorded public method invocation. */\nexport interface RecordedCall {\n method: string;\n args: readonly unknown[];\n}\n\nconst DEFAULT_CAPABILITIES: EngineCapabilities = {\n linkPicking: false,\n rangeUpdates: [],\n trackedPositions: false,\n simulation: true,\n // the FakeEngine schedules nothing on its own — frames exist only\n // when a test calls stepFrame/emitFrame — so it is quiescent by\n // construction, and those calls apply-then-emit, which is genuinely\n // post-draw.\n idleFrames: 'stops',\n postDrawFrames: true,\n};\n\nconst CAMERA_METHODS: ReadonlySet<string> = new Set([\n 'fitView',\n 'zoom',\n 'setViewport',\n 'zoomToIndex',\n]);\n\n/** Deterministic seed for an unknown (NaN) position: a 10px grid, 100 per row. */\nfunction seedPosition(index: number): readonly [number, number] {\n return [(index % 100) * 10, Math.floor(index / 100) * 10];\n}\n\n/** Standard even-odd ray cast (screen == space in the FakeEngine). */\nfunction pointInPolygon(x: number, y: number, polygon: readonly [number, number][]): boolean {\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const [xi, yi] = polygon[i]!;\n const [xj, yj] = polygon[j]!;\n const crosses = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;\n if (crosses) inside = !inside;\n }\n return inside;\n}\n\nexport class FakeEngine implements GraphEngine {\n readonly capabilities: EngineCapabilities;\n\n /** Every public method call, in order. */\n readonly calls: RecordedCall[] = [];\n /** Every commit passed to `commit`, in call order (queued or applied). */\n readonly commits: EngineCommit[] = [];\n /** The fitView/zoom/setViewport/zoomToIndex entries of `calls`, in order. */\n readonly cameraCalls: RecordedCall[] = [];\n\n private readonly manualFrames: boolean;\n private readonly mountError: Error | null;\n private readonly screenshot: Blob | null;\n private events: EngineHostEvents | null = null;\n /** Auto-advancing activity clock for emitFrame/stepFrame (ms). */\n private frameClock = 0;\n private destroyedFlag = false;\n private viewport: ViewportState = { x: 0, y: 0, zoom: 1 };\n private applied: number | null = null;\n private positions: Float32Array | null = null;\n /** Links of the most recent structure-bearing commit (commit-time, even in\n * manualFrames mode) — the adjacency source for neighborIndices. */\n private lastLinks: Uint32Array | null = null;\n private pinned: readonly number[] | null = null;\n private selected: readonly number[] | null = null;\n /** Commits awaiting stepFrame in manualFrames mode (oldest first). */\n private readonly pendingFrames: EngineCommit[] = [];\n\n constructor(options: FakeEngineOptions = {}) {\n this.capabilities = { ...DEFAULT_CAPABILITIES, ...options.capabilities };\n this.manualFrames = options.manualFrames ?? false;\n this.mountError = options.mountError ?? null;\n this.screenshot = options.screenshot ?? null;\n }\n\n /** Most recent commit, if any. */\n get lastCommit(): EngineCommit | undefined {\n return this.commits[this.commits.length - 1];\n }\n\n get destroyed(): boolean {\n return this.destroyedFlag;\n }\n\n /** Last setPinnedIndices value (null = unpinned / never pinned). */\n get pinnedIndices(): readonly number[] | null {\n return this.pinned;\n }\n\n /** Last setSelectedIndices value (null = cleared / never selected) — the\n * highlight mirror of {@link pinnedIndices}. */\n get selectedIndices(): readonly number[] | null {\n return this.selected;\n }\n\n /**\n * Structure of the most recent structure-bearing commit — the geometry the\n * engine currently holds. Buffer channels commit independently of structure,\n * so the newest commit often carries none.\n */\n get lastStructure(): NonNullable<EngineCommit['structure']> | undefined {\n for (let i = this.commits.length - 1; i >= 0; i--) {\n const structure = this.commits[i]!.structure;\n if (structure !== undefined) return structure;\n }\n return undefined;\n }\n\n /**\n * Most recently committed value of ONE buffer channel — the engine's current\n * content for it. Channels are committed independently (a mask drain may\n * carry `pointColor` alone), so scanning back per channel is the only way to\n * read composed state; the newest commit alone is not the whole picture.\n */\n lastBuffer(channel: keyof NonNullable<EngineCommit['buffers']>): Float32Array | undefined {\n // Newest FULL upload seeds the channel; any LATER ranged patches replay\n // over a copy in commit order — the return is what the engine\n // currently holds either way.\n let baseIndex = -1;\n let base: Float32Array | undefined;\n for (let i = this.commits.length - 1; i >= 0; i--) {\n const value = this.commits[i]!.buffers?.[channel];\n if (value !== undefined) {\n baseIndex = i;\n base = value;\n break;\n }\n }\n if (base === undefined) return undefined;\n let out = base;\n let copied = false;\n for (let i = baseIndex + 1; i < this.commits.length; i++) {\n const patches = this.commits[i]!.bufferPatches?.[channel];\n if (patches === undefined) continue;\n if (!copied) {\n out = out.slice();\n copied = true;\n }\n for (const patch of patches) out.set(patch.data, patch.start);\n }\n return out;\n }\n\n // --- GraphEngine contract ---\n\n /** Headless: never touches `container` — a dummy cast works under node. */\n mount(container: HTMLElement, events: EngineHostEvents): Promise<void> {\n this.record('mount', [container, events]);\n if (this.mountError !== null) return Promise.reject(this.mountError);\n this.events = events;\n return Promise.resolve();\n }\n\n commit(update: EngineCommit): void {\n if (this.destroyedFlag) {\n throw new Error('FakeEngine: commit() called after destroy()');\n }\n // tripwires: ranged patches are legal only on DECLARED channels,\n // never alongside a full buffer for the same channel in one commit, and\n // only after a full upload seeded the channel. Each is a producer bug\n // fail the test loudly instead of rendering stale state silently.\n if (update.bufferPatches !== undefined) {\n for (const [channel, patches] of Object.entries(update.bufferPatches)) {\n if (patches === undefined) continue;\n const ch = channel as keyof NonNullable<EngineCommit['buffers']>;\n if (!this.capabilities.rangeUpdates.includes(ch)) {\n throw new Error(`FakeEngine: bufferPatches.${channel} without the declared capability`);\n }\n if (update.buffers?.[ch] !== undefined) {\n throw new Error(\n `FakeEngine: commit carries BOTH buffers.${channel} and bufferPatches.${channel}`,\n );\n }\n const seeded = this.commits.some((c) => c.buffers?.[ch] !== undefined);\n if (!seeded) {\n throw new Error(\n `FakeEngine: bufferPatches.${channel} before any full upload seeded the channel`,\n );\n }\n }\n }\n this.record('commit', [update]);\n this.commits.push(update);\n if (update.structure !== undefined) this.lastLinks = update.structure.links;\n if (this.manualFrames) {\n this.pendingFrames.push(update);\n } else {\n this.apply(update);\n }\n }\n\n appliedRevision(): number | null {\n this.record('appliedRevision', []);\n return this.applied;\n }\n\n fitView(opts?: FitViewOptions): void {\n this.record('fitView', [opts]);\n }\n\n zoom(factor: number, durationMs?: number): void {\n this.record('zoom', [factor, durationMs]);\n }\n\n setViewport(v: Partial<ViewportState>, opts?: { durationMs?: number }): void {\n this.record('setViewport', [v, opts]);\n this.viewport = { ...this.viewport, ...v };\n }\n\n getViewport(): ViewportState | null {\n this.record('getViewport', []);\n return { ...this.viewport };\n }\n\n zoomToIndex(index: number, durationMs?: number): void {\n this.record('zoomToIndex', [index, durationMs]);\n }\n\n start(alpha?: number): void {\n this.record('start', [alpha]);\n }\n\n pause(): void {\n this.record('pause', []);\n }\n\n setSelectedIndices(indices: readonly number[] | null): void {\n this.record('setSelectedIndices', [indices]);\n this.selected = indices === null ? null : [...indices];\n }\n\n setFocusedIndex(index: number | null): void {\n this.record('setFocusedIndex', [index]);\n }\n\n /** Screen == space in the FakeEngine: ray-cast over current positions,\n * skipping NaN pairs (not-yet-applied structure in manualFrames mode). */\n pointsInPolygon(screenPolygon: readonly [number, number][]): number[] {\n this.record('pointsInPolygon', [screenPolygon]);\n const pos = this.positions;\n const out: number[] = [];\n if (pos === null || screenPolygon.length < 3) return out;\n for (let i = 0; i < pos.length / 2; i++) {\n const x = pos[2 * i]!;\n const y = pos[2 * i + 1]!;\n if (Number.isNaN(x) || Number.isNaN(y)) continue;\n if (pointInPolygon(x, y, screenPolygon)) out.push(i);\n }\n return out;\n }\n\n /** Screen == space: point indices inside `[x0, y0, x1, y1]` (bounds\n * normalized), skipping NaN pairs (not-yet-applied structure). */\n pointsInRect(screenRect: readonly [number, number, number, number]): number[] {\n this.record('pointsInRect', [screenRect]);\n const pos = this.positions;\n const out: number[] = [];\n if (pos === null) return out;\n const minX = Math.min(screenRect[0], screenRect[2]);\n const maxX = Math.max(screenRect[0], screenRect[2]);\n const minY = Math.min(screenRect[1], screenRect[3]);\n const maxY = Math.max(screenRect[1], screenRect[3]);\n for (let i = 0; i < pos.length / 2; i++) {\n const x = pos[2 * i]!;\n const y = pos[2 * i + 1]!;\n if (Number.isNaN(x) || Number.isNaN(y)) continue;\n if (x >= minX && x <= maxX && y >= minY && y <= maxY) out.push(i);\n }\n return out;\n }\n\n /** Resolves the constructor's `screenshot` option (null by default). */\n captureScreenshot(): Promise<Blob | null> {\n this.record('captureScreenshot', []);\n return Promise.resolve(this.screenshot);\n }\n\n /** 1-hop adjacency from the last committed links (self-loops excluded). */\n neighborIndices(index: number): number[] {\n this.record('neighborIndices', [index]);\n const links = this.lastLinks;\n if (links === null) return [];\n const out = new Set<number>();\n for (let k = 0; k < links.length; k += 2) {\n const s = links[k]!;\n const t = links[k + 1]!;\n if (s === index && t !== index) out.add(t);\n if (t === index && s !== index) out.add(s);\n }\n return [...out];\n }\n\n /** Identity transform: FakeEngine screen coordinates ARE space coordinates. */\n screenToSpace(p: readonly [number, number]): [number, number] | null {\n this.record('screenToSpace', [p]);\n return [p[0], p[1]];\n }\n\n /** Identity transform: FakeEngine screen coordinates ARE space coordinates. */\n spaceToScreen(p: readonly [number, number]): [number, number] | null {\n this.record('spaceToScreen', [p]);\n return [p[0], p[1]];\n }\n\n setPinnedIndices(indices: readonly number[] | null): void {\n this.record('setPinnedIndices', [indices]);\n this.pinned = indices === null ? null : [...indices];\n }\n\n getPositions(): Float32Array | null {\n this.record('getPositions', []);\n return this.positions === null ? null : new Float32Array(this.positions);\n }\n\n destroy(): void {\n this.record('destroy', []);\n this.destroyedFlag = true;\n this.events = null;\n }\n\n // --- test helpers (not part of GraphEngine) ---\n\n /**\n * manualFrames mode: apply the oldest queued commit, making its revision\n * visible via appliedRevision. No-op on the queue when empty. A drawn\n * frame is also an activity-clock sample, so a mounted engine gets an\n * `onFrame` tick.\n */\n stepFrame(): void {\n this.record('stepFrame', []);\n const next = this.pendingFrames.shift();\n if (next !== undefined) this.apply(next);\n if (this.events !== null) {\n this.frameClock += 16;\n this.events.onFrame?.(this.frameClock);\n }\n }\n\n /**\n * Drive the host `onFrame` activity clock. `timeMs` sets the clock\n * explicitly; omitted, the clock auto-advances by 16ms per call.\n */\n emitFrame(timeMs?: number): void {\n const events = this.requireMounted('emitFrame');\n this.frameClock = timeMs ?? this.frameClock + 16;\n this.record('emitFrame', [this.frameClock]);\n events.onFrame?.(this.frameClock);\n }\n\n /** Simulate simulation drift: shift every current position by (dx, dy). */\n nudgePositions(dx: number, dy: number): void {\n this.record('nudgePositions', [dx, dy]);\n const pos = this.positions;\n if (pos === null) return;\n for (let i = 0; i < pos.length; i += 2) {\n pos[i] = pos[i]! + dx;\n pos[i + 1] = pos[i + 1]! + dy;\n }\n }\n\n injectPointClick(index: number | null, modifiers?: { metaKey: boolean; shiftKey: boolean }): void {\n const events = this.requireMounted('injectPointClick');\n this.record('injectPointClick', [index, modifiers]);\n events.onPointClick?.(index, modifiers);\n }\n\n injectPointHover(index: number | null): void {\n const events = this.requireMounted('injectPointHover');\n this.record('injectPointHover', [index]);\n events.onPointHover?.(index);\n }\n\n injectLinkClick(linkIndex: number): void {\n const events = this.requireMounted('injectLinkClick');\n this.record('injectLinkClick', [linkIndex]);\n events.onLinkClick?.(linkIndex);\n }\n\n injectLinkHover(linkIndex: number | null): void {\n const events = this.requireMounted('injectLinkHover');\n this.record('injectLinkHover', [linkIndex]);\n events.onLinkHover?.(linkIndex);\n }\n\n injectDragStart(index: number): void {\n const events = this.requireMounted('injectDragStart');\n this.record('injectDragStart', [index]);\n events.onDragStart?.(index);\n }\n\n injectDragEnd(index: number, x: number, y: number): void {\n const events = this.requireMounted('injectDragEnd');\n this.record('injectDragEnd', [index, x, y]);\n events.onDragEnd?.(index, x, y);\n }\n\n injectContextMenu(index: number | null, screen: readonly [number, number]): void {\n const events = this.requireMounted('injectContextMenu');\n this.record('injectContextMenu', [index, screen]);\n events.onContextMenu?.(index, screen);\n }\n\n injectViewportChange(v: ViewportState): void {\n const events = this.requireMounted('injectViewportChange');\n this.record('injectViewportChange', [v]);\n this.viewport = { ...v };\n events.onViewportChange?.(v);\n }\n\n injectSimulationEnd(): void {\n const events = this.requireMounted('injectSimulationEnd');\n this.record('injectSimulationEnd', []);\n events.onSimulationEnd?.();\n }\n\n injectError(error: Error): void {\n const events = this.requireMounted('injectError');\n this.record('injectError', [error]);\n events.onError?.(error);\n }\n\n injectContextLost(): void {\n const events = this.requireMounted('injectContextLost');\n this.record('injectContextLost', []);\n events.onContextEvent?.({ type: 'lost' });\n }\n\n injectContextRestored(): void {\n const events = this.requireMounted('injectContextRestored');\n this.record('injectContextRestored', []);\n events.onContextEvent?.({ type: 'restored' });\n }\n\n injectContextFailed(error: Error): void {\n const events = this.requireMounted('injectContextFailed');\n this.record('injectContextFailed', [error]);\n events.onContextEvent?.({ type: 'failed', error });\n }\n\n injectEngineDiagnostic(d: EngineDiagnostic): void {\n const events = this.requireMounted('injectEngineDiagnostic');\n this.record('injectEngineDiagnostic', [d]);\n events.onDiagnostic?.(d);\n }\n\n // --- internals ---\n\n private record(method: string, args: unknown[]): void {\n // Trim trailing omitted optionals so `args` matches the caller's shape.\n while (args.length > 0 && args[args.length - 1] === undefined) args.pop();\n const call: RecordedCall = { method, args };\n this.calls.push(call);\n if (CAMERA_METHODS.has(method)) this.cameraCalls.push(call);\n }\n\n private requireMounted(helper: string): EngineHostEvents {\n const events = this.events;\n if (events === null) {\n throw new Error(`FakeEngine: ${helper}() requires a mounted engine — call mount() first`);\n }\n return events;\n }\n\n /**\n * Make a commit visible: rebuild positions when structure is present (NaN\n * pairs seeded deterministically, known coordinates kept verbatim) and\n * advance the applied revision.\n */\n private apply(update: EngineCommit): void {\n const structure = update.structure;\n if (structure !== undefined) {\n const { pointCount, positions } = structure;\n const next = new Float32Array(2 * pointCount);\n for (let i = 0; i < pointCount; i++) {\n const x = positions[2 * i]!;\n const y = positions[2 * i + 1]!;\n if (Number.isNaN(x) || Number.isNaN(y)) {\n const [sx, sy] = seedPosition(i);\n next[2 * i] = sx;\n next[2 * i + 1] = sy;\n } else {\n next[2 * i] = x;\n next[2 * i + 1] = y;\n }\n }\n this.positions = next;\n }\n this.applied = update.revision;\n }\n}\n","/**\n * requestAnimationFrame audit — the quiescence instrument.\n *\n * Wraps a window's `requestAnimationFrame` and counts SCHEDULING calls\n * (registrations) separately from delivered ticks: the stop-at-rest claim is\n * about registrations — a truly stopped loop schedules nothing at all, while\n * tick counts alone can read zero under fake timers even though a loop is\n * still re-arming itself.\n *\n * Used three ways: core/react quiescence tests (install, drive the instance,\n * assert `registrations === 0` over a settled window), the demo e2e's\n * page-side counterpart (same shape, injected via addInitScript), and the\n * dev-mode runtime assertion in the instance. The M0 spike's instrument.ts\n * pioneered the wrapper; this is its reusable, uninstallable form.\n */\n\nexport interface RafAudit {\n /** requestAnimationFrame CALLS observed since install (scheduling). */\n registrations(): number;\n /** Callbacks actually delivered since install (ticks). */\n ticks(): number;\n /** Zero both counters without uninstalling. */\n reset(): void;\n /** Restore the original requestAnimationFrame. Idempotent. */\n uninstall(): void;\n}\n\n/**\n * Install the audit on `win` (default: globalThis). Under jsdom + vitest\n * fake timers, rAF is timer-backed, so `vi.advanceTimersByTime` drives\n * deliveries — registrations count regardless. In a rAF-less environment\n * (plain-Node core tests) a 16ms setTimeout shim delivers: without the\n * audit, any rAF call there would simply crash — with it, the call is\n * COUNTED, which is exactly the evidence a quiescence test wants.\n */\nexport function installRafAudit(win: Window = globalThis as unknown as Window): RafAudit {\n const target = win as Window & {\n requestAnimationFrame?: typeof requestAnimationFrame;\n };\n const original = target.requestAnimationFrame;\n const native: typeof requestAnimationFrame =\n original !== undefined\n ? original.bind(target)\n : (cb) => setTimeout(() => cb(performance.now()), 16) as unknown as number;\n let registrations = 0;\n let ticks = 0;\n let installed = true;\n\n const wrapper = (callback: FrameRequestCallback): number => {\n registrations += 1;\n return native((time) => {\n ticks += 1;\n callback(time);\n });\n };\n target.requestAnimationFrame = wrapper;\n\n return {\n registrations: () => registrations,\n ticks: () => ticks,\n reset: () => {\n registrations = 0;\n ticks = 0;\n },\n uninstall: () => {\n if (!installed) return;\n installed = false;\n // Only restore if nobody else re-wrapped after us — otherwise leave\n // the newer wrapper in place and simply stop counting (native is\n // already bound into it).\n if (target.requestAnimationFrame === wrapper) {\n if (original !== undefined) target.requestAnimationFrame = original;\n else Reflect.deleteProperty(target, 'requestAnimationFrame');\n }\n },\n };\n}\n","/**\n * Worker-side request handler, implemented as a PURE function over the\n * codec so the real thread entry (worker/entry.ts) and the in-process test\n * double drive IDENTICAL code (D2: one implementation, never duplicated).\n *\n * First cargo: `derive-columnar` — the acceptance rules over\n * transferred acceptance inputs. Dictionaries arrive as UTF-8 string tables\n * (transferables, decoded off-main); results leave as keep bitmaps, the\n * survivor remap, resolved links, and object-lane-identical diagnostics\n * every heavy field a transferable.\n *\n * No thread machinery here: input envelope in, reply envelope + transfer\n * list out. Unknown ops and malformed payloads reply with an 'error' op\n * (never throw — a worker that dies on one bad message kills every pending\n * request behind it).\n */\n\nimport { acceptColumnar } from '../columnarValidate';\nimport type { ColumnarGraphSnapshot, GraphDiagnostic } from '../types';\nimport {\n EnvelopeSequencer,\n collectTransfers,\n decodeStringTable,\n isWellFormedEnvelope,\n} from '../workerProtocol';\nimport type { EncodedStringTable, WorkerEnvelope } from '../workerProtocol';\n\n/** Wire payload for 'derive-columnar' — the acceptance inputs ONLY (attr\n * columns never cross; materialization stays main-side this slice). */\nexport interface DeriveColumnarRequest {\n nodeIdTable: EncodedStringTable;\n nodeIdCodes: Uint32Array;\n nodeCount: number;\n edgeIdTable: EncodedStringTable;\n edgeIdCodes: Uint32Array;\n edgeSource: Uint32Array;\n edgeTarget: Uint32Array;\n edgeCount: number;\n}\n\nexport interface DeriveColumnarResult {\n keepNodes: Uint8Array;\n keepEdges: Uint8Array;\n acceptedNodeCount: number;\n acceptedEdgeCount: number;\n nodeAcceptedIndex: Int32Array;\n links: Uint32Array;\n diagnostics: GraphDiagnostic[];\n}\n\nexport interface HandledReply {\n reply: WorkerEnvelope;\n transfers: ArrayBuffer[];\n}\n\n/** Handle ONE request envelope. The sequencer is the worker's own outbound\n * direction (per-direction monotonic ids). */\nexport function handleWorkerRequest(\n request: unknown,\n sequencer: EnvelopeSequencer,\n): HandledReply {\n if (!isWellFormedEnvelope(request)) {\n const reply = sequencer.make(0, 'scene', 'error', {\n message: 'malformed envelope (protocol violation)',\n });\n return { reply, transfers: [] };\n }\n\n if (request.op === 'derive-columnar') {\n try {\n const p = request.payload as DeriveColumnarRequest;\n // Rebuild the snapshot SHAPE acceptColumnar expects — same module the\n // main lane uses (D2), fed decoded-off-main dictionaries.\n const snapshot: ColumnarGraphSnapshot<unknown, unknown> = {\n kind: 'columnar',\n datasetKey: 'worker', // acceptance rules never read the coordinate\n sourceRevision: 0,\n nodes: {\n ids: {\n kind: 'string',\n dictionary: decodeStringTable(p.nodeIdTable),\n codes: p.nodeIdCodes,\n },\n columns: {},\n length: p.nodeCount,\n },\n edges: {\n ids: {\n kind: 'string',\n dictionary: decodeStringTable(p.edgeIdTable),\n codes: p.edgeIdCodes,\n },\n source: p.edgeSource,\n target: p.edgeTarget,\n columns: {},\n length: p.edgeCount,\n },\n };\n const acceptance = acceptColumnar(snapshot);\n const result: DeriveColumnarResult = {\n keepNodes: acceptance.keepNodes,\n keepEdges: acceptance.keepEdges,\n acceptedNodeCount: acceptance.acceptedNodeCount,\n acceptedEdgeCount: acceptance.acceptedEdgeCount,\n nodeAcceptedIndex: acceptance.nodeAcceptedIndex,\n links: acceptance.links,\n diagnostics: acceptance.diagnostics,\n };\n const reply = sequencer.make(\n request.epoch,\n request.entity,\n 'result',\n result,\n request.msgId,\n );\n return {\n reply,\n transfers: collectTransfers([\n result.keepNodes,\n result.keepEdges,\n result.nodeAcceptedIndex,\n result.links,\n ]),\n };\n } catch (err) {\n const reply = sequencer.make(\n request.epoch,\n request.entity,\n 'error',\n { message: err instanceof Error ? err.message : String(err) },\n request.msgId,\n );\n return { reply, transfers: [] };\n }\n }\n\n const reply = sequencer.make(\n request.epoch,\n request.entity,\n 'error',\n { message: `unknown op '${request.op}'` },\n request.msgId,\n );\n return { reply, transfers: [] };\n}\n","/**\n * In-process worker transport double — drives the REAL\n * runtime module through the REAL codec, asynchronously (microtask), with\n * REAL transfer semantics: payloads round through `structuredClone` with\n * the declared transfer list, so a wrong transfer set detaches something\n * the sender still needs and fails the suite loudly — exactly what a live\n * thread would do, minus the scheduling.\n */\n\nimport { EnvelopeSequencer } from '../workerProtocol';\nimport type { WorkerEnvelope } from '../workerProtocol';\nimport { handleWorkerRequest } from '../worker/runtime';\nimport type { WorkerTransport } from '../worker/lane';\n\nexport interface WorkerDouble extends WorkerTransport {\n /** Requests handled so far (post-clone shapes, in arrival order). */\n readonly handled: WorkerEnvelope[];\n}\n\nexport function createWorkerDouble(): WorkerDouble {\n const sequencer = new EnvelopeSequencer();\n const handled: WorkerEnvelope[] = [];\n let deliver: ((reply: WorkerEnvelope) => void) | null = null;\n return {\n handled,\n post(envelope, transfers) {\n // REAL transfer semantics: the sender's views detach here.\n const received = structuredClone(envelope, {\n transfer: [...transfers],\n }) as WorkerEnvelope;\n queueMicrotask(() => {\n handled.push(received);\n const { reply, transfers: replyTransfers } = handleWorkerRequest(received, sequencer);\n const delivered = structuredClone(reply, {\n transfer: [...replyTransfers],\n }) as WorkerEnvelope;\n deliver?.(delivered);\n });\n },\n onReply(cb) {\n deliver = cb;\n },\n terminate() {\n deliver = null;\n },\n };\n}\n"]}
@@ -1,5 +1,262 @@
1
- import { handleWorkerRequest } from '../chunk-GUXIITKK.js';
2
- import { EnvelopeSequencer } from '../chunk-NIJX5NVJ.js';
1
+ // src/workerProtocol.ts
2
+ var EnvelopeSequencer = class {
3
+ nextId = 1;
4
+ make(epoch, entity, op, payload, inReplyTo) {
5
+ const envelope = { msgId: this.nextId, epoch, entity, op, payload };
6
+ this.nextId += 1;
7
+ if (inReplyTo !== void 0) envelope.inReplyTo = inReplyTo;
8
+ return envelope;
9
+ }
10
+ };
11
+ function collectTransfers(views) {
12
+ const seen = /* @__PURE__ */ new Set();
13
+ const out = [];
14
+ for (const view of views) {
15
+ const buffer = view.buffer;
16
+ if (!(buffer instanceof ArrayBuffer)) continue;
17
+ if (seen.has(buffer)) continue;
18
+ seen.add(buffer);
19
+ out.push(buffer);
20
+ }
21
+ return out;
22
+ }
23
+ function decodeStringTable(table) {
24
+ const decoder = new TextDecoder();
25
+ const n = table.offsets.length - 1;
26
+ const out = new Array(n);
27
+ for (let i = 0; i < n; i++) {
28
+ out[i] = decoder.decode(table.bytes.subarray(table.offsets[i], table.offsets[i + 1]));
29
+ }
30
+ return out;
31
+ }
32
+ function isWellFormedEnvelope(value) {
33
+ if (value === null || typeof value !== "object") return false;
34
+ const e = value;
35
+ return typeof e.msgId === "number" && Number.isInteger(e.msgId) && e.msgId > 0 && typeof e.epoch === "number" && Number.isInteger(e.epoch) && e.epoch >= 0 && (e.entity === "nodes" || e.entity === "edges" || e.entity === "scene") && typeof e.op === "string" && e.op.length > 0 && (e.inReplyTo === void 0 || Number.isInteger(e.inReplyTo) && e.inReplyTo > 0);
36
+ }
37
+
38
+ // src/types.ts
39
+ var DIAGNOSTIC_SAMPLE_CAP = 10;
40
+
41
+ // src/columnarValidate.ts
42
+ function canonicalizeDictionary(dictionary) {
43
+ const canonical = new Uint32Array(dictionary.length);
44
+ const firstByString = /* @__PURE__ */ new Map();
45
+ for (let d = 0; d < dictionary.length; d++) {
46
+ const existing = firstByString.get(dictionary[d]);
47
+ if (existing === void 0) {
48
+ firstByString.set(dictionary[d], d);
49
+ canonical[d] = d;
50
+ } else {
51
+ canonical[d] = existing;
52
+ }
53
+ }
54
+ return canonical;
55
+ }
56
+ function record(tally, sample) {
57
+ tally.count++;
58
+ if (tally.samples.length < DIAGNOSTIC_SAMPLE_CAP) tally.samples.push(sample);
59
+ }
60
+ function pushDiagnostic(out, code, severity, tally, message) {
61
+ if (tally.count === 0) return;
62
+ out.push({ code, severity, count: tally.count, sampleIds: tally.samples, message });
63
+ }
64
+ function acceptColumnar(snapshot) {
65
+ const nodeIds = snapshot.nodes.ids;
66
+ const edgeIds = snapshot.edges.ids;
67
+ const nodeRows = snapshot.nodes.length;
68
+ const edgeRows = snapshot.edges.length;
69
+ const duplicateNode = { count: 0, samples: [] };
70
+ const duplicateEdge = { count: 0, samples: [] };
71
+ const selfLoop = { count: 0, samples: [] };
72
+ const invalidNode = { count: 0, samples: [] };
73
+ const danglingEdge = { count: 0, samples: [] };
74
+ const nodeCanonical = canonicalizeDictionary(nodeIds.dictionary);
75
+ const nulDict = new Uint8Array(nodeIds.dictionary.length);
76
+ for (let d = 0; d < nodeIds.dictionary.length; d++) {
77
+ if (nodeIds.dictionary[d].includes("\0")) nulDict[d] = 1;
78
+ }
79
+ const keepNodes = new Uint8Array(nodeRows);
80
+ const nodeAcceptedIndex = new Int32Array(nodeRows).fill(-1);
81
+ const acceptedByCanonical = new Int32Array(nodeIds.dictionary.length).fill(-1);
82
+ let acceptedNodeCount = 0;
83
+ for (let i = 0; i < nodeRows; i++) {
84
+ if (nulDict[nodeIds.codes[i]] !== 0) {
85
+ record(invalidNode, `[${i}]`);
86
+ continue;
87
+ }
88
+ const canonical = nodeCanonical[nodeIds.codes[i]];
89
+ const survivor = acceptedByCanonical[canonical];
90
+ if (survivor === -1) {
91
+ acceptedByCanonical[canonical] = acceptedNodeCount;
92
+ nodeAcceptedIndex[i] = acceptedNodeCount;
93
+ keepNodes[i] = 1;
94
+ acceptedNodeCount += 1;
95
+ } else {
96
+ nodeAcceptedIndex[i] = survivor;
97
+ record(duplicateNode, nodeIds.dictionary[nodeIds.codes[i]]);
98
+ }
99
+ }
100
+ const edgeCanonical = canonicalizeDictionary(edgeIds.dictionary);
101
+ const keepEdges = new Uint8Array(edgeRows);
102
+ const seenEdgeByCanonical = new Uint8Array(edgeIds.dictionary.length);
103
+ const { source, target } = snapshot.edges;
104
+ const linksOut = new Uint32Array(edgeRows * 2);
105
+ let acceptedEdgeCount = 0;
106
+ for (let e = 0; e < edgeRows; e++) {
107
+ const canonical = edgeCanonical[edgeIds.codes[e]];
108
+ if (seenEdgeByCanonical[canonical] !== 0) {
109
+ record(duplicateEdge, edgeIds.dictionary[edgeIds.codes[e]]);
110
+ continue;
111
+ }
112
+ seenEdgeByCanonical[canonical] = 1;
113
+ const s = nodeAcceptedIndex[source[e]];
114
+ const t = nodeAcceptedIndex[target[e]];
115
+ if (s === -1 || t === -1) {
116
+ record(
117
+ danglingEdge,
118
+ nodeIds.dictionary[nodeIds.codes[(s === -1 ? source : target)[e]]]
119
+ );
120
+ continue;
121
+ }
122
+ if (s === t) {
123
+ record(selfLoop, nodeIds.dictionary[nodeIds.codes[source[e]]]);
124
+ }
125
+ keepEdges[e] = 1;
126
+ linksOut[acceptedEdgeCount * 2] = s;
127
+ linksOut[acceptedEdgeCount * 2 + 1] = t;
128
+ acceptedEdgeCount += 1;
129
+ }
130
+ const diagnostics = [];
131
+ pushDiagnostic(
132
+ diagnostics,
133
+ "invalid-node",
134
+ "error",
135
+ invalidNode,
136
+ `${invalidNode.count} node row(s) dropped: missing, non-string, or NUL-containing id`
137
+ );
138
+ pushDiagnostic(
139
+ diagnostics,
140
+ "duplicate-node-id",
141
+ "warning",
142
+ duplicateNode,
143
+ `${duplicateNode.count} duplicate node id(s) dropped (first occurrence wins)`
144
+ );
145
+ pushDiagnostic(
146
+ diagnostics,
147
+ "dangling-edge-endpoint",
148
+ "warning",
149
+ danglingEdge,
150
+ `${danglingEdge.count} edge(s) dropped: endpoint not in accepted node set`
151
+ );
152
+ pushDiagnostic(
153
+ diagnostics,
154
+ "duplicate-edge-id",
155
+ "warning",
156
+ duplicateEdge,
157
+ `${duplicateEdge.count} duplicate edge id(s) dropped (first occurrence wins)`
158
+ );
159
+ pushDiagnostic(
160
+ diagnostics,
161
+ "self-loop-retained",
162
+ "info",
163
+ selfLoop,
164
+ `${selfLoop.count} self-loop edge(s) retained`
165
+ );
166
+ return {
167
+ keepNodes,
168
+ keepEdges,
169
+ acceptedNodeCount,
170
+ acceptedEdgeCount,
171
+ nodeAcceptedIndex,
172
+ links: linksOut.subarray(0, acceptedEdgeCount * 2).slice(),
173
+ diagnostics
174
+ };
175
+ }
176
+
177
+ // src/worker/runtime.ts
178
+ function handleWorkerRequest(request, sequencer2) {
179
+ if (!isWellFormedEnvelope(request)) {
180
+ const reply2 = sequencer2.make(0, "scene", "error", {
181
+ message: "malformed envelope (protocol violation)"
182
+ });
183
+ return { reply: reply2, transfers: [] };
184
+ }
185
+ if (request.op === "derive-columnar") {
186
+ try {
187
+ const p = request.payload;
188
+ const snapshot = {
189
+ kind: "columnar",
190
+ datasetKey: "worker",
191
+ // acceptance rules never read the coordinate
192
+ sourceRevision: 0,
193
+ nodes: {
194
+ ids: {
195
+ kind: "string",
196
+ dictionary: decodeStringTable(p.nodeIdTable),
197
+ codes: p.nodeIdCodes
198
+ },
199
+ columns: {},
200
+ length: p.nodeCount
201
+ },
202
+ edges: {
203
+ ids: {
204
+ kind: "string",
205
+ dictionary: decodeStringTable(p.edgeIdTable),
206
+ codes: p.edgeIdCodes
207
+ },
208
+ source: p.edgeSource,
209
+ target: p.edgeTarget,
210
+ columns: {},
211
+ length: p.edgeCount
212
+ }
213
+ };
214
+ const acceptance = acceptColumnar(snapshot);
215
+ const result = {
216
+ keepNodes: acceptance.keepNodes,
217
+ keepEdges: acceptance.keepEdges,
218
+ acceptedNodeCount: acceptance.acceptedNodeCount,
219
+ acceptedEdgeCount: acceptance.acceptedEdgeCount,
220
+ nodeAcceptedIndex: acceptance.nodeAcceptedIndex,
221
+ links: acceptance.links,
222
+ diagnostics: acceptance.diagnostics
223
+ };
224
+ const reply2 = sequencer2.make(
225
+ request.epoch,
226
+ request.entity,
227
+ "result",
228
+ result,
229
+ request.msgId
230
+ );
231
+ return {
232
+ reply: reply2,
233
+ transfers: collectTransfers([
234
+ result.keepNodes,
235
+ result.keepEdges,
236
+ result.nodeAcceptedIndex,
237
+ result.links
238
+ ])
239
+ };
240
+ } catch (err) {
241
+ const reply2 = sequencer2.make(
242
+ request.epoch,
243
+ request.entity,
244
+ "error",
245
+ { message: err instanceof Error ? err.message : String(err) },
246
+ request.msgId
247
+ );
248
+ return { reply: reply2, transfers: [] };
249
+ }
250
+ }
251
+ const reply = sequencer2.make(
252
+ request.epoch,
253
+ request.entity,
254
+ "error",
255
+ { message: `unknown op '${request.op}'` },
256
+ request.msgId
257
+ );
258
+ return { reply, transfers: [] };
259
+ }
3
260
 
4
261
  // src/worker/entry.ts
5
262
  var sequencer = new EnvelopeSequencer();