- 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
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: falsestage: "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/startand/api/cases/update. Any other URL is passed through unchanged. - Uses
window.__MOCK_*globals (set byuseMockGlobals()hook in ScenarioForm) for runtime env access from the browser. Falls back toprocess.env.*on the server side. - UI integration in
scenario-form.jsx: one compile-time boolean (MOCK_ENABLED), one React hook (useMockGlobals), two ternary replacements offetch. 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 byuseMockGlobals). - 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.localcommit: The.gitignorealready excludes.env.local. Copy from.env.examplefor local overrides. - Real path preserved: Setting
NEXT_PUBLIC_CONFIDENCE_ENGINE_MOCKSto 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.