Files
confidence-engine/docs/v0.7-ui-mock-mode.md

13 KiB

v0.7 — Mock Investigation Mode for UI Development

Purpose

A local mock/demo mode lets you develop and test the Confidence Engine UI without running Ollama. It intercepts API calls at the frontend layer and replays pre-recorded scenario fixtures, producing identical response shapes whether real or mocked.

Quick Start

# Enable mock mode
export NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCKS=true

# Optional: choose a delay profile (default: normal = 700ms)
export NEXT_PUBLIC_CONFIDENCE_MOCK_DELAY=normal        # instant | normal | slow

# Optional: choose a scenario (default: complete = jumps to end after start)
export NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCK_SCENARIO=complete   # complete | error | ""

npm run dev

Navigate to the confidence-engine UI and enter any scenario text — the response will come from fixtures, not Ollama.

Environment Variables

Variable Required Values Default Description
NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCKS yes "true" or anything else disabled Enables mock mode when set to "true"
NEXT_PUBLIC_CONFIDENCE_MOCK_DELAY no "instant", "normal", "slow" "normal" (700ms) Simulated latency for realistic loading UX
NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCK_SCENARIO no "complete", "error", "" "" (sequential turns) Which scenario to replay

Scenarios

Default (Sequential Turns)

Replays 6 turns of the "Complaints + Production" investigation:

Turn What happens
0 Start — two observations, three unknown nodes. Question: "Were both percentages calculated from comparable baseline counts?"
1 User confirms same period → new observation added. Question: "Did the complaint rate per unit produced improve or worsen?"
2 User provides baselines (100→135 complaints, 1000→1400 production) → new observation. Question: "Was there any change in how complaints were recorded?"
3 User confirms rate improved (10/1000→9.6/1000) → new observation. Unknown u-4 resolved by process of elimination. no-question — needs more evidence.
4 (not reached in default — shown only when stepping past turn 3)
5 User confirms same reporting rules → final completion with full summary.

After the initial analysis is submitted, each update call advances to the next turn. In "complete" mode, the first update jumps directly to turn 5 (final).

Complete Mode (NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCK_SCENARIO=complete)

After the start response (turn 0), every subsequent update returns the final completion state (turn 5) immediately. Useful for quickly verifying end-to-end UI flow.

Error Mode (NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCK_SCENARIO=error)

All API calls return a structured error response with:

  • success: false
  • stage: "provider"
  • error: "Mock provider error: structured response unavailable."
  • providerErrors: [...]

Useful for testing the UI's error display paths.

Architecture

ScenarioForm (client)
  ├── MOCK_ENABLED (compile-time env resolution via Next.js build injection)
  ├── useMockGlobals() → window.__MOCK_* runtime globals
  ├── mockFetch ──► lib/mocks/confidence-engine/mock-client.js
  │                     └── Self-contained interceptor (no external deps, pure ESM)
  │                           ├── handleStartCase() — returns turn 0 or error
  │                           └── handleUpdateCase() — advances turns (0→5)
  └── fetch ────────────────► real API routes /api/cases/start | /api/cases/update
  • mock-client.js is self-contained: all turn data is defined inline. It intercepts POST requests to /api/cases/start and /api/cases/update. Any other URL is passed through unchanged.
  • Uses window.__MOCK_* globals (set by useMockGlobals() hook in ScenarioForm) for runtime env access from the browser. Falls back to process.env.* on the server side.
  • UI integration in scenario-form.jsx: one compile-time boolean (MOCK_ENABLED), one React hook (useMockGlobals), two ternary replacements of fetch. No other components need changes.

Mock Indicator

When mock mode is active, a "Mock mode active" label appears inside the Developer details panel (bottom of the workspace). It does not appear in user-facing UI areas.

The indicator uses mockFetch's built-in guard:

  • In client components: reads from window.__MOCK_ENABLED (set by useMockGlobals).
  • The real API path is preserved — when mock mode is off, mockFetch simply delegates to native fetch.

