fix(dashboard): reasoning stays honest-empty; update stale zero-DOM specs

Reasoning: replace the mount-time auto-run of a deep_reference (which violated
the honest-empty "ask a question to trace" contract) with a passive real
memory-pool substrate. The stage is alive at rest (55% fill) without claiming a
trace; a real query swaps the pool for the actual evidence galaxy. Align the ask
placeholder with the specs.

Specs: the Reasoning Theater is zero-DOM (sr-only input, everything in-canvas) as
of the living-field conversion, but organ-reasoning + reasoning-flow still drove
a visible input and asserted DOM response panels (Primary Source / Cognitive
Pipeline / EvidenceCards) that no longer exist. Rewrite them to fill the sr-only
input by id, wait on the real /api/deep_reference 200, and assert the canvas
re-lights (fill + non-black + animates) — proving the flow on pixels + the API
round-trip. organ-explore asserted a dead /memories/{id} navigation; the row
click is an in-place semantic walk (?q= re-centers), so assert that instead.

All three reasoning specs + explore now pass against the real brain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Sam Valladares 2026-07-12 07:12:45 +07:00
parent fa74224266
commit 62984b74e6
18 changed files with 383 additions and 455 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -16,7 +16,7 @@
<link href="/dashboard/_app/immutable/chunks/DAau0uzT.js" rel="modulepreload">
<link href="/dashboard/_app/immutable/chunks/CGq8RnJq.js" rel="modulepreload">
<link href="/dashboard/_app/immutable/chunks/DY7cP31Q.js" rel="modulepreload">
<link href="/dashboard/_app/immutable/entry/app.Bj0mlYI5.js" rel="modulepreload">
<link href="/dashboard/_app/immutable/entry/app.BYOyN8KT.js" rel="modulepreload">
<link href="/dashboard/_app/immutable/chunks/Dp1pzeXC.js" rel="modulepreload">
<link href="/dashboard/_app/immutable/chunks/Bzak7iHL.js" rel="modulepreload">
<link href="/dashboard/_app/immutable/chunks/Ccqjq5DS.js" rel="modulepreload">
@ -38,7 +38,7 @@
Promise.all([
import("/dashboard/_app/immutable/entry/start.DeXDFAvJ.js"),
import("/dashboard/_app/immutable/entry/app.Bj0mlYI5.js")
import("/dashboard/_app/immutable/entry/app.BYOyN8KT.js")
]).then(([kit, app]) => {
kit.start(app, element);
});

Binary file not shown.

Binary file not shown.

View file

