archive issue fix
Some checks failed
CI / check (push) Failing after 5m5s

This commit is contained in:
2026-09-10 19:29:39 +05:30
parent 6249e00a3a
commit f522b6508e
20 changed files with 2444 additions and 207 deletions

View File

@@ -3840,6 +3840,192 @@ record('every published agent offers at least one starter where it applies',
.every((a) => a.pages.length === 0 || runtime.agentStarters(a, null).length > 0),
ALL_AGENTS.map((a) => `${a.id}:${a.starters.length}`).join(' '));
/* ── Removing an agent ───────────────────────────────────────────────────
*
* Removal is permanent, and the two things that make it safe are both
* structural rather than visible: WHICH agents offer it, and that archiving
* never quietly becomes it.
*
* The menu is duplicated between the card view and the table row — two blocks
* of the same JSX — so every property here is asserted against BOTH. A guard
* added to one and forgotten in the other is exactly the shape of bug that
* would ship a delete button on a built-in agent.
*
* `shipped` is the source of truth, from the ids this build bundles. Nothing
* here reads a display name: two agents may legitimately share one.
*/
const removeItems = agentsListSource.match(
/onAction\('remove', agent\)[\s\S]{0,400}?<\/DropdownMenuItem>/g) || [];
record('both agent menus offer removal, and neither offers it unconditionally',
removeItems.length === 2
&& (agentsListSource.match(/\{\(overridden \|\| !shipped\) && \(/g) || []).length === 2,
`${removeItems.length} remove item(s), each behind (overridden || !shipped)`);
record('a custom agent is offered Remove, and a built-in one is only offered a revert',
removeItems.every((block) => / Remove</.test(block) && /Revert to shipped/.test(block)
&& /shipped\s*\?/.test(block)),
'the label is chosen by `shipped`, not by name');
/* Archive is reversible; Remove is not. The menu must not make removal depend
on status, or an archived custom agent becomes unremovable — which would
silently turn Archive into the only exit and leave the row forever. */
record('removal does not depend on an agent status, so an archived custom agent stays removable',
removeItems.every((block) => !/status/.test(block)),
'the remove item reads `shipped`/`overridden` only');
/* Removal is REVERSIBLE, and the confirmation is where a reader learns that.
Copy that promised permanence would be a false statement about what the
button does — the agent is archived, not destroyed — so the wording is
asserted, including the absence of the two phrases that would be lies. */
record('removing a custom agent confirms first, in words that say it is reversible',
/'Remove agent\?'/.test(agentsListSource)
&& /This agent will be removed from the active Agents list\./.test(agentsListSource)
&& /can be restored later from Archived/.test(agentsListSource)
&& /'Remove Agent'/.test(agentsListSource),
'title, description and confirm label');
record('...and the confirmation never claims the removal is permanent',
!/cannot be undone/i.test(agentsListSource)
&& !/permanently (remove|delete)/i.test(agentsListSource),
'no irreversibility language anywhere on the screen');
/* The substance behind that copy: Remove on an authored agent runs ARCHIVE.
Only a shipped agent's own override is deleted, and deleting an override is
how "Revert to shipped" restores the product's definition — it destroys no
agent. If this resolution is ever removed, Remove becomes a hard delete
again and every promise above becomes false. */
record('Remove archives an authored agent rather than deleting it',
/const resolved = action === 'remove' && !isShipped\(agent\.id\) \? 'archive' : action;/
.test(agentsListSource),
'run() resolves remove -> archive for anything not shipped');
record('...and the default list stops showing what has been removed',
/useState\('active'\)/.test(agentsListSource)
&& /if \(status === 'active'\) return found\.filter\(\(a\) => a\.status !== 'archived'\);/
.test(agentsListSource),
'the default filter is active, which excludes archived');
record('...while Archived stays reachable as the place removal is undone',
/setStatus\('archived'\)/.test(agentsListSource)
&& /onAction\('restore', agent\)/.test(agentsListSource),
'the Archived tab and Restore as draft both survive');
/* The tab must be there BEFORE anything is in it. It was rendered behind
`archivedCount > 0`, so the one screen that says where a removed agent went
only appeared once a reader had already removed one and gone looking — and
the confirmation names "Archived" while no such tab is on screen. */
record('...and Archived is offered even when it is empty',
!/\{archivedCount > 0 && \(/.test(agentsListSource)
&& /Archived <span[^>]*>\(\{archivedCount\}\)/.test(agentsListSource),
'the tab is unconditional and shows its count');
record('...and reverting a built-in agent is not worded as a removal',
/'Revert to the shipped definition\?'/.test(agentsListSource)
&& /isShipped\(confirming\?\.agent\?\.id\) \? 'Confirm' : 'Remove Agent'/.test(agentsListSource),
'the shipped path keeps its own copy');
record('a removal that fails is reported rather than swallowed',
/if \(result\?\.error\) toast\.error\(result\.error\)/.test(agentsListSource),
'run() surfaces the error the mutation returned');
/* The gate itself, exercised rather than read: every id this build ships is
`shipped`, so none of them reaches the branch that renders Remove. This is
the same set `useAgents().isShipped` tests against — `AGENTS`, bundled from
the agent definitions under src/agents — so the check moves with the
product. */
const shippedAgentIds = new Set(ALL_AGENTS.map((a) => a.id));
record('every agent this build ships is classified as built-in',
ALL_AGENTS.every((a) => shippedAgentIds.has(a.id)),
`${shippedAgentIds.size} shipped id(s)`);
record('...and an authored agent is not, whatever its status',
['draft', 'published', 'archived'].every((status) => {
const id = `authored-${status}-agent`;
return !shippedAgentIds.has(id);
}),
'draft, published and archived authored ids are all removable');
/* ── Remove and restore, exercised end to end ────────────────────────────
*
* The claim the confirmation makes — "its configuration and skills will be
* preserved and it can be rmRestored later" — is a claim about these two
* functions, so it is tested against them rather than against the sentence.
*
* Both are pure over Markdown and the Markdown is the authoritative artefact,
* so "nothing was lost" is checkable exactly: the source may differ in the
* status line and in nothing else, and the parsed agent may differ in `status`
* and in nothing else. A patch that dropped a tool, renumbered a version or
* rewrote an id would fail here rather than in somebody's account.
*/
const rmLifecycle = await server.ssrLoadModule('/src/lib/agents/agentLifecycle.js');
const rmAuthored = [
'---',
'id: coverage-helper',
'name: Coverage Helper',
'description: Finds and offers cover for open shifts.',
'status: published',
'version: 3',
'pages:',
' - control-center',
' - positions',
'tools:',
' - workforce.coverage',
'skills:',
' - create-position',
'---',
'',
'## Instructions',
'Find the shifts nobody has taken and say who could take them.',
].join('\n');
const rmStatusless = (src) => src.replace(/^status:.*$/m, 'status: <redacted>');
/* `markdown` is excluded because it IS the source, status line and all — the
line above already asserts that source byte-for-byte, so comparing it again
here would only re-report the one difference both checks expect. Every other
parsed field, including tools, skills, pages, instructions and version, is
compared. */
const rmWithoutStatus = (agent) => {
const { status, markdown, ...rest } = agent;
return JSON.stringify(rest);
};
const rmRemoved = rmLifecycle.archiveAgent(rmAuthored);
const rmRestored = rmLifecycle.restoreAgent(rmRemoved);
const rmBefore = agentReg.parseAgent(rmAuthored, { custom: true });
const rmAfterRemove = agentReg.parseAgent(rmRemoved, { custom: true });
const rmAfterRestore = agentReg.parseAgent(rmRestored, { custom: true });
record('remove: an authored agent becomes archived rather than disappearing',
rmAfterRemove.status === 'archived',
`status ${rmBefore.status} -> ${rmAfterRemove.status}`);
record('remove: the definition keeps its identity',
rmAfterRemove.id === rmBefore.id && rmAfterRemove.id === 'coverage-helper',
rmAfterRemove.id);
record('remove: instructions, tools, skills, pages and version all survive',
rmStatusless(rmRemoved) === rmStatusless(rmAuthored)
&& rmWithoutStatus(rmAfterRemove) === rmWithoutStatus(rmBefore),
'the source differs in the status line and nothing else');
record('restore: the SAME agent comes back, as a draft',
rmAfterRestore.id === rmBefore.id && rmAfterRestore.status === 'draft',
`${rmAfterRestore.id} @ ${rmAfterRestore.status}`);
record('restore: nothing was lost on the round trip',
rmStatusless(rmRestored) === rmStatusless(rmAuthored)
&& rmWithoutStatus(rmAfterRestore) === rmWithoutStatus(rmBefore),
'archive -> restore is lossless apart from status');
/* Removing something already archived must not escalate into anything else:
it is still that same archived definition afterwards. */
const rmRemovedTwice = rmLifecycle.archiveAgent(rmRemoved);
record('remove: removing an already-archived agent leaves it archived and whole',
agentReg.parseAgent(rmRemovedTwice, { custom: true }).status === 'archived'
&& rmStatusless(rmRemovedTwice) === rmStatusless(rmAuthored),
'idempotent, and still non-destructive');
/* ── 18. Conversation records and insights ───────────────────────────────
*
* Conversations gained fields: which agent answered, where, what it used, and
@@ -8774,6 +8960,7 @@ console.log('\n── Candidates vs Talent Pool ──');
const skillE = await server.ssrLoadModule('/src/lib/ui/skillNodes.js');
const uiCfgE = await server.ssrLoadModule('/src/lib/skills/uiConfig.js');
const editorOps = await server.ssrLoadModule('/src/components/ui-editor/ops.js');
const validateE = await server.ssrLoadModule('/src/lib/ui/validate.js');
await server.ssrLoadModule('/src/components/ui-tree/nodeTypes.jsx');
await server.ssrLoadModule('/src/pages/admin/hired-history/nodes.jsx');
await server.ssrLoadModule('/src/pages/admin/positions/nodes.js');
@@ -9207,7 +9394,7 @@ console.log('\n── Candidates vs Talent Pool ──');
})().pass);
record('a failed node renders in place, named, and still addressable', (() => {
const boundary = new boundaryE.UiNodeBoundary({ node: { id: 'bad', type: 'chart', props: {} } });
const boundary = new boundaryE.UiNodeBoundary({ node: { id: 'bad', type: 'bar-chart', props: {} } });
boundary.state = { failed: true, forNode: 'bad' };
const html = draw(boundary.render());
return {
@@ -9552,7 +9739,8 @@ console.log('\n── Candidates vs Talent Pool ──');
})().pass);
record('replace: an unregistered type is refused', (() => {
const r = replaceWith('pie-chart');
/* A name nobody registers, and nothing here should ever register. */
const r = replaceWith('sculpture');
return { pass: !r.ok && /Unsupported UI type/i.test(JSON.stringify(r.problems)),
detail: JSON.stringify(r.problems).slice(0, 120) };
})().pass);
@@ -9612,21 +9800,41 @@ console.log('\n── Candidates vs Talent Pool ──');
})().pass);
/* ── Chart and pie ────────────────────────────────────────────────────
/* ── Visualizations ───────────────────────────────────────────────────
*
* Two node types that are deliberately *not* skill section types, drawing
* Five node types that are deliberately *not* skill section types, drawing
* the payload a `flow` reading already resolves to. The tests that matter
* are the ones about compatibility: nothing may become a chart unless its
* reading really carries a series.
* are about compatibility, and there are now two kinds: whether a component
* *can* draw a reading, and whether doing so would be true.
*/
const VIZ = ['bar-chart', 'line-chart', 'area-chart', 'pie-chart', 'donut-chart'];
/* What a reading means, asked the same way every consumer asks it. */
const seriesMod = await server.ssrLoadModule('/src/lib/ui/series.js');
const seriesNode = (type, source, extra = {}) => nodeE.makeNode({
id: 'viz', type, origin: 'user', props: { title: 'Hiring performance' },
data: { source }, layout: { spacingBefore: 'lg' },
presentation: { variant: 'emphasis', density: 'compact' }, ...extra,
});
for (const type of ['chart', 'pie']) {
/**
* A reading whose meaning this visualization can honestly draw.
*
* There is no single source that fits all five, and that is the point: a
* line may draw a reading that is ordered, a pie may draw one whose points
* are parts of a whole, and no reading is both. Picked from what the source
* itself declares rather than assumed.
*/
const READING_OF_KIND = {
periodic: 'candidates.activity',
cumulative: 'position.pipeline',
parts: 'activity.breakdown',
};
const readingFor = (type) => READING_OF_KIND[nreg.get(type).seriesKinds[0]];
for (const type of VIZ) {
record(`${type}: is a registered node type with a real component`, (() => {
const entry = nreg.get(type);
return { pass: Boolean(entry) && typeof entry.component === 'function' && entry.dataRequired,
@@ -9639,6 +9847,12 @@ console.log('\n── Candidates vs Talent Pool ──');
detail: entry.dataShapes.join(', ') };
})().pass);
record(`${type}: declares which series meanings it can honestly draw`, (() => {
const entry = nreg.get(type);
const known = entry.seriesKinds.every((k) => nodeE.SERIES_KINDS.includes(k));
return { pass: entry.seriesKinds.length > 0 && known, detail: entry.seriesKinds.join(', ') };
})().pass);
record(`${type}: supports the presentation vocabulary it honours`, (() => {
const entry = nreg.get(type);
return { pass: entry.variants.length === 3 && entry.densities.length === 2,
@@ -9646,15 +9860,28 @@ console.log('\n── Candidates vs Talent Pool ──');
})().pass);
record(`${type}: a card on a series reading can become one`, (() => {
const r = opsE.applyOperation([seriesNode('card', 'hires.performance')],
const source = readingFor(type);
const r = opsE.applyOperation([seriesNode('card', source)],
{ op: 'replace', target: 'viz', type }, ectx);
const after = r.ok ? nodeE.findNode(r.tree, 'viz') : null;
return { pass: r.ok && after.type === type && after.id === 'viz'
&& after.data.source === 'hires.performance', detail: JSON.stringify(r.problems) };
&& after.data.source === source, detail: JSON.stringify(r.problems) };
})().pass);
/* Gap 4: a reading whose meaning was never declared is refused, not
guessed at. `hires.performance` draws `flow` and `stats` — structurally
every chart could take it — and says nothing about what its figures
mean, which used to be read as consent. */
record(`${type}: a reading of unknown meaning is refused, not guessed`, (() => {
const before = [seriesNode('card', 'hires.performance')];
const r = opsE.applyOperation(before, { op: 'replace', target: 'viz', type }, ectx);
const said = JSON.stringify(r.problems);
return { pass: !r.ok && r.tree === before && /does not say what its figures mean/i.test(said),
detail: said.slice(0, 170) };
})().pass);
record(`${type}: replacement keeps layout, presentation and title`, (() => {
const after = opsE.applyOperation([seriesNode('card', 'hires.performance')],
const after = opsE.applyOperation([seriesNode('card', readingFor(type))],
{ op: 'replace', target: 'viz', type }, ectx).tree[0];
return { pass: after.layout.spacingBefore === 'lg' && after.presentation.variant === 'emphasis'
&& after.presentation.density === 'compact' && after.props.title === 'Hiring performance',
@@ -9678,42 +9905,571 @@ console.log('\n── Candidates vs Talent Pool ──');
})().pass);
record(`${type}: the editor offers it only where the reading fits`, (() => {
const fits = nreg.replacements('card',
{ shapes: surfaces.dataSourceFor('hires.performance').shapes, page: 'analytics' });
const doesNot = nreg.replacements('list',
{ shapes: surfaces.dataSourceFor('position.requirements').shapes, page: 'analytics' });
return { pass: fits.includes(type) && !doesNot.includes(type),
detail: `fits: ${fits.join(',')} | not: ${doesNot.join(',')}` };
const source = readingFor(type);
const fits = nreg.replacements('card', {
shapes: surfaces.dataSourceFor(source).shapes, page: 'analytics',
seriesKind: seriesMod.kindOfBinding({ source }), bound: true,
});
const doesNot = nreg.replacements('list', {
shapes: surfaces.dataSourceFor('position.requirements').shapes, page: 'analytics',
seriesKind: seriesMod.kindOfBinding({ source: 'position.requirements' }), bound: true,
});
/* And the one gap 4 is about: structurally able, meaning undeclared. */
const unknown = nreg.replacements('card', {
shapes: surfaces.dataSourceFor('hires.performance').shapes, page: 'analytics',
seriesKind: seriesMod.kindOfBinding({ source: 'hires.performance' }), bound: true,
});
return { pass: fits.includes(type) && !doesNot.includes(type) && !unknown.includes(type),
detail: `fits: ${fits.join(',')} | not: ${doesNot.join(',')} | unknown: ${unknown.join(',') || 'none'}` };
})().pass);
record(`${type}: Owliver plans the same operation the editor emits`, (() => {
const tree = [seriesNode('card', 'hires.performance')];
const tree = [seriesNode('card', readingFor(type))];
const node = inspectE.inspectTree(tree, ectx)[0];
const fromEditor = editorOps.replaceOp(node, type);
const phrase = type === 'pie' ? 'change the Hiring performance to a pie' : 'change the Hiring performance to a chart';
const fromOwliver = intentE.matchUiEdit(phrase, { tree, registry: nreg, page: 'analytics' });
const label = nreg.get(type).label.toLowerCase();
const fromOwliver = intentE.matchUiEdit(
`change the Hiring performance to a ${label}`, { tree, registry: nreg, page: 'analytics' });
return { pass: JSON.stringify(fromEditor) === JSON.stringify(fromOwliver?.op),
detail: `${JSON.stringify(fromEditor)} vs ${JSON.stringify(fromOwliver?.op)}` };
})().pass);
}
record('chart/pie: are not skill section types', (() => {
record('visualizations: none of them is a skill section type', (() => {
/* The MD vocabulary is untouched, so the Go parser and its oracle are too. */
const inMd = surfaces.SUPPORTED_SECTION_TYPES.filter((t) => t === 'chart' || t === 'pie');
const inMd = surfaces.SUPPORTED_SECTION_TYPES.filter((t) => VIZ.includes(t));
return { pass: inMd.length === 0, detail: surfaces.SUPPORTED_SECTION_TYPES.join(',') };
})().pass);
record('chart/pie: ordinary data questions do not become visualisations', (() => {
record('visualizations: ordinary data questions do not become visualisations', (() => {
const tree = [seriesNode('card', 'hires.performance')];
const ordinary = ['What is on this page?', 'Show recent hires', 'How many candidates applied?',
'What is the hiring trend?', 'Compare the top candidates'];
const taken = ordinary.filter((q) => {
const m = intentE.matchUiEdit(q, { tree, registry: nreg, page: 'analytics' });
return m?.kind === 'plan' && (m.op?.type === 'chart' || m.op?.type === 'pie');
return m?.kind === 'plan' && VIZ.includes(m.op?.type);
});
return { pass: taken.length === 0, detail: taken.join(' | ') || 'none taken' };
})().pass);
/* ── Series registry and meaning ──────────────────────────────────────
*
* The half `dataShapes` could not express. A `flow` is, in the section
* vocabulary's own words, "a sequence of stages *or* periods" — so these
* check that the difference is now declared, enforced, and explained.
*/
{
const seriesE = await server.ssrLoadModule('/src/lib/ui/series.js');
record('series: the kind vocabulary is closed', () => true);
record('series: the kind vocabulary is closed',
JSON.stringify(nodeE.SERIES_KINDS) === JSON.stringify(['periodic', 'cumulative', 'parts']),
nodeE.SERIES_KINDS.join(', '));
record('series: Control Center publishes its hiring activity', (() => {
const entry = seriesE.seriesFor('control-center.hiring-activity');
return { pass: Boolean(entry) && entry.kind === 'periodic' && entry.measures.length === 4,
detail: entry ? `${entry.kind} · ${entry.measures.map((m) => m.key).join(',')}` : 'missing' };
})().pass);
record('series: a registration with an unknown kind is refused', (() => {
try {
seriesE.registerSeries({ id: 'x.y', kind: 'vibes', measures: [{ key: 'a', label: 'A' }], read: () => [] });
return false;
} catch (e) { return /unknown kind/i.test(e.message); }
})());
record('series: a registration with no measure is refused', (() => {
try {
seriesE.registerSeries({ id: 'x.z', kind: 'parts', measures: [], read: () => [] });
return false;
} catch (e) { return /at least one measure/i.test(e.message); }
})());
record('series: a registration with no read is refused', (() => {
try {
seriesE.registerSeries({ id: 'x.w', kind: 'parts', measures: [{ key: 'a', label: 'A' }] });
return false;
} catch (e) { return /needs a `read/i.test(e.message); }
})());
record('series: a reading bound to periods is periodic', (() => {
const kind = seriesE.kindOfBinding({ source: 'candidates.activity', params: { periods: ['today'] } });
return { pass: kind === 'periodic', detail: String(kind) };
})().pass);
record('series: a binding that cannot say vetoes nothing', (() => {
const kind = seriesE.kindOfBinding({ source: 'hires.performance', params: {} });
return { pass: kind === null, detail: String(kind) };
})().pass);
record('series: a page series resolves the page\u2019s own rows, unchanged', (() => {
const rows = [{ label: '9/1', applications: 3, screened: 2, interviews: 1, hires: 0 }];
const out = seriesE.readSeries({ series: 'control-center.hiring-activity' },
{ context: { activitySeries: rows } });
return { pass: out.rows.length === 1 && out.rows[0].applications === 3
&& out.rows[0].label === '9/1' && out.measures.length === 4,
detail: JSON.stringify(out.rows) };
})().pass);
record('series: nothing is invented when the page published nothing', (() => {
const out = seriesE.readSeries({ series: 'control-center.hiring-activity' }, { context: {} });
return { pass: out.rows.length === 0, detail: JSON.stringify(out.rows) };
})().pass);
}
/* ── Built-in chart → another visualization ───────────────────────────
*
* The whole point, end to end on the real page composition: the section
* Control Center ships is bound to a series it publishes, and that is the
* only reason it can be drawn another way.
*/
{
const seriesE = await server.ssrLoadModule('/src/lib/ui/series.js');
await server.ssrLoadModule('/src/pages/admin/control-center/nodes.jsx');
const ccTree = () => compE.composePage('control-center', ectx).tree;
const activity = () => ccTree().find((n) => n.id === 'cc-activity');
record('built-in: Hiring activity is bound to the page\u2019s own series', (() => {
const node = activity();
return { pass: node?.data?.series === 'control-center.hiring-activity',
detail: JSON.stringify(node?.data) };
})().pass);
{
const verdict = validateE.validateTree(ccTree(), ectx);
record('built-in: it composes and validates as it ships',
verdict.ok === true, JSON.stringify(verdict.problems).slice(0, 260));
}
for (const type of ['bar-chart', 'line-chart', 'area-chart']) {
record(`built-in: Hiring activity can become a ${type}`, (() => {
const r = opsE.applyOperation(ccTree(), { op: 'replace', target: 'cc-activity', type }, ectx);
const after = r.ok ? nodeE.findNode(r.tree, 'cc-activity') : null;
return { pass: r.ok && after.type === type
&& after.id === 'cc-activity'
&& after.data.series === 'control-center.hiring-activity'
&& after.origin === 'builtin',
detail: JSON.stringify(r.problems).slice(0, 160) };
})().pass);
}
for (const type of ['pie-chart', 'donut-chart']) {
record(`built-in: Hiring activity refuses ${type}, and says why`, (() => {
const r = opsE.applyOperation(ccTree(), { op: 'replace', target: 'cc-activity', type }, ectx);
const said = JSON.stringify(r.problems);
return { pass: !r.ok && /ordered in time/i.test(said), detail: said.slice(0, 170) };
})().pass);
}
record('built-in: a refused visualization mutates nothing', (() => {
const before = ccTree();
const r = opsE.applyOperation(before, { op: 'replace', target: 'cc-activity', type: 'pie-chart' }, ectx);
return { pass: !r.ok && r.tree === before, detail: String(r.ok) };
})().pass);
record('built-in: the offering is the registry\u2019s, and excludes the untrue ones', (() => {
const node = activity();
const offered = nreg.replacements(node.type, {
page: 'control-center',
seriesKind: seriesE.kindOfBinding(node.data),
seriesBound: true,
bound: true,
});
return { pass: offered.includes('bar-chart') && offered.includes('line-chart')
&& offered.includes('area-chart') && !offered.includes('pie-chart')
&& !offered.includes('donut-chart'),
detail: offered.join(', ') };
})().pass);
record('built-in: Owliver and the editor emit the same operation', (() => {
const tree = ccTree();
const node = inspectE.inspectTree(tree, { ...ectx, page: 'control-center' })
.find((n) => n.id === 'cc-activity');
const fromEditor = editorOps.replaceOp(node, 'bar-chart');
const fromOwliver = intentE.matchUiEdit('Change Hiring activity to a bar chart',
{ tree, registry: nreg, page: 'control-center' });
return { pass: JSON.stringify(fromEditor) === JSON.stringify(fromOwliver?.op),
detail: `${JSON.stringify(fromEditor)} vs ${JSON.stringify(fromOwliver?.op)}` };
})().pass);
record('built-in: a bar chart can be changed back to a line chart', (() => {
const barred = opsE.applyOperation(ccTree(),
{ op: 'replace', target: 'cc-activity', type: 'bar-chart' }, ectx).tree;
const r = opsE.applyOperation(barred, { op: 'replace', target: 'cc-activity', type: 'line-chart' }, ectx);
const after = r.ok ? nodeE.findNode(r.tree, 'cc-activity') : null;
return { pass: r.ok && after.type === 'line-chart'
&& after.data.series === 'control-center.hiring-activity',
detail: JSON.stringify(r.problems).slice(0, 140) };
})().pass);
record('built-in: a stored patch replays the change from cold', (() => {
const patch = { ops: [{ op: 'replace', target: 'cc-activity', type: 'bar-chart' }] };
const round = JSON.parse(JSON.stringify(patch));
const out = compE.composePage('control-center', { patch: round, ...ectx });
const after = out.tree.find((n) => n.id === 'cc-activity');
return { pass: after?.type === 'bar-chart' && out.skipped.length === 0,
detail: `${after?.type} · skipped ${out.skipped.length}` };
})().pass);
record('built-in: a stored patch that became untrue is refused on load', (() => {
const patch = { ops: [{ op: 'replace', target: 'cc-activity', type: 'pie-chart' }] };
const out = compE.composePage('control-center', { patch, ...ectx });
const after = out.tree.find((n) => n.id === 'cc-activity');
return { pass: after?.type === 'cc-activity' && out.skipped.length === 1,
detail: `${after?.type} · skipped ${out.skipped.length}` };
})().pass);
}
/* ── Continuity, controls, and knowing what a reading means ───────────
*
* The four gaps the live verification found, each as the smallest test
* that would have caught it.
*/
{
const seriesE = await server.ssrLoadModule('/src/lib/ui/series.js');
const ccTree = () => compE.composePage('control-center', ectx).tree;
const barred = () => opsE.applyOperation(ccTree(),
{ op: 'replace', target: 'cc-activity', type: 'bar-chart' }, ectx).tree;
const ask = (q, opts = {}) => intentE.matchUiEdit(q,
{ tree: ccTree(), registry: nreg, page: 'control-center', ...opts });
/* ── A. "Change it back to a line chart." ─────────────────────────── */
record('continuity: a replaced node keeps the name of what it reads', (() => {
const node = inspectE.inspectTree(barred(), ectx).find((n) => n.id === 'cc-activity');
return { pass: node?.type === 'bar-chart' && node?.title === 'Hiring activity',
detail: `${node?.type} · ${node?.title}` };
})().pass);
record('continuity: it is still addressable by that name after replacement', (() => {
const m = intentE.matchUiEdit('Change Hiring activity to a line chart',
{ tree: barred(), registry: nreg, page: 'control-center' });
return { pass: m?.kind === 'plan' && m.op.target === 'cc-activity' && m.op.type === 'line-chart',
detail: `${m?.kind}: ${JSON.stringify(m?.op)}` };
})().pass);
record('continuity: "change it back to a line chart" resolves to what was changed', (() => {
const m = intentE.matchUiEdit('Change it back to a line chart',
{ tree: barred(), registry: nreg, page: 'control-center', focus: 'cc-activity' });
return { pass: m?.kind === 'plan' && m.op.op === 'replace'
&& m.op.target === 'cc-activity' && m.op.type === 'line-chart',
detail: `${m?.kind}: ${JSON.stringify(m?.op)}` };
})().pass);
record('continuity: the same sentence with no subject is still unknown', (() => {
const m = intentE.matchUiEdit('Change it back to a line chart',
{ tree: barred(), registry: nreg, page: 'control-center' });
return { pass: m?.kind === 'unknown', detail: String(m?.kind) };
})().pass);
record('continuity: a request that names something else is never redirected', (() => {
/* Focus is a last resort, not a preference: the words still win. */
const m = intentE.matchUiEdit('Hide the pipeline intelligence',
{ tree: ccTree(), registry: nreg, page: 'control-center', focus: 'cc-activity' });
return { pass: m?.kind === 'plan' && m.op.target === 'cc-pipeline',
detail: JSON.stringify(m?.op) };
})().pass);
record('continuity: a focus that has left the page resolves to nothing', (() => {
const m = intentE.matchUiEdit('Change it back to a line chart',
{ tree: barred(), registry: nreg, page: 'control-center', focus: 'no-such-node' });
return { pass: m?.kind === 'unknown', detail: String(m?.kind) };
})().pass);
record('continuity: a phrase with no pronoun does not reach for the focus', (() => {
const m = intentE.matchUiEdit('Change the audit log to a table',
{ tree: ccTree(), registry: nreg, page: 'control-center', focus: 'cc-activity' });
return { pass: m?.kind !== 'plan' || m.op.target !== 'cc-activity', detail: String(m?.kind) };
})().pass);
record('continuity: the data is untouched across bar → it → line', (() => {
const rows = [{ label: '9/1', applications: 4, screened: 2, interviews: 1, hires: 1 }];
const read = (tree) => seriesE.readSeries(tree.find((n) => n.id === 'cc-activity').data,
{ context: { activitySeries: rows } });
const before = read(ccTree());
const asBar = read(barred());
const m = intentE.matchUiEdit('Change it back to a line chart',
{ tree: barred(), registry: nreg, page: 'control-center', focus: 'cc-activity' });
const asLine = read(opsE.applyOperation(barred(), m.op, ectx).tree);
const same = JSON.stringify(before.rows) === JSON.stringify(asBar.rows)
&& JSON.stringify(asBar.rows) === JSON.stringify(asLine.rows);
return { pass: same && before.rows.length === 1 && before.rows[0].applications === 4,
detail: JSON.stringify(asLine.rows) };
})().pass);
/* ── B. The control survives the replacement ──────────────────────── */
record('control: the reading publishes the range, not the component', (() => {
const entry = seriesE.seriesFor('control-center.hiring-activity');
const values = (entry?.control?.options || []).map((o) => o.value);
return { pass: JSON.stringify(values) === JSON.stringify(['7d', '30d', '90d']),
detail: values.join(', ') || 'none' };
})().pass);
for (const type of ['bar-chart', 'line-chart', 'area-chart']) {
record(`control: 7D/30D/90D is still there after becoming a ${type}`, (() => {
const tree = opsE.applyOperation(ccTree(),
{ op: 'replace', target: 'cc-activity', type }, ectx).tree;
const node = tree.find((n) => n.id === 'cc-activity');
const control = seriesE.controlOfBinding(node.data, { range: '30d', setRange: () => {} });
return { pass: Boolean(control) && control.value === '30d'
&& control.options.length === 3 && control.label.length > 0,
detail: control ? `${control.label} · ${control.options.map((o) => o.label).join('/')}` : 'lost' };
})().pass);
}
record('control: choosing a range calls the page back, and nothing else', (() => {
const seen = [];
const control = seriesE.controlOfBinding({ series: 'control-center.hiring-activity' },
{ range: '7d', setRange: (v) => seen.push(v) });
control.set('90d');
return { pass: seen.length === 1 && seen[0] === '90d', detail: seen.join(',') };
})().pass);
record('control: none is invented when the page publishes none', (() => {
const control = seriesE.controlOfBinding({ series: 'control-center.hiring-activity' }, {});
return { pass: control === null, detail: JSON.stringify(control) };
})().pass);
record('control: a reading that declares none has none', (() => {
const control = seriesE.controlOfBinding({ source: 'candidates.activity' }, { range: '7d' });
return { pass: control === null, detail: JSON.stringify(control) };
})().pass);
record('control: a control with no option is refused at registration', (() => {
try {
seriesE.registerSeries({ id: 'x.control', kind: 'parts', measures: [{ key: 'a', label: 'A' }],
read: () => [], control: { id: 'r', options: [], read: () => null, write: () => {} } });
return false;
} catch (e) { return /at least one option/i.test(e.message); }
})());
record('control: a control with no writer is refused at registration', (() => {
try {
seriesE.registerSeries({ id: 'x.control2', kind: 'parts', measures: [{ key: 'a', label: 'A' }],
read: () => [], control: { id: 'r', options: [{ value: 'a', label: 'A' }], read: () => null } });
return false;
} catch (e) { return /needs a `read` and a `write`/i.test(e.message); }
})());
record('replace: identity, binding, origin and visibility all survive', (() => {
const before = ccTree().find((n) => n.id === 'cc-activity');
const after = barred().find((n) => n.id === 'cc-activity');
return { pass: after.id === before.id && after.origin === before.origin
&& Boolean(after.hidden) === Boolean(before.hidden)
&& JSON.stringify(after.data) === JSON.stringify(before.data),
detail: JSON.stringify({ id: after.id, origin: after.origin, data: after.data }) };
})().pass);
/* ── C. Asking for alternatives, in the words people use ──────────── */
for (const phrase of [
"I don't like this design. Show me other options.",
'Can you give me another visualization?',
'What else can I use?',
'Give me some alternatives.',
'I want a different chart.',
]) {
record(`alternatives: "${phrase.slice(0, 40)}…" is answered without a model`, (() => {
/* `matchUiEdit` is a pure function of the tree and the registry: there
is no provider to reach and nothing to await, so an answer here is
an answer with zero model calls by construction. */
const m = ask(phrase, { focus: 'cc-activity' });
const types = (m?.options || []).map((o) => o.type);
return { pass: m?.kind === 'options' && types.length > 0
&& types.every((t) => Boolean(nreg.get(t))),
detail: `${m?.kind}: ${types.join(', ') || '—'}` };
})().pass);
}
record('alternatives: the answer is the registry\u2019s, and excludes the untrue', (() => {
const m = ask('Show me other options.', { focus: 'cc-activity' });
const types = (m?.options || []).map((o) => o.type);
return { pass: types.includes('bar-chart') && types.includes('area-chart')
&& !types.includes('pie-chart') && !types.includes('donut-chart'),
detail: types.join(', ') };
})().pass);
record('alternatives: every one offered is one replace would accept', (() => {
const m = ask('I want a different chart.', { focus: 'cc-activity' });
const bad = (m?.options || []).filter((o) => (
!opsE.applyOperation(ccTree(), { op: 'replace', target: 'cc-activity', type: o.type }, ectx).ok
));
return { pass: (m?.options || []).length > 0 && bad.length === 0,
detail: bad.map((o) => o.type).join(', ') || 'none' };
})().pass);
record('alternatives: an ordinary question is still left alone', (() => {
const left = [
'What are my options for this position?',
'What other candidates applied?',
'Give me an alternative candidate',
'Show me another worker for Friday',
'Is there a different applicant for this shift?',
].filter((q) => ask(q, { focus: 'cc-activity' }) !== null);
return { pass: left.length === 0, detail: left.join(' | ') || 'none taken' };
})().pass);
/* ── D. Meaning that was never established ────────────────────────── */
record('meaning: a reading that declares one is believed', (() => {
const declared = ['position.activity', 'candidates.activity', 'position.pipeline',
'candidates.pipeline', 'activity.breakdown']
.map((id) => [id, seriesE.kindOfBinding({ source: id })]);
const bad = declared.filter(([, kind]) => !nodeE.SERIES_KINDS.includes(kind));
return { pass: bad.length === 0, detail: declared.map(([i, k]) => `${i}=${k}`).join(' ') };
})().pass);
record('meaning: every declared kind is one of the closed three', (() => {
const bad = surfaces.DATA_SOURCES
.filter((source) => source.series != null)
.filter((source) => !nodeE.SERIES_KINDS.includes(source.series));
return { pass: bad.length === 0, detail: bad.map((s) => `${s.id}=${s.series}`).join(', ') || 'all known' };
})().pass);
record('meaning: a reading that declares none is refused rather than guessed', (() => {
const node = nodeE.makeNode({ id: 'viz', type: 'card', origin: 'user',
data: { source: 'hires.performance' } });
const m = intentE.matchUiEdit('Change the Hiring performance card to a pie chart',
{ tree: [node], registry: nreg, page: 'analytics' });
return { pass: m?.kind === 'refused' && /does not say what its figures mean/i.test(m.message),
detail: `${m?.kind}: ${m?.message}` };
})().pass);
record('meaning: nor is it offered in the first place', (() => {
const node = nodeE.makeNode({ id: 'viz', type: 'card', origin: 'user',
data: { source: 'hires.performance' } });
const m = intentE.matchUiEdit('Show me other options for the card',
{ tree: [node], registry: nreg, page: 'analytics', focus: 'viz' });
const types = (m?.options || []).map((o) => o.type);
const charts = types.filter((t) => nreg.get(t).seriesKinds.length > 0);
return { pass: charts.length === 0, detail: types.join(', ') || 'nothing offered' };
})().pass);
record('meaning: a stored patch that never established one is refused on load', (() => {
const tree = [nodeE.makeNode({ id: 'viz', type: 'bar-chart', origin: 'user',
data: { source: 'hires.performance' } })];
const verdict = validateE.validateTree(tree, ectx);
return { pass: !verdict.ok, detail: JSON.stringify(verdict.problems).slice(0, 170) };
})().pass);
record('meaning: components that claim no meaning are untouched by the rule', (() => {
/* The Card → Table path, which says nothing about what its rows mean
and must keep working exactly as it did. */
const node = nodeE.makeNode({ id: 'viz', type: 'card', origin: 'user',
props: { title: 'Recent hires' }, data: { source: 'hires.recent' } });
const r = opsE.applyOperation([node], { op: 'replace', target: 'viz', type: 'table' }, ectx);
const after = r.ok ? nodeE.findNode(r.tree, 'viz') : null;
return { pass: r.ok && after.type === 'table' && after.data.source === 'hires.recent'
&& after.props.title === 'Recent hires',
detail: JSON.stringify(r.problems).slice(0, 150) };
})().pass);
}
/* ── Asking for the alternatives ──────────────────────────────────────
*
* The request that most invites a model to invent something. Every answer
* here is the registry's, and it is the same list the replace path checks
* a single name against.
*/
{
const ccTree = () => compE.composePage('control-center', ectx).tree;
const ask = (q) => intentE.matchUiEdit(q, { tree: ccTree(), registry: nreg, page: 'control-center' });
for (const phrase of [
'Show me other options for the Hiring activity',
'I do not like this design, show me other designs for Hiring activity',
'What else could the Hiring activity be',
'Give me alternatives for the Hiring activity',
]) {
record(`options: "${phrase.slice(0, 44)}…" is answered from the registry`, (() => {
const m = ask(phrase);
const types = (m?.options || []).map((o) => o.type);
return { pass: m?.kind === 'options' && types.length > 0
&& types.every((t) => Boolean(nreg.get(t)))
&& !types.includes('pie-chart'),
detail: `${m?.kind}: ${types.join(', ')}` };
})().pass);
}
record('options: at most four are offered', (() => {
const m = ask('Show me other options for the Hiring activity');
return { pass: (m?.options || []).length <= 4, detail: String(m?.options?.length) };
})().pass);
record('options: every option is one replace would accept', (() => {
const m = ask('Show me other options for the Hiring activity');
const bad = (m?.options || []).filter((o) => (
!opsE.applyOperation(ccTree(), { op: 'replace', target: 'cc-activity', type: o.type }, ectx).ok
));
return { pass: bad.length === 0, detail: bad.map((o) => o.type).join(', ') || 'none' };
})().pass);
record('options: an ordinary question about options is left alone', (() => {
const left = ['What are my options for this position?', 'Show me the candidates',
'What other candidates applied?', 'Give me an alternative candidate']
.filter((q) => ask(q) !== null);
return { pass: left.length === 0, detail: left.join(' | ') || 'none taken' };
})().pass);
record('options: a refusal offers the alternatives', (() => {
const m = ask('Change Hiring activity to a pie chart');
const labels = (m?.alternatives || []).map((a) => a.type);
return { pass: m?.kind === 'refused' && /ordered in time/i.test(m.message)
&& labels.includes('bar-chart') && !labels.includes('pie-chart'),
detail: `${m?.message} → ${labels.join(', ')}` };
})().pass);
}
/* ── Safety ───────────────────────────────────────────────────────────
*
* Nothing a person can type produces markup, a class name or a component.
*/
{
const ccTree = () => compE.composePage('control-center', ectx).tree;
const ask = (q) => intentE.matchUiEdit(q, { tree: ccTree(), registry: nreg, page: 'control-center' });
record('safety: an invented visualization type is refused, not improvised', (() => {
const m = ask('Turn the Hiring activity into a neon 3D holographic chart');
const planned = m?.kind === 'plan';
return { pass: !planned, detail: `${m?.kind}` };
})().pass);
record('safety: an unregistered type never reaches the tree', (() => {
const r = opsE.applyOperation(ccTree(),
{ op: 'replace', target: 'cc-activity', type: 'holograph' }, ectx);
return { pass: !r.ok && /Unsupported UI type/i.test(JSON.stringify(r.problems)),
detail: JSON.stringify(r.problems).slice(0, 120) };
})().pass);
record('safety: a request for custom CSS produces no operation', (() => {
const bad = ['Give this card some custom CSS', 'Add class bg-red-500 to the Hiring activity',
'Set the style of the Hiring activity to display:none',
'Inject <script>alert(1)</script> into the Hiring activity']
.filter((q) => ask(q)?.kind === 'plan');
return { pass: bad.length === 0, detail: bad.join(' | ') || 'none planned' };
})().pass);
record('safety: a class name in props is dropped by the schema', (() => {
const r = opsE.applyOperation(
[seriesNode('bar-chart', 'hires.performance')],
{ op: 'update', target: 'viz', props: { className: 'bg-red-500', style: 'color:red' } },
ectx
);
const props = r.ok ? nodeE.findNode(r.tree, 'viz').props : null;
return { pass: !r.ok || (!('className' in props) && !('style' in props)),
detail: JSON.stringify(props) };
})().pass);
record('safety: an ambiguous request asks rather than guesses', (() => {
const m = ask('Change this');
return { pass: m === null || m.kind === 'ambiguous' || m.kind === 'unknown'
|| m.kind === 'unknown-type' || m.kind === 'refused',
detail: String(m?.kind) };
})().pass);
}
if (!hadWindow) delete globalThis.window;
}
}