Files

File Purpose
lib/mocks/confidence-engine/mock-client.js Self-contained interceptor + 6-turn scenario data (pure ESM)
components/scenario-form.jsx Minimal integration: MOCK_ENABLED guard, useMockGlobals hook, mockFetch dispatch
.env.example Documented env var reference
docs/v0.7-ui-mock-mode.md This file

Safety Rules

  • No secrets: Mock fixtures contain only fictional scenario data. No API keys, passwords, or PII.
  • No .env.local commit: The .gitignore already excludes .env.local. Copy from .env.example for local overrides.
  • Real path preserved: Setting NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCKS to anything other than "true" returns to the real Ollama API — zero code change needed.

Turn Fixture Schema

Each turn snapshot (inline in mock-client.js) contains:

{
  nodes: [{ id, label, description, kind, status, confidence, confidenceAssessment?, value?, unit?, evidenceIds?, dependsOn?, affects?, parentId?, childIds? }],
  edges: [{ id, fromNodeId, toNodeId, relationship, confidence, description }],
  resolved: string[],           // IDs of nodes now marked "resolved"
  active: string | null,       // ID of the current unknown node (or null)
  question: string | null,     // Question text for this turn
  noQReason: string | null,    // Why no question is asked (turns 4+ in complete mode)
  summary: string              // Current summary text
}

The situationGraph returned by the fixtures matches the real route response shape exactly, ensuring the UI renders identically.


Playwright E2E Scenario Automation

Purpose

Playwright tests replay main mock investigation journeys to validate:

  • UI layout transitions — idle → loading → success/error terminal/recovery states
  • State machine behaviour — loading overlays, question changes, history rendering
  • Terminal states — CompletionCard (genuine completion) and EvidenceLimitCard
  • Recovery states — ProviderUnavailableCard, MalformedResponseCard content visibility
  • History rendering — turn count increases with each answer submission

These tests do NOT validate reasoning correctness, candidate selection quality, confidence accuracy, or question quality. They are purely UI-layout and state-transition checks.

Quick Start

# Enable mock mode for all Playwright tests
export NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCKS=true

# Run all E2E tests (headless, screenshot on failure only)
npx playwright test

# Run a single spec file
npx playwright test tests/e2e/happy-path.spec.js

# Run in headed mode for debugging
npx playwright test --headed

# Show browser console logs
PWDEBUG=1 npx playwright test

Note: Playwright is already listed as a devDependency (v1.62.1). No additional package installation is needed.

Screenshot Location

Screenshots are automatically saved to test-results/ in the project root when a test fails. They are named by test title and project. Pass-by-default tests produce no screenshots.

To capture screenshots for every scenario (useful for visual regression), run with the --retries=0 flag and inspect test-results/:

npx playwright test --retries=0
ls test-results/
# → happy-path-mock-mode/
# → recovery-states-mock-mode/
# → long-investigation-mock-mode/

Scenario Fixtures

All scenario data lives in tests/e2e/fixtures/investigation-scenarios.js. This file separates content (central statements, answer sequences, expected headings) from test logic. It is shared across all four spec files:

Fixture Central Statement Mock Mode Turns Terminal State
Happy path — multi-turn comparison Product A vs B ratings default (env var) 3 turns No terminal
Happy path — complete investigation Complaints + production complete 1 update turn Investigation complete
Evidence limit (stuck early) Manufacturing quality default (env var) Start only Evidence limit reached
Provider error Complaints + production error Start only Error panel visible
Malformed response Complaints + production error Start only Error panel visible
Long investigation — European market entry SaaS market entry default (env var) 4 answer turns Investigation complete
Contradiction fixture Outsourcing consultants default (env var) 1 update turn No terminal
Diagnosis fixture Customer churn default (env var) Start only No terminal
Comparison fixture Product A vs B ratings default (env var) 2 update turns No terminal
Prioritisation fixture (team relocation) London → Manchester default (env var) 1 update turn No terminal