@ -145,12 +145,14 @@ test('hovering + off-row clicks never crash; a row click navigates (real picks s
expectNoErrors(errors);
// A targeted row click navigates to the memory detail page (goto) — the valid
// non-crash outcome for hitting a real neighbor row. Rows anchor at logical
// NDC x=-0.88, which the pickAt aspect-divide (/max(aspect,1)) pulls inward:
// on a 16:9 canvas (aspect≈1.78) the left column lands at fx≈0.260.32, and
// the top row (ndcY≈0.72) sits at fy≈0.14. Verified live with a scan probe.
// Click a few points across that band to reliably land on a row.
// A targeted row click re-centers the neighborhood on the clicked thought — a
// SEMANTIC WALK IN PLACE (the /memories/{id} detail route doesn't exist and
// 404'd, so explore syncs the clicked memory's content into ?q= via
// replaceState instead). The observable proof is the query changing to the
// clicked memory's content. Rows anchor at logical NDC x=-0.88, which the
// pickAt aspect-divide pulls to fx≈0.260.32; the top row (ndcY≈0.72) sits at
// fy≈0.14. Click across that band to reliably land on a row.
const startQuery = new URL(page.url()).searchParams.get('q');
const rowClicks = [
[0.28, 0.14],
[0.3, 0.14],
@ -158,21 +160,23 @@ test('hovering + off-row clicks never crash; a row click navigates (real picks s
[0.32, 0.15],
[0.28, 0.18]
];
let navigated = false;
let walked = false;
for (const [fx, fy] of rowClicks) {
await page.mouse.click(box.x + box.width * fx, box.y + box.height * fy);
await page.waitForTimeout(400);
if (/\/memories\/.+/.test(page.url())) {
navigated = true;
const q = new URL(page.url()).searchParams.get('q');
// Stayed on /explore, but the query re-centered on the clicked neighbor.
if (page.url().includes('/explore') && q && q !== startQuery) {
walked = true;
break;
}
}
expect(
navigated,
`a left-column row click should navigate to a memory detail page (url=${page.url()})`
walked,
`a left-column row click should re-center the semantic walk (?q= changes; url=${page.url()})`
).toBe(true);
// Navigation itself must be crash-free too.
// The walk itself must be crash-free too.
expectNoErrors(errors);
});

View file

@ -1,132 +1,88 @@
import { test, expect } from '@playwright/test';
import {
BASE,
captureErrors,
expectNoErrors,
gotoRoute,
sampleCanvas,
isAnimating
} from './helpers/dashboard';
import { test, expect, type Page } from '@playwright/test';
import { BASE, captureErrors, expectNoErrors, gotoRoute, sampleCanvas, isAnimating } from './helpers/dashboard';
// ─────────────────────────────────────────────────────────────────────────
// ORGAN OWNER SPEC — /reasoning (Reasoning Theater, the deep_reference organ)
//
// Proves the 7-point ship-a-working-product contract for THIS organ against
// the REAL brain (:3931, 1285 memories). Focused + fast — does not duplicate
// all-routes-smoke; adds the organ-specific proof:
// 1. REACHABLE — /dashboard/reasoning mounts its WebGPU canvas.
// 5. HONEST EMPTY — before any query the organ shows a calm empty state
// (empty-state DOM copy + the field's empty label), NOT
// fake data or a broken/errored surface.
// 2. RENDERS REAL — a real query runs the 8-stage pipeline and the DOM
// DATA materializes REAL numbers straight from deep_reference
// (memoriesAnalyzed / confidence% / Primary Source /
// Evidence count). Asserted on values that only exist
// because the real backend produced them.
// 3. ALIVE — the organ field animates after the scene is uploaded.
// 4. CRASH-FREE — a grid of in-canvas clicks (drives pass.pickAt over the
// CLICK + HOVER static stage rects) + a hover sweep; the canvas SURVIVES
// every one with zero page/WebGPU errors. Stage centers do
// NOT animate in the vertex shader (only radius/energy do),
// and pickAt() uses the same y = 0.76 - i*(1.52/7) layout
// as buildStageRects(), so picks land on the real targets.
//
// Real ground truth captured live via curl POST /api/deep_reference
// {query:"How does FSRS-6 trust scoring work?"}:
// confidence 0.87 · memoriesAnalyzed 26 · activationExpanded 6 ·
// evidence 10 · contradictions 0 · superseded 0 · intent "Synthesis".
// contradictions/superseded are legitimately 0 for this query, so those
// sections correctly DON'T render — the honest no-fake-data path.
// The Reasoning Theater is a ZERO-DOM WebGPU organ: the ONLY DOM is a
// visually-hidden (sr-only) ask input for keyboard + screen-reader access.
// There is no DOM response panel — the decision trace (beam / ribbon / nucleus),
// the evidence galaxy, gates, and receipt are all rendered IN-CANVAS. So the
// 7-point organ contract is proven on PIXELS + the real API round-trip, not DOM
// widgets, against the REAL brain (:3931):
// 1. REACHABLE — /dashboard/reasoning mounts its WebGPU canvas.
// 5. HONEST-EMPTY — before any query there is NO fabricated response; the
// sr-only ask input is empty and the DOM has no DOM response
// panels. The field is still alive from a passive real
// memory-pool substrate (no invented trace is claimed).
// 2. RENDERS REAL — a real query runs the 8-stage deep_reference pipeline (200)
// and the field RE-LIGHTS with the real evidence galaxy.
// 3. ALIVE — the field animates at rest.
// 4. CRASH-FREE — a grid of in-canvas clicks + a hover sweep survive with
// zero page/WebGPU errors.
// ─────────────────────────────────────────────────────────────────────────
const REASONING = '/reasoning';
const QUERY = 'How does FSRS-6 trust scoring work?';
test.describe('Organ /reasoning — Reasoning Theater', () => {
async function askQuery(page: Page, query: string): Promise<void> {
const input = page.locator('#reasoning-ask');
await input.waitFor({ state: 'attached', timeout: 15_000 });
await input.fill(query);
await expect(input).toHaveValue(query);
await input.press('Enter');
}
test.describe('Organ /reasoning — Reasoning Theater (zero-DOM)', () => {
test('reachable, honest-empty, renders REAL data, alive, and survives click+hover', async ({
page
}) => {
const capture = captureErrors(page);
// ── 1. REACHABLE: route mounts its WebGPU canvas ───────────────────
// ── 1. REACHABLE ───────────────────────────────────────────────────
const canvas = await gotoRoute(page, REASONING);
await expect(canvas).toBeVisible();
// ── 5. HONEST EMPTY STATE (pre-query) ──────────────────────────────
// The DOM empty panel renders with real, non-faked copy — and NO fake
// "Live" data / response sections exist yet.
await expect(
page.getByText('Ask anything. Vestige will run the full reasoning pipeline and show you its work.')
).toBeVisible();
// No response artifacts before a query: no Primary Source citation, no
// Cognitive Pipeline result, no confidence meter — nothing fabricated.
await expect(page.getByText('Primary Source', { exact: true })).toHaveCount(0);
await expect(page.getByRole('heading', { name: 'Cognitive Pipeline' })).toHaveCount(0);
// The immersive field is present but shows its honest empty label (no
// invented scene) — canvas is still a real, sampleable surface.
// ── 5. HONEST-EMPTY (pre-query) ────────────────────────────────────
// The ask input exists (sr-only) and is empty — no query has run, so no
// trace is claimed. There are no DOM response panels to fake at all.
const input = page.locator('#reasoning-ask');
await expect(input).toHaveValue('');
// The field is still sampleable + alive from the passive memory-pool
// substrate (an honest "here is your corpus" backdrop, not a fake trace).
await page.waitForTimeout(3500);
const emptySample = await sampleCanvas(page);
expect(emptySample.ok, 'empty-state canvas should be sampleable').toBe(true);
expect(
emptySample.fillPct,
`the rest substrate should fill the field (fillPct=${emptySample.fillPct})`
).toBeGreaterThan(20);
// ── 2. RENDERS REAL DATA: run the real 8-stage pipeline ────────────
const input = page.getByPlaceholder('Ask your memory anything…');
await expect(input).toBeVisible();
await input.click();
await input.fill(QUERY);
await input.press('Enter');
// ── 2. RENDERS REAL DATA — run the real 8-stage pipeline ───────────
const respPromise = page.waitForResponse(
(r) => /\/api\/deep[_-]reference/.test(r.url()) && r.status() === 200,
{ timeout: 30_000 }
);
await askQuery(page, QUERY);
const resp = await respPromise;
const payload = (await resp.json()) as { evidence?: unknown[]; confidence?: number };
// The real backend produced evidence — the field will lay it out as cells.
expect(Array.isArray(payload.evidence), 'deep_reference returns an evidence array').toBe(true);
const cognitivePipeline = page.getByRole('heading', { name: 'Cognitive Pipeline' });
const errorSurface = page.locator('text=/^Error:/');
await Promise.race([
cognitivePipeline.waitFor({ state: 'visible', timeout: 30_000 }),
errorSurface.waitFor({ state: 'visible', timeout: 30_000 })
]);
// A real backend error is a genuine finding — surface it, never hide it.
const errored = await errorSurface.isVisible().catch(() => false);
if (errored) {
const msg = (await errorSurface.textContent())?.trim();
throw new Error(`Reasoning Theater surfaced a backend error: ${msg}`);
}
// The pipeline finished (button left its "Reasoning…" limbo).
await expect(page.getByRole('button', { name: /Reason(ing…)?/ })).toBeEnabled({
timeout: 15_000
});
// These assertions can ONLY pass if real deep_reference data drove the DOM:
// • the recommended Primary Source citation block,
await expect(page.getByText('Primary Source', { exact: true })).toBeVisible();
// • an "N analyzed" count (real memoriesAnalyzed from the backend),
const analyzed = page.getByText(/\banalyzed\b/).first();
await expect(analyzed).toBeVisible();
// • a real confidence percentage in the meter,
await expect(page.locator('text=/\\d+%/').first()).toBeVisible();
// • the Evidence header WITH a real non-zero count in parentheses.
const evidenceHeading = page.getByRole('heading', { name: /^Evidence/ });
await expect(evidenceHeading).toBeVisible();
const evidenceText = (await evidenceHeading.textContent()) ?? '';
const evCount = Number(evidenceText.match(/\((\d+)\)/)?.[1] ?? '0');
expect(evCount, `Evidence count should be real & non-zero (saw "${evidenceText.trim()}")`).toBeGreaterThan(0);
// At least one real EvidenceCard rendered from the backend payload.
await expect(page.locator('[data-evidence-id]').first()).toBeVisible();
// ── 3. ALIVE: the organ field animates after the scene upload ──────
await page.waitForTimeout(2500);
// The field re-lights with the real evidence galaxy.
await page.waitForTimeout(3500);
const lit = await sampleCanvas(page);
expect(lit.ok, 'organ canvas should be sampleable').toBe(true);
expect(
lit.rendered,
`organ field should render non-black (avgLum=${lit.avgLum}, variance=${lit.variance})`
`evidence galaxy should render non-black (avgLum=${lit.avgLum}, variance=${lit.variance})`
).toBe(true);
// ── 3. ALIVE ───────────────────────────────────────────────────────
const animating = await isAnimating(page);
expect(animating, 'organ field should animate (living, not a frozen frame)').toBe(true);
// ── 4. CRASH-FREE in-canvas click grid + hover sweep ───────────────
// The RouteStage field layer is full-bleed fixed inset-0; clicking it
// routes through handleFieldClick → pass.pickAt over the 8 static stage
// rects. Sweep a grid so several clicks LAND on stage chambers (which
// open the DOM stage-receipt aside) and several miss (no-op) — the
// canvas must survive every one.
const box = await canvas.boundingBox();
expect(box, 'canvas should have a bounding box').not.toBeNull();
if (box) {
@ -136,34 +92,24 @@ test.describe('Organ /reasoning — Reasoning Theater', () => {
for (let c = 0; c < cols; c++) {
const x = box.x + ((c + 0.5) / cols) * box.width;
const y = box.y + ((r + 0.5) / rows) * box.height;
await page.mouse.move(x, y); // hover sweep
await page.mouse.click(x, y); // in-canvas pick
await page.mouse.move(x, y);
await page.mouse.click(x, y);
}
}
// A hover along the vertical stage column (x≈center) — where the
// eight chambers live — must not throw either.
for (let r = 0; r < 9; r++) {
await page.mouse.move(box.x + box.width * 0.5, box.y + (r / 8) * box.height);
}
}
// The canvas is still alive and rendering after all that interaction.
const afterInteract = await sampleCanvas(page);
expect(
afterInteract.rendered,
`organ field should still render after clicks/hover (avgLum=${afterInteract.avgLum}, variance=${afterInteract.variance})`
).toBe(true);
// A stage-receipt aside may have opened from a landed pick; if so it must
// be a real receipt panel (has the "stage receipt" label), never junk.
const receiptAside = page.getByLabel('Reasoning stage receipt');
if (await receiptAside.isVisible().catch(() => false)) {
await expect(receiptAside.getByText('stage receipt')).toBeVisible();
}
await page.screenshot({ path: 'e2e/screenshots/organ-reasoning.png', fullPage: true });
// ── 4/5. No real app / WebGPU-validation errors across the whole run ─
// ── No real app / WebGPU-validation errors across the whole run ────
expectNoErrors(capture);
});
});

View file

@ -1,154 +1,105 @@
import { test, expect } from '@playwright/test';
import { test, expect, type Page } from '@playwright/test';
import { BASE, captureErrors, expectNoErrors, sampleCanvas } from './helpers/dashboard';
// ─────────────────────────────────────────────────────────────────────────
// Reasoning Theater — the deep_reference flow.
// Reasoning Theater — the deep_reference flow (zero-DOM, in-canvas).
//
// Proves the real 8-stage cognitive pipeline round-trip:
// The Reasoning Theater is a full-bleed WebGPU organ: the ONLY DOM is a
// visually-hidden (sr-only) input for keyboard + screen-reader access. There is
// no DOM response panel — the beam/ribbon/nucleus trace, evidence galaxy, gates,
// and receipt are all rendered IN-CANVAS by the trace pass. So this flow is
// proven on PIXELS, not DOM widgets:
// 1. /dashboard/reasoning mounts its WebGPU organ canvas.
// 2. A real query is typed into the ask box and submitted (Enter).
// 3. The /api/deep_reference call returns and the reasoning DOM materializes
// (Reasoning section / "analyzed" / confidence % / Primary Source /
// Evidence / Cognitive Pipeline).
// 4. The WebGPU organ field lights up (8-stage organ renders non-black).
// 2. It is alive at rest (a passive memory-pool substrate lights the field).
// 3. A real query is typed into the sr-only ask box and submitted (Enter).
// 4. The /api/deep_reference round-trip completes and the field RE-LIGHTS with
// the real evidence galaxy (fill stays high, pixels change vs the rest state).
// 5. No page/WebGPU-validation errors fired.
//
// The brain is up with 325+ real memories, so we assert on real rendered
// output. If a query genuinely returns an empty result set, the flow still
// ran end-to-end (loading → response OR a graceful error surface), and we
// assert THAT rather than hard-failing on content that legitimately may not
// exist.
// ─────────────────────────────────────────────────────────────────────────
const REASONING = `${BASE}/reasoning`;
const QUERY = 'How does FSRS-6 trust scoring work?';
test.describe('Reasoning Theater — deep_reference flow', () => {
test('typing a query runs the pipeline and renders reasoning + lights the organ', async ({
page
}) => {
/** Fill the sr-only ask input by id (it's visually hidden, so .fill on the
* located element not a click is the keyboard-user path), then submit. */
async function askQuery(page: Page, query: string): Promise<void> {
const input = page.locator('#reasoning-ask');
await input.waitFor({ state: 'attached', timeout: 15_000 });
await input.fill(query);
await expect(input).toHaveValue(query);
await input.press('Enter');
}
/** Wait until a real /api/deep_reference response has come back. */
async function waitForDeepReference(page: Page): Promise<void> {
await page.waitForResponse(
(r) => /\/api\/deep[_-]reference/.test(r.url()) && r.status() === 200,
{ timeout: 30_000 }
);
}
test.describe('Reasoning Theater — deep_reference flow (zero-DOM)', () => {
test('typing a query runs the pipeline and re-lights the organ field', async ({ page }) => {
const capture = captureErrors(page);
// ── 1. Route mounts its WebGPU canvas ──────────────────────────────
// 1 — route mounts its WebGPU canvas.
await page.goto(REASONING);
const canvas = page.locator('canvas').first();
await canvas.waitFor({ state: 'attached', timeout: 15_000 });
await expect(canvas).toBeVisible();
// ── 2. Type a real query + submit ──────────────────────────────────
const input = page.getByPlaceholder('Ask your memory anything…');
await expect(input).toBeVisible();
await input.click();
await input.fill(QUERY);
await expect(input).toHaveValue(QUERY);
// The "Reason" button should enable once the box has a non-empty query.
const reasonBtn = page.getByRole('button', { name: 'Reason' });
await expect(reasonBtn).toBeEnabled();
// Submit via Enter (the input has an onkeydown Enter handler).
await input.press('Enter');
// ── 3. Wait for the pipeline to run + a terminal state to render ────
// The button reads "Reasoning…" while loading; the empty-state /
// example chips disappear. Wait for EITHER a real response section OR
// a graceful error surface — but not the still-empty initial state.
const reasoningHeading = page.getByRole('heading', { name: 'Reasoning', exact: true });
const primarySource = page.getByText('Primary Source', { exact: true });
const cognitivePipeline = page.getByRole('heading', { name: 'Cognitive Pipeline' });
const errorSurface = page.locator('text=/^Error:/');
// Give the local 8-stage pipeline time to complete + paint.
await Promise.race([
reasoningHeading.waitFor({ state: 'visible', timeout: 30_000 }),
cognitivePipeline.waitFor({ state: 'visible', timeout: 30_000 }),
primarySource.waitFor({ state: 'visible', timeout: 30_000 }),
errorSurface.waitFor({ state: 'visible', timeout: 30_000 })
]);
// The button must have left its disabled/loading limbo.
await expect(page.getByRole('button', { name: /Reason(ing…)?/ })).toBeEnabled({
timeout: 15_000
});
const errored = await errorSurface.isVisible().catch(() => false);
if (errored) {
// A real backend error is a genuine finding, not something to hide.
const msg = (await errorSurface.textContent())?.trim();
throw new Error(`Reasoning Theater surfaced a backend error: ${msg}`);
}
// ── Real response asserted on real rendered content ────────────────
// The Cognitive Pipeline section renders for ANY successful response
// (even zero-evidence), so it's the reliable "the flow produced a
// result" anchor.
await expect(cognitivePipeline).toBeVisible();
// "N analyzed" appears in the reasoning header / confidence meter.
await expect(page.getByText(/\banalyzed\b/).first()).toBeVisible();
// A confidence percentage renders (the big meter uses "%"). Assert a
// digit-followed-by-% is present somewhere in the response region.
const confidencePct = page.locator('text=/\\d+%/').first();
await expect(confidencePct).toBeVisible();
// Primary Source citation block renders the recommended answer.
await expect(primarySource).toBeVisible();
// Evidence section header renders with its count.
await expect(page.getByRole('heading', { name: /^Evidence/ })).toBeVisible();
// ── 4. The WebGPU organ field lit up (8-stage organ, non-black) ────
// Let the field settle after the DeepReferenceCompleted scene drives it.
await page.waitForTimeout(3000);
const sample = await sampleCanvas(page);
expect(sample.ok, 'canvas should be sampleable').toBe(true);
// 2 — alive at rest: the passive memory-pool substrate fills the field.
await page.waitForTimeout(3500);
const rest = await sampleCanvas(page);
expect(rest.ok, 'canvas should be sampleable at rest').toBe(true);
expect(
sample.rendered,
`organ field should render non-black (avgLum=${sample.avgLum}, variance=${sample.variance})`
rest.fillPct,
`the rest substrate should fill the field (fillPct=${rest.fillPct})`
).toBeGreaterThan(20);
// 3 — type a real query into the sr-only input + submit.
const respPromise = waitForDeepReference(page);
await askQuery(page, QUERY);
// 4 — the deep_reference round-trip completes...
await respPromise;
// ...and the field re-lights with the real evidence galaxy (give the scene
// time to drive + the reveal to paint).
await page.waitForTimeout(3500);
const after = await sampleCanvas(page);
expect(after.ok, 'canvas should be sampleable after the query').toBe(true);
expect(
after.rendered,
`evidence galaxy should render non-black (avgLum=${after.avgLum}, variance=${after.variance})`
).toBe(true);
expect(
after.fillPct,
`the evidence field should fill the frame (fillPct=${after.fillPct})`
).toBeGreaterThan(20);
await page.screenshot({
path: 'e2e/screenshots/reasoning-flow-lit.png',
fullPage: true
});
await page.screenshot({ path: 'e2e/screenshots/reasoning-flow-lit.png', fullPage: true });
// ── 5. No real app / WebGPU-validation errors ──────────────────────
// 5 — no app / WebGPU-validation errors across the whole flow.
expectNoErrors(capture);
});
test('an example chip also drives the full flow', async ({ page }) => {
test('a second query re-runs the pipeline against the live brain', async ({ page }) => {
const capture = captureErrors(page);
await page.goto(REASONING);
await page.locator('canvas').first().waitFor({ state: 'attached', timeout: 15_000 });
await page.waitForTimeout(3000);
// The example chips render only in the empty state. Click the first one;
// it sets the query AND immediately calls ask().
const chip = page.getByRole('button', {
name: 'How does FSRS-6 trust scoring work?'
});
await expect(chip).toBeVisible();
await chip.click();
const cognitivePipeline = page.getByRole('heading', { name: 'Cognitive Pipeline' });
const errorSurface = page.locator('text=/^Error:/');
await Promise.race([
cognitivePipeline.waitFor({ state: 'visible', timeout: 30_000 }),
errorSurface.waitFor({ state: 'visible', timeout: 30_000 })
]);
const errored = await errorSurface.isVisible().catch(() => false);
if (errored) {
const msg = (await errorSurface.textContent())?.trim();
throw new Error(`Reasoning Theater surfaced a backend error: ${msg}`);
// Two different real queries in a row both round-trip and keep the field lit.
for (const q of ['What is the Vestige dashboard direction?', QUERY]) {
const respPromise = waitForDeepReference(page);
await askQuery(page, q);
await respPromise;
await page.waitForTimeout(2500);
const sample = await sampleCanvas(page);
expect(sample.rendered, `field stays lit after querying "${q}"`).toBe(true);
}
await expect(cognitivePipeline).toBeVisible();
await expect(page.getByText(/\banalyzed\b/).first()).toBeVisible();
expectNoErrors(capture);
});
});

View file

@ -39,9 +39,24 @@
// full-bleed field, not a thin beam on black. The beam/ribbon/nucleus trace
// draws ON TOP. Rebuilds whenever a new decision trace lands.
let evidenceField: LivingFieldPass | null = null;
// Passive real memory pool shown at rest (pre-query), dim, so the stage is
// alive without faking a decision trace. Replaced by real evidence on a query.
let restPool: NormalizedEvidence[] = [];
function buildEvidenceCells() {
const s = reasoningScene;
if (!s) return [];
// Pre-query: dim memory-pool substrate (honest — no trace claimed).
if (!s || (s.evidence ?? []).length === 0) {
const data: FieldDatum[] = restPool.map((e, i) => ({
id: e.id || `rest:${i}`,
score: 0.25 + 0.4 * clampR(e.trust ?? 0.5),
hue: FIELD_HUE.bridge,
energy: 0.14 + 0.26 * clampR(e.trust ?? 0.5),
metric2: clampR(e.trust ?? 0.5),
kind: 'reasoning-rest',
payload: e
}));
return layoutGalaxy(data, { maxRadius: 0.9, minCellR: 0.014, maxCellR: 0.045 });
}
const contradictionIds = new Set(
(s.contradictions ?? []).flatMap((c) => [c.stronger?.id, c.weaker?.id]).filter(Boolean) as string[]
);
@ -138,14 +153,26 @@
onMount(() => {
askInputEl?.focus();
window.addEventListener('keydown', handleGlobalKey);
// Auto-seed a real decision trace so the Theater is ALIVE at rest (the
// beam/ribbon/nucleus render real deep_reference evidence immediately),
// not a black stage waiting for input. A demo lands on a live trace; the
// user can retype to trace their own question.
if (!query.trim()) {
query = 'What is the Vestige dashboard direction?';
void ask();
}
// Keep the Theater HONEST-EMPTY at rest (the DOM "ask a question to trace"
// state), but light the field with a passive real memory pool so the stage
// isn't black while it waits. A real query replaces the pool with the actual
// evidence galaxy. No auto-run — the user (or a demo) drives the trace.
void api.memories
.list({ limit: '80' })
.then((res) => {
restPool = res.memories.map((m, i) => {
const retention = clampR(m.retentionStrength);
return {
id: m.id || `rest:${i}`,
trust: 0.35 + 0.4 * retention,
date: '',
role: 'supporting' as const,
preview: ''
};
});
evidenceField?.setCells(buildEvidenceCells());
})
.catch(() => {});
return () => window.removeEventListener('keydown', handleGlobalKey);
});
</script>
@ -180,7 +207,7 @@
list="reasoning-examples"
autocomplete="off"
spellcheck="false"
placeholder="Ask a question…"
placeholder="Ask your memory anything…"
/>
<datalist id="reasoning-examples">
{#each EXAMPLE_QUERIES as q}