test(explore): add the factory-closure fixture and its selection probe (CG-27)

A file whose top-level symbol spans almost all of it — createFoo() returning
an object of closures — is how Svelte 5 rune stores, React custom-hook modules,
IIFE module-pattern JS and Zustand's create((set,get)=>({…})) are all written.
probe-factory-closure.mjs measures what such a file DELIVERS from within: which
inner symbols' definitions reach the agent, not how many bytes did.
This commit is contained in:
Colby McHenry
2026-08-06 13:58:36 -05:00
parent dc4fd755ef
commit d49265043c
11 changed files with 992 additions and 0 deletions
@@ -0,0 +1,62 @@
import type { FilterSpec } from '../stores/types';
/** Parse the dashboard's filter bar text into filter specs. */
const OPERATORS: Record<string, FilterSpec['op']> = {
':': 'eq',
'~': 'contains',
'>': 'gt',
'<': 'lt',
};
/** `title~sales kind:chart column>3` → three specs. */
export function parseFilterText(text: string): FilterSpec[] {
const specs: FilterSpec[] = [];
for (const token of tokenize(text)) {
const spec = parseToken(token);
if (spec) specs.push(spec);
}
return specs;
}
/** Split on whitespace, honouring double-quoted values. */
export function tokenize(text: string): string[] {
const tokens: string[] = [];
let current = '';
let quoted = false;
for (const ch of text) {
if (ch === '"') { quoted = !quoted; continue; }
if (!quoted && /\s/.test(ch)) {
if (current.length > 0) { tokens.push(current); current = ''; }
continue;
}
current += ch;
}
if (current.length > 0) tokens.push(current);
return tokens;
}
/** One `field<op>value` token, or null when it does not parse. */
export function parseToken(token: string): FilterSpec | null {
for (const [symbol, op] of Object.entries(OPERATORS)) {
const at = token.indexOf(symbol);
if (at <= 0) continue;
const field = token.slice(0, at).trim();
const value = token.slice(at + symbol.length).trim();
if (field.length === 0 || value.length === 0) return null;
return { field, op, value };
}
return null;
}
/** Render specs back to filter-bar text — the round trip the URL uses. */
export function formatFilterText(specs: readonly FilterSpec[]): string {
const symbolFor = (op: FilterSpec['op']): string =>
Object.entries(OPERATORS).find(([, candidate]) => candidate === op)?.[0] ?? ':';
return specs
.map((spec) => {
const value = /\s/.test(spec.value) ? `"${spec.value}"` : spec.value;
return `${spec.field}${symbolFor(spec.op)}${value}`;
})
.join(' ');
}
@@ -0,0 +1,101 @@
import type { FilterSpec, MetricSample, Widget } from '../stores/types';
import { bucketByHour, meanOf, rateOfChange } from '../lib/metrics';
/**
* Stateless metric helpers — the server-shaped half of the same domain. These
* are ordinary top-level functions, not closures, so they are the control the
* factory-closure file is measured against.
*/
const STALE_AFTER_MS = 15 * 60 * 1000;
/** Refresh a cached metric map in place, returning the widgets that changed. */
export function refreshMetricCache(
cache: Map<string, MetricSample[]>,
incoming: readonly MetricSample[],
now: number,
): string[] {
const touched = new Set<string>();
for (const sample of incoming) {
if (typeof sample.value !== 'number' || Number.isNaN(sample.value)) continue;
const bucket = cache.get(sample.widgetId);
if (bucket) bucket.push(sample);
else cache.set(sample.widgetId, [sample]);
touched.add(sample.widgetId);
}
for (const [widgetId, bucket] of cache) {
const fresh = bucket.filter((s) => now - s.at <= STALE_AFTER_MS);
if (fresh.length !== bucket.length) {
cache.set(widgetId, fresh);
touched.add(widgetId);
}
}
return [...touched].sort();
}
/** Apply a filter spec set to raw samples rather than to widgets. */
export function filterMetrics(
samples: readonly MetricSample[],
specs: readonly FilterSpec[],
): MetricSample[] {
if (specs.length === 0) return samples.slice();
return samples.filter((sample) => specs.every((spec) => {
const field = spec.field === 'unit'
? sample.unit
: spec.field === 'widget'
? sample.widgetId
: String(sample.value);
switch (spec.op) {
case 'eq': return field === spec.value;
case 'contains': return field.includes(spec.value);
case 'gt': return Number(field) > Number(spec.value);
case 'lt': return Number(field) < Number(spec.value);
default: return false;
}
}));
}
/** Per-widget rollup used by the server-rendered summary card. */
export function rollupByWidget(
samples: readonly MetricSample[],
widgets: readonly Widget[],
): Array<{ widgetId: string; title: string; mean: number; slope: number; hours: number }> {
const titles = new Map(widgets.map((w) => [w.id, w.title]));
const grouped = new Map<string, MetricSample[]>();
for (const sample of samples) {
const bucket = grouped.get(sample.widgetId);
if (bucket) bucket.push(sample);
else grouped.set(sample.widgetId, [sample]);
}
const out: Array<{ widgetId: string; title: string; mean: number; slope: number; hours: number }> = [];
for (const [widgetId, bucket] of grouped) {
out.push({
widgetId,
title: titles.get(widgetId) ?? '(unknown)',
mean: meanOf(bucket),
slope: rateOfChange(bucket),
hours: bucketByHour(bucket).size,
});
}
out.sort((a, b) => b.mean - a.mean);
return out;
}
/** Which widgets have not reported inside the staleness window. */
export function staleWidgets(
samples: readonly MetricSample[],
widgets: readonly Widget[],
now: number,
): string[] {
const newest = new Map<string, number>();
for (const sample of samples) {
const seen = newest.get(sample.widgetId) ?? 0;
if (sample.at > seen) newest.set(sample.widgetId, sample.at);
}
return widgets
.filter((w) => !w.hidden)
.filter((w) => now - (newest.get(w.id) ?? 0) > STALE_AFTER_MS)
.map((w) => w.id)
.sort();
}