What Each Spec File Validates

Spec file Scenario coverage Key checks
happy-path.spec.js multi-turn, complete, evidence-limit, reset flow, loading transitions Idle→loading→success transitions, CompletionCard/EvidenceLimitCard visible, history turn count increases, reset button works
recovery-states.spec.js provider error (start + update), malformed response Error panels visible, workspace stays rendered, session persists after error, multiple successive errors don't crash UI
long-investigation.spec.js long 5-turn, contradiction, diagnosis, comparison, prioritisation Multi-turn loading state cycling, answer placeholders update, terminal renders without answer textarea, workspace stability across rapid updates

Accessible Selectors

All tests use role-based selectors (getByRole, getByLabel) and attribute selectors — never CSS class names:

// ✅ Role-based (good)
page.getByRole("button", { name: "Analyse" })
page.getByRole("textbox").first()  // textarea with placeholder="Describe..."
page.getByRole("heading", { name: /Investigation complete/ })

// ❌ CSS class selectors (brittle) — NEVER USED
page.locator(".bg-gray-900 .px-6")  // fragile to theme changes

Test Structure Pattern

Each test follows a consistent flow:

test("scenario name", async ({ page }) => {
  // 1. Navigate
  await page.goto("/");

  // 2. Enable mock mode (set window globals)
  await page.evaluate(() => {
    window.__MOCK_ENABLED = true;
    window.__MOCK_DELAY = "instant";      // instant | normal | slow
    window.__MOCK_SCENARIO = "complete";   // scenario key or ""
  });

  // 3. Enter central statement
  const textarea = page.locator("textarea[placeholder*=Describe]");
  await textarea.fill(scenario.centralStatement);

  // 4. Click Analyse
  await page.getByRole("button", { name: "Analyse" }).click();

  // 5. Wait for loading overlay visible, then hidden
  await expect(page.locator('[data-testid="loading-overlay"]')).toBeVisible();
  await expect(page.locator('[data-testid="loading-overlay"]')).toBeHidden({ timeout: 30_000 });

  // 6. Verify workspace state (terminal card, error panel, or question textarea)
  await expect(page.locator('[data-testid="reasoning-workspace"]')).toBeVisible();
});

Playwright Config Reference

See playwright.config.js for the full configuration. Key settings:

Setting Value Purpose
testDir "./tests/e2e" All spec files under this directory
fullyParallel false Tests run sequentially to avoid race conditions with mock state
timeout 60_000 60s per test (long enough for slow delay mode)
expect.timeout 15_000 15s for individual assertions
screenshot "only-on-failure" No disk writes on passing tests
headless true CI-safe by default
projects[0].name "mock-mode" Distinguishes output in test results directory
retries 0 No retries — failures are deterministic with mock data

Adding a New Scenario Fixture

  1. Add the scenario definition to tests/e2e/fixtures/investigation-scenarios.js:
const newScenario = {
  name: "New fixture description",
  centralStatement: "The statement to analyse...",
  mockMode: "",                     // "" = default, or set window.__MOCK_SCENARIO in test
  turnCount: 2,
  answerSequence: [
    { text: "Answer to first question.", expectedHeadingAfterTurn: "Current investigation" },
  ],
  terminalState: null,              // or "Investigation complete" / "Current evidence limit reached"
  screenshots: [
    { label: "initial-state", afterAction: "before-start" },
    { label: "after-answer-1", afterAction: "after-answer-1" },
  ],
};

export const INVESTIGATION_SCENARIOS = [...INVESTIGATION_SCENARIOS, newScenario];
  1. Add a test case in the appropriate spec file that references the fixture.

Running Tests During Development

While developing mock responses or UI components, run tests with headed mode:

# Watch all specs and re-run on file changes
npx playwright test --headed --ui

The Playwright Test UI (shown via --ui) lets you step through each assertion, inspect the live DOM, and replay failed steps.