Files
confidence-engine/docs/v0.7-ui-mock-mode.md
T
robbond 97a4847770 feat: add mock investigation mode for UI development
- lib/mocks/confidence-engine/mock-client.js: self-contained ESM interceptor with 6 inline turn fixtures, no external deps or require() calls
- components/scenario-form.jsx: MOCK_ENABLED compile-time boolean, useMockGlobals() hook injects window.__MOCK_* globals at runtime, ternary dispatch to mockFetch
- .env.example: NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCKS, MOCK_DELAY, MOCK_SCENARIO env vars
- docs/v0.7-ui-mock-mode.md: setup, scenarios (default/complete/error), architecture, safety rules, fixture schema
2026-08-04 13:56:15 +01:00

6.1 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.