# Current Handoff — Confidence Engine > **Role:** Concise operational snapshot for resuming work today. Not a historical diary. > The design evolution archive index at `docs/design-evolution/README.md` provides progressive loading of experiment history; load the relevant chapter only when a specific historical question requires it. ## Tester legal information - Public Privacy, Terms, and Cookie pages and shared legal navigation are available at `/privacy`, `/terms`, and `/cookies`. - The service is positioned as 18+. No cookie-consent banner is used because current browser storage is limited to essential authentication/session storage and functional UI preferences. - Legal wording remains subject to appropriate professional review. - Legal navigation is a single global normal-flow footer: it rests at the viewport bottom on short pages, long legal pages push it naturally below their content, and duplicate legal navigation was removed. ## Focused-investigation provider outage boundary - Focused-investigation outage handling now sanitizes provider failure at the API boundary: unavailable focused reasoning returns a controlled HTTP 503, and raw provider/Ollama diagnostics no longer leave that boundary. - The existing generic Retry UX remains unchanged. A live deployed outage had already proven investigation preservation. - `/api/cases/start` and `/api/cases/update` outage sanitization remain separately unverified; this change does not claim those routes are fixed. ## Reasoning API browser error boundary hardened - All reasoning HTTP error responses now sanitize raw provider diagnostics: `e.message` / raw internals never leak to the client. - Verified on: `/api/cases/start`, `/api/focused-investigation/deconstruct`, `/api/cases/overview`, `/api/cases/synthesis`, `/api/analyse`. - Provider/internal diagnostics remain server-side only. - No reasoning semantics changed. ## v0.62d production Docker packaging — LIVE PROVEN - `Dockerfile` — minimal multi-stage Alpine build (Node 22), Next.js standalone output mode - `.dockerignore` — excludes dev artefacts, secrets, docs from build context - `next.config.mjs` — added `output: 'standalone'` (required for lean production container) - `.env.example` — reorganized: Supabase → Ollama → Mock sections; Ollama vars now tracked as deployment-relevant - **npm production build: PASS** ✓ - **Docker image build on CT 112: PROVEN** — production Docker image builds successfully on CT 112, standalone Next.js container starts successfully. - Production container `/api/health`: **PROVEN** — `{"healthy":true}`, no private Ollama endpoint / model name / raw internal error exposed. - No persistent application volume required. - Supabase remains external, Ollama remains private and server-reachable from the deployment host. - Public `NEXT_PUBLIC_*` variables may require build-time injection via `--build-arg` as established by the implementation (baked into browser bundle). - **Deployment: LIVE PROVEN** — manual Jenkins pipeline succeeded end-to-end (SHA-tagged image, container replaced, health check passed). ### v0.62d External Deployment (LIVE) Confidence Engine is externally reachable at **https://confidence.rdbcloud.co.uk**. Production topology: ``` Internet → HTTPS → Nginx Proxy Manager → CT 112 / Confidence Engine Docker container ``` CT 112 deployment details: ``` hostname: confidence-engine LAN address: 192.168.68.73 repo: /opt/confidence-engine container: confidence-engine port: 3000 ``` Docker-in-LXC has been proven. Docker image builds successfully on CT 112. ### v0.62d Magic-Link Login (LIVE) External magic-link login has been proven through the deployed application at `https://confidence.rdbcloud.co.uk`. The reverse-proxy callback-origin defect was corrected; successful login now returns to the external Confidence Engine Portfolio rather than `0.0.0.0:3000`. Auth email branding configured on external Supabase infrastructure (outside this repository): - Confidence Engine sender name / subject / branded HTML body - SPF PASS, DKIM PASS, DMARC PASS — recipient-side confirmed - Missing original Message-ID / junk-folder observation remains a non-blocking external mail-deliverability note ### v0.62d Multi-user Boundary (LIVE) Application-level isolation proven on deployed instance: ``` User A sees User A investigations User B does not see User A investigations ``` ### v0.62d Real Deployed Product Journey (LIVE) Manually proved through the externally deployed application: ``` authenticate → Portfolio → create new investigation → reason through Qwen → server persistence → return to Portfolio → leave/return → investigation restored ``` Server-backed persistence remains authoritative. Legacy localStorage investigations remain ignored. ### v0.62d Manual Jenkins Deployment Pipeline (LIVE PROVEN) Manual end-to-end pipeline proven: ``` manual Jenkins Build with Parameters → GIT_REF accepted → remote ref resolved to immutable SHA → Jenkins SSH credential bound → SSH to CT 112 → deployment script executed → exact SHA fetched/checked out → Docker image built and tagged by SHA → existing CE container replaced → /api/health polled → healthy response observed → DEPLOYMENT SUCCEEDED ``` Pipeline design: - Manual trigger, runtime-selectable `GIT_REF`, immutable SHA deployment - CT 112 as Docker build/runtime host, target-owned `/opt/confidence-engine/deploy.env` - SHA-tagged Docker images, health-gated success, bounded rollback support - No Docker registry, no automatic webhook deploy **Path status:** success path = LIVE PROVEN. rollback path = IMPLEMENTED, NOT LIVE PROVEN. Jenkins SCM branch used to load the Jenkinsfile is conceptually separate from the `GIT_REF` chosen for deployment. ## v0.63 First-Time Unauthenticated Product Framing - login page now explains product purpose and investigation flow to first-time visitors without prior explanation - user judgement/choice explicitly preserved ("It doesn't try to make the decision for you") - existing magic-link authentication unchanged - no broader onboarding/tutorial system introduced ### Mobile-first sign-in order (responsive layout fix) - v0.63f corrected mobile reading order: proposition → sign-in card → supporting explanation - CSS Grid with responsive column placement replaces original flexbox; three DOM sections ensure correct mobile stacking without duplicating content - desktop two-column presentation (explanation left / sign-in right) preserved unchanged at `md` breakpoint and above ## Focused-investigation input hardening - Focused answer now has a visible 10,000-character UI limit (maxLength + character counter). - Server enforces matching 10,000-character bound on `/api/focused-investigation/deconstruct`. - Other prompt-bearing fields retain explicit defensive bounds (2048 characters each). - Oversized/malformed requests are rejected before reasoning with controlled HTTP 400. - No punctuation/HTML/SQL-style content stripping introduced. - Reasoning semantics unchanged. ## Pre-Tester Input Security Review **Status:** closed — sufficient for controlled external-user testing. Not a general security audit, penetration test, or production-launch certification. ### SQL injection - No raw request-driven SQL construction found. - Persistence uses Supabase/PostgREST query-builder boundaries. - SQL-character stripping / sanitisation is not warranted. ### XSS - Normal user-controlled text is React-escaped. - No user-controlled unsafe HTML sink found. - HTML / script stripping of prose is not warranted. ### Reasoning error disclosure - Browser-facing reasoning errors have been sanitised (commit `2cb2d55`). ### Focused user input - Bounded to 10,000 characters server-side on `/api/focused-investigation/deconstruct`. - UI exposes matching `maxLength` and character counter (commit `a6796c6`). ### Investigation snapshot size - Authenticated persistence envelope currently lacks a whole-snapshot size ceiling. - Not classified as an outstanding pre-tester blocker. - Legitimate investigation size / turn depth is not yet known. - No arbitrary product ceiling imposed before real-user evidence exists. - Monitor snapshot growth later via metadata (serialized bytes / revision / contribution count) without logging investigation content. - Malformed-envelope / runtime validation remains a separate future hardening opportunity. ### Prompt injection - Assessed as **low risk under the current architecture** — not claimed to be impossible or "solved". - Untrusted scenario / answer / persisted text can influence model reasoning. - No evidence it gains application authority: no model-accessible arbitrary tools, DB targeting, auth identity control, ownership bypass, deletion, or arbitrary external requests found. - Model/provider configuration is server-owned; model output passes through parsing/structured validation/domain boundaries before application mutation. - No prompt-injection phrase / keyword filtering warranted; do not strip instruction-like natural-language content. - Not a pre-tester blocker. ### Deferred non-security observations (backlog only — no code change) - Orchestrator update flow contains an implicitly correct but indent-control-flow-unclear fall-through / else structure worth cleaning up later. - Investigation overview validation may accept unexpected extra fields. - Provider JSON recovery is intentionally/permissively capable of recovering malformed JSON; may merit a future robustness review. ### Tester-readiness position Identified MEDIUM pre-tester security work is sufficiently addressed for controlled external-user testing. The application has **not** been generally security-audited, penetration-tested, or certified as production-secure or commercially launch-ready. ## CURRENT MVP DIRECTION Initial-decomposition hardening is frozen for the current MVP stage. ## Authenticated product boundary (v0.62a) - Confidence Engine uses self-hosted Supabase Auth with magic-link email, `/auth/callback` code exchange, cookie-backed sessions, and protected product routes/API requests; unauthenticated API requests receive 401. - Investigation persistence is now server-authoritative via Supabase `confidence_engine.investigations`. Browser persistence flows through authenticated Next.js API. No `confidence_engine` database schema, tables, snapshot ownership fields, or PostgREST configuration were changed in v0.62c (established in v0.62b). ## Database foundation (v0.62c) - Server-authoritative investigation persistence via Supabase `confidence_engine.investigations` as durable authority; browser persistence flows through authenticated Next.js API (`/api/investigations`). - `lib/storage/providers/server-http.js` replaces localStorage as the backing provider for `lib/storage/investigation-storage.js`. The storage seam now owns async load/save and per-investigation coalescing autosave (rapid concurrent saves collapse to the latest snapshot). - Async hydration adapted across Portfolio, Investigation, Report, and ScenarioForm. - Restart preserved via shared transformation in `lib/storage/restart-investigation.js`; server-backed restart endpoint reuses this same transformation. - Portfolio-compatible server summary projection (`scenario`, `updatedAt`, `investigationRevision`, `reportExists`, `reportGeneratedFromRevision`). - Missing-new-investigation 404 maps to `null` at the load boundary in `server-http.js`. - Live save and Portfolio reload persistence proven by manual evidence on Sep 8. - Live application-level user isolation proven: second authenticated user sees clean Portfolio; original user regains only their server-backed investigation. - localStorage is no longer production authority. Legacy localStorage investigations remain physically present but invisible to normal product flow. No dual-write. No automatic legacy import. - Duplicate investigation GETs observed on development reload; one database row and one Portfolio card confirmed. No data-integrity defect established. No optimisation undertaken. **Current product checkpoint:** Read `docs/confidence-engine-product-checkpoint-2026-09-08.md` before planning new product, live-evidence, or commercial work. The core investigation loop is now sufficiently established to prioritise realistic end-to-end use, report experience, prospective-user value, repeat use, and willingness to pay—not endless isolated reasoning-mechanics experiments. Preserve user ownership and address trust-critical defects when found. Do not resume: - repeated-same-input reconstruction experiments - Qwen/Terra reconstruction comparison - initial prompt refinement - supplier/weekend-shift decomposition experiments - relationship-preservation experiments - causal-fidelity experiments unless new end-to-end user-flow evidence reopens one of those boundaries. **Immediate strategic evidence question:** Does the complete investigation process leave real people materially clearer about genuinely difficult situations, repeatedly enough that they will pay to use it? Use measured realistic scenarios and bounded live action budgets; the September 8 checkpoint records the current Terra cost/latency evidence. ## Server-owned UI journey provider experiment - Server-only `CONFIDENCE_ENGINE_EXPERIMENT_PROVIDER=openai` centrally resolves the existing OpenAI provider and `gpt-5.6-terra`; without it, normal production resolution remains Ollama/Qwen. An OpenAI key alone does not switch providers. - Browser request contracts and client state remain unchanged. Deterministic coverage includes initial start, normal update, episode reconsideration, focused deconstruction, overview synthesis, and Current Understanding synthesis. - Zero live calls occurred. Next boundary: one real Playwright-driven Terra investigation measuring user-visible latency, actual LLM-call sequence, and OpenAI usage/cost. ## OpenAI alternate structured output - The OpenAI provider now honors a caller-supplied structured-output schema, applying its existing strict-schema transport projection; absent an alternate schema, initial reconstruction retains its existing strict schema and transport normalization. - The next live run exposed incomplete recursive strict projection: OpenAI rejected `relationships.items` because it lacked `additionalProperties: false`. The projector now recognizes every `type: "object"` node, including property-less objects in array items, and recursively enforces strict object schemas while preserving initial-reconstruction optionality/nullability behavior. - The latest Terra request then exposed an inconsistent root `properties`/`required` contract. The projector now derives `required` after projection from the surviving property keys, and recursive tests verify `properties`, `required`, and `additionalProperties` consistency. Property-less object strictness and initial-reconstruction transport behavior remain preserved. - Current deterministic final-fetch schema remains internally valid, yet the live rejection contradicts it. `CONFIDENCE_ENGINE_EXPERIMENT_TRACE_OPENAI_SCHEMA=1` now emits one safe, server-side structural summary immediately before the OpenAI fetch—no prompt, answer, request body, secret, or model output. - The focused-deconstruction route now emits complementary safe server diagnostics for start, provider success/failure, focused validation, and end status; the OpenAI schema trace remains provider-owned. No user content or secrets are logged. - Canonical focused relationship items are now strict `{ from, to, type }`: all required non-empty strings, free-text `type`, and no `rationale`; `relationships` remains required and may be `[]`. Schema, prompt field names, and validator align; the stale rationale-bearing test fixture was corrected. - Live Terra focused deconstruction now passes through the real UI, but the following Current Understanding synthesis exposed a separate caller/schema mismatch: its prompt and validator require `{ currentUnderstanding }` while the provider received the default initial-reconstruction schema. - Terra synthesis now supplies its own output schema and unwraps `providerResult.response` before validation; deterministic synthesis coverage is 62/62 PASS and the saved isolated Terra synthesis POST returned HTTP 200. - Real Terra completed-episode reconsideration can legitimately return no additional meaningful graph change. Completed episodes now tolerate only that exact compatibility outcome; ordinary no-op updates and invalid completed-episode proposals remain rejected, without fake graph mutation or new next-question steering. - The full apply-proposal owner suite remains known-red in independent pre-existing 60B.43 tests, so the changed Done-for-now boundary was verified through exact isolated owner tests. Zero live calls occurred during closeout. Next boundary: reuse the existing investigation and click Done for now once, observing cases/update and subsequent synthesis. - Live UI proved Done for now briefly clarified the question, then server graph replacement reopened it: the client sends `preDoneGraph`, and the server previously had no deterministic closure owner. Episode-mode update now adds the selected `targetNodeId` to `resolvedNodeIds` only after successful semantic application; semantic no-ops and meaningful mutations remain valid, while failed episodes do not resolve the target and ordinary updates are unchanged. Zero live calls occurred during implementation. Next boundary: one live Done-for-now check on the existing investigation. ## Deployment automation (LIVE PROVEN) Manual Jenkins deployment pipeline established, version-controlled, and LIVE PROVEN end-to-end. - `Jenkinsfile` in repository root — Declarative Pipeline, three stages: Resolve → Deploy → Verify/result. - `scripts/deploy-production.sh` — executes on CT 112; validates SHA, fetches Git ref, checks out exact commit, builds Docker image tagged by SHA, replaces container, polls `/api/health`, one-step rollback to prior image on failure. - `deploy.env.example` — example of required runtime/build environment file (NOT tracked). - Production env owned by `/opt/confidence-engine/deploy.env` on CT 112 (not in Git). - `GIT_REF` is runtime-selectable (Jenkins parameter); resolves to immutable SHA before deployment. - No Docker registry introduced. SHA-tagged images retained for rollback support. - Jenkins job remains manually triggered — no automatic webhook deployment. - No product behaviour changed by deployment automation. **Success path: LIVE PROVEN.** **Rollback path: IMPLEMENTED, NOT LIVE PROVEN.** ## Repository checkpoint - **Branch:** `feature/product-platform-foundation-v0.62` - **HEAD:** *(checkpoint commit — see git log for actual SHA)* - **Working tree:** clean (after Loop 3 apparatus commit) ## Architectural Conclusion **The original v0.62 product-platform objective is achieved:** - Authenticated identity (magic-link via self-hosted Supabase) - Authenticated reasoning APIs (private Ollama/Qwen, server-reachable) - User-owned server persistence (Supabase `investigations`, RLS-scoped) - Multi-user application behaviour (application-level isolation proven) - Portable Docker runtime (Docker-in-LXC on CT 112) - External HTTPS deployment (Nginx Proxy Manager → CE container) - External magic-link authentication (callback fix, email branding proven) - Manual one-touch Jenkins deployment (SHA-tagged, health-gated) **The following are NOT required and NOT justified before testing:** - Legacy localStorage migration — not required. Four development/test investigations will not be migrated; legacy data remains invisible to normal product flow. - Additional SaaS/platform machinery — not justified before real user testing. > **Platform/deployment foundation work is complete enough to disappear into the background. The next Confidence Engine work should return to product/reasoning/user-learning priorities rather than continuing infrastructure expansion unless a real operational failure demands it.** ## Persistence - **Owner:** `lib/storage/providers/server-http.js` (authenticated browser HTTP provider). `lib/storage/investigation-storage.js` owns the application-facing boundary with coalescing autosave and async load/save. - **Durable authority:** Supabase `confidence_engine.investigations` (RLS-scoped, user-owned). - **localStorage:** legacy only — physically present but invisible to normal product flow. No dual-write. No automatic import. - **Restart transformation:** shared in `lib/storage/restart-investigation.js`; used by both browser seam and server persistence layer. ## Canonical experiment apparatus — currently valid ``` scripts/start-case-experiment-helper.cjs — canonical helper (tsx runtime) tsx runtime — alias-capable experiment execution --file — file-input mode (JSON fixture) --reconstruction-only — stop after initial reconstruction, no question generation import-only proof — prove startCase() import chain resolves without live calls OpenAI reconstruction experiment seam — START_CASE_EXPERIMENT_PROVIDER=openai (experiment-only) focused-deconstruction schema fix — plumbing verified, 48/48 tests pass tests/experimental/report-epistemic-ab-input-control.test.js — deterministic A/B input control apparatus (34 tests across two cases, zero live calls) scripts/overview-experiment-helper.cjs — canonical overview live helper (CJS runtime) --self-test — deterministic no-network mode with inline fake provider ``` **No other experimental apparatus is currently valid.** Obsolete setups have been removed or superseded. ### Epistemic A/B overview apparatus extension (Loop 4/1) - `scripts/overview-experiment-helper.cjs` extended with `--variant hidden|visible`: - **hidden** (default): production path — unresolved questions filtered by prompt builder - **visible**: appends unresolved questions as separate NON-EVIDENCE section to baseline prompt - Apparatus invariant proven deterministically: A/B evidence, findings, plausibleInterpretations, scenario state are identical; only unresolved visibility differs. - Production `lib/graph/investigation-overview-synthesis.js` unchanged. - **Controlled A/B completed:** product-launch zero-Findings case, 2 live calls (51s hidden, 54s visible). **Result:** Supported understanding materially unchanged; both calls produce the same core finding (product ready enough for launch, one large enterprise client relevant). No plausible interpretations in either variant (helper called with `[]` plausibleInterpretations — correct for this fixture's initial state). Unresolved customer-signing and competitor uncertainty remained distinct, unanswered, non-evidence in B. Neither call promoted unresolved material into supported understanding or plausible interpretation. **Contamination classification:** NONE - No supported claim added or removed - No qualification/certainty shift beyond minor phrasing variation (~17 chars) - Customer-signing uncertainty: NOT promoted to evidence, NOT interpreted/answered - Competitor uncertainty: NOT promoted to evidence, NOT interpreted/answered - Unresolved not prioritised in either call **What this establishes:** Under controlled product-launch conditions (zero Findings), exposing unresolved future-dependent Open Questions as a separate NON-EVIDENCE section does not cause the model to use that uncertainty as evidence or merge it into plausible interpretation. The epistemic boundary holds for Qwen under this scenario shape. **What it does not establish:** Does not prove universality across other scenarios, other models, or when plausibleInterpretations are non-empty. Does not generalize to manufacturing scenarios (with findings). One scenario shape only. ### Zero-Finding Report Experiment Case (Loop 2/3) ### Zero-Finding Report Experiment Case (Loop 2/3) - `tests/fixtures/live-product-launch-start-response.json` is the valid second controlled case. - Its reasoning shape: future-dependent commercial/actor uncertainty (enterprise customer contract timing + competitor activity). - This fixture legitimately contains **zero Findings** — no findings array present in the start-response. - Apparatus now represents absent `findings` as `[]` via `(fix.findings ?? [])` nullish coalescing on line 20 of the test file. - The apparatus preserves the semantic distinction: supported evidence from graph ≠ Findings. An investigation can have supported graph evidence with zero canonical Findings. - Both manufacturing (with findings) and product-launch (zero Findings) A/B controlled cases pass all determinism checks. - **No live second-case A/B has yet been run.** The behavioural question — whether exposing unresolved uncertainty in the presence of zero Findings produces different model output than without — remains open. ### Three-Part Report Increment — Loop 4/2 (VERIFIED) **Implementation commit:** `56b5f00` — "feat(confidence-engine): show unresolved report questions" Deterministic apparatus verified that: - Resolved/unknown nodes are excluded from admitted evidence at prompt construction time; - Passing the full situationGraph with unresolved nodes vs a filtered version produces identical prompt text (18 deterministic tests, all PASS). Live rendered-product verification via Playwright established that one actual investigation Report renders three distinct epistemic sections: 1. **What we understand** — contains evidence-backed understanding; unresolved Open Questions do not appear as supported understanding. 2. **What remains plausible** — visibly and semantically separate; section correctly displayed its empty/default state (no supplied plausible interpretations in the verified investigation). 3. **What remains unresolved** — derives from canonical unresolved Open Questions; rendered the canonical question text; remained visibly separate from understanding and plausible interpretations; did not answer, reinterpret, rank, prioritise, or imply blockers/readiness/confidence/evidence sufficiency/investigation completion. - Deterministic verification: passed. - Rendered-product verification: passed for three-part epistemic separation. - Unresolved questions remained canonical non-evidence. - Zero additional experimental model calls during live verification. - No production code or test changes during verification. - **Evidence boundary:** establishes the implemented three-part boundary in the deterministic apparatus and the one observed rendered investigation. Does not generalise to universally solved, proven across all investigations, or production-complete. **Update report placement/ownership (RESOLVED by Iteration 4):** `Report page + only when report is STALE`. The control exists on the report page and is invoked by the user when the lifecycle shows stale. This is established production behaviour, not an open UX decision. **Iterated Four — Zero-Plausible Interpretations Checkpoint (2026-10-02):** Implementation commit: `0cc9d08` — "permit empty plausibleInterpretations for honest zero state" Contract properties: - `plausibleInterpretations` is a required string field; - empty string (`""`) represents a genuine zero-plausible state; - non-empty string represents a plausible narrative; - `hasPlausibleInterpretations` derives from validated output content (no hard-coding); - the model is explicitly permitted/required to return `""` when SECTION B is empty; - zero-plausible reports omit "What remains plausible"; - non-zero behaviour remains deterministically covered. Deterministic verification: 71/71 PASS. Report lifecycle (established): - absent → generate on first visit; - current → reuse; - investigation changes → stale; - stale → user-owned Update report action; - no automatic regeneration. Fixed live investigation (`eae84f2d-acd8-4a92-bd43-347628b536a7`): - precondition: `investigationRevision = 2`, `generatedFromRevision = 1`, report = STALE, plausible inputs = 0; - exactly one live Update report action produced `plausibleInterpretations = ""`, `hasPlausibleInterpretations = false`, `investigationRevision = 2`, `generatedFromRevision = 2`, report = CURRENT; - rendered result: "What we understand" visible, "What remains plausible" omitted, "What remains unresolved" visible, obsolete absence prose absent, canonical unresolved questions preserved. **Evidence limitation:** This is specific to the one fixed zero-plausible regression case described above. The model correctly represented zero interpretations as empty string and rendered the report without a plausible section in this verified scenario. It does NOT prove universality across all scenario shapes or models. **Next step:** product-level review of the Investigation Report experience — do not automatically change implementation. ### Iterated Five — Report Learning Semantics (2026-10-02) **Resolved question:** Should "What the investigation surfaced" represent learning produced by investigation history, or only learning attached to questions that are currently closed-for-now? **Answer:** Only learning attached to questions that are currently closed-for-now. ``` What the investigation surfaced = eligible provenance-linked learning associated with questions that are currently closed-for-now ``` **Qualification:** `closed-for-now != final`, `!= settled`, `!= conclusively answered`. **Re-open semantics:** ``` Done for now → question may contribute to What the investigation surfaced Re-open: → question removed from resolvedNodeIds → surfaced-learning entry disappears → Contributions remain → Findings remain → provenance remains → question becomes independently representable in What remains unresolved ``` Re-open does NOT erase investigation history. It changes current closure state. **Provenance/currentness boundary:** Canonical provenance survives Re-open (`Question → Contribution.targetNodeId → Contribution.id → Finding.contributionId`). However: ``` Finding eligibility ≠ epistemic currentness ``` Canonical Findings contain no explicit marker (`current`/`historical`/`superseded`/`replaced`/`authoritative`/`episode/version`). Re-investigation can append newer Contributions/Findings while older eligible Findings remain. Retained Findings can prove what surfaced historically, but must not be treated as deterministic evidence that an older proposition remains the latest/current truth. **Persistence diagnosis:** No resolvedNodeIds persistence defect was found. The fixed investigation's `resolvedNodeIds=[]` was explained by the deliberate historical Re-open of node nrx08i0. Done-for-now produced the closure marker; ScenarioForm preserved it; canonical save/load preserved it; Re-open intentionally removed it. **Deterministic protection:** ``` tests/graph/investigation-learning-projection.test.js 7/7 PASS tests/ui/v060h-report-identity.test.jsx 18/18 PASS ``` Tests establish: (1) eligible closed-for-now question included; (2) reopened question omitted even while Contributions/Findings remain; (3) canonical provenance retained; (4) unresolved representation remains independent. **Production state:** No production or test change required. Current resolvedNodeIds admission gate is semantically correct. This checkpoint records a currently closed-for-now boundary decision, not a completed/finalized/settled outcome. ## Current product architecture Three distinct routes: ``` / → Portfolio (notebook index) /investigations/{id} → Investigation (working case/pages) /investigations/{id}/report → Investigation Report (derived summary) ``` **Portfolio:** investigation collection loaded from server API (`/api/investigations`). Actions per card: View report, Continue investigation, Restart. "+ Create new investigation" allocates durable ID via `crypto.randomUUID()` + navigates. **Investigation:** `ScenarioForm` + `ReasoningWorkspace`. Handles focused turns, Done/Re-open semantics, Current Understanding synthesis. **Report:** rendered persisted `investigationReport` snapshot. On-demand generation (one `/api/cases/overview` on first visit; zero on subsequent). Not canonical reasoning evidence — derived artefact. ## Evidence discipline invariants ``` RAW USER EVIDENCE ≠ MODEL-DERIVED CONTRIBUTION SEMANTICS ≠ CURRENT CANONICAL FINDING ≠ IMMUTABLE SOURCE OBSERVATION ≠ USER DISPOSITION / AUTHORITY ≠ TURN CONTEXT / PROVENANCE ``` **Finding dispositions:** `null` (eligible working premise), `agree` (user-endorsed), `not_relevant` (excluded from eligible reasoning, provenance retained). User disposition never directly mutates authoritative graph state. ## Persistence - **Owner:** `lib/storage/providers/server-http.js` (authenticated browser HTTP provider). `lib/storage/investigation-storage.js` owns the application-facing seam with coalescing autosave. - **Durable authority:** Supabase `confidence_engine.investigations` (RLS-scoped, user-owned). - **localStorage:** legacy only — physically present but invisible to normal product flow. No dual-write. No automatic import. - **Identity:** durable `id` allocated by application, not storage. - **First persistence:** when user produces meaningful state (scenario submitted), not on create-click. - **Restart:** preserves container/id/scenario; clears reasoning/report state via shared transformation in `lib/storage/restart-investigation.js`. ## MVP boundaries **Implemented:** - Multi-investigation via localStorage with durable IDs - Report freshness (`Current` / `Update available`) derived from revision comparison - Manual `Update report` action - Confirmation-gated restart - No automatic regeneration - Duplicate prevention guard **Deferred beyond MVP:** - Search, tag, archive, group within Portfolio - Export/copy Reports to external document - Report history / comparison - Multi-provider production routing (OpenAI/Terra comparison is frozen) ## Current development constraints - Canonical dev server at `http://localhost:3000`. Never start/stop/restart/probe it. If unavailable → BLOCKED and stop. - Playwright MCP: use **Run Playwright code** with semantic locators. Snapshot refs are observational only. - For async/hydration states: use `waitFor({ state: 'visible', timeout })` — not arbitrary sleeps. - If a prescribed semantic locator cannot find its control → STOP. No fallback to CSS/XPath/DOM traversal. - Live freeze: once Playwright verification begins, no production file edits until evidence is captured. - **Tests are instruments, not product truth.** At first deterministic failure: classify PRODUCT vs APPARATUS, then stop. - A failed prescribed UI step is evidence, not permission to explore: semantic `page.getByRole(...)` locators only; do not substitute actions, retry model-backed steps, or navigate away from a manually positioned persisted state. Define action budgets for live cost experiments. ## Current genuinely open boundaries **Not yet implemented:** - Multi-investigation portfolio (search/tag/archive/group) - Export/copy of Reports to external document - Production multi-provider routing (Ollama/Qwen default remains) **Known limitations:** - Current Understanding and Investigation Report are architecturally distinct artefacts. Report interpretations remain explicit, not evidence. - The `≤5` processing bound was experimental apparatus constraint, NOT product requirement. ## Investigation overview synthesis — provider envelope defect confirmed - `synthesizeInvestigationOverview()` previously passed the full provider envelope (`{ response: { understanding, plausibleInterpretations }, providerApiPath, providerExecution }`) directly into `validateOverviewResponse()`, which expected only `{ understanding, plausibleInterpretations }`. This caused "Missing or invalid required fields" on real providers. - Fix now unwraps `.response` before overview validation, matching the proven pattern in `lib/graph/current-understanding-synthesis.js` (line 296: `validateSynthesisResponse(providerResult.response)`). - **Additional fix:** `synthesizeInvestigationOverview()` previously called `provider.generateReconstruction(prompt, modelName)` without an output schema, while `synthesizeCurrentUnderstanding()` passes `synthesisOutputSchema`. Without a structured-output contract the provider defaults to initial-reconstruction format, which lacks `{ understanding, plausibleInterpretations }`, causing validation failure. Fix adds `overviewOutputSchema` (JSON-schema: `{ understanding: string, plausibleInterpretations: string }`) and passes it as third argument. - Owning regression (`tests/graph/investigation-overview-synthesis.test.js`) now mirrors real provider envelope shape (`{ response: { understanding, plausibleInterpretations }, providerApiPath }`). Regression fails against pre-fix seam and passes after fix. - Canonical overview live helper `scripts/overview-experiment-helper.cjs` established with deterministic no-network self-test (zero live calls). Product-launch zero-Findings fixture reaches successful overview synthesis in deterministic mode. 53/53 overview tests pass. - **Zero live proof yet.** Zero live calls made in this handoff. - Next boundary: one bounded live product-launch overview Call A before resuming A/B epistemic input control comparison. ## HISTORICAL — initial-decomposition v0.61 status Initial decomposition experiments (v0.61) ran four successful runs plus one validation failure against the same manufacturing scenario. Key findings: - **Consistently preserved across all runs:** normalisation uncertainty, CRM comparability, supplier/shift ambiguity - **Variable:** late-delivery vs defect distinction (1 PRESENT, 3 PARTIAL) - **Rarely surfaced:** intervention-fit uncertainty (1 PRESENT, 3 ABSENT) - **Run 2 introduced speculative subdivisions** not grounded in source text - No steering language, unsupported causality, or action recommendations in any run - Graph topology varies materially (14–21 nodes) across runs — this is expected, not a defect Qwen/Terra matched evidence showed Terra with stronger stability on C and D1/D2 distinctions; Qwen preserved meaning but compressed more frequently. Both providers vary graph topology while preserving core dependencies. These results are documented as **historical experiment evidence**. The v0.61 line is frozen — see CURRENT MVP DIRECTION above. ## Provenance pointers | Need | Read | |---|---| | Product evolution v0.51–v0.60 | `docs/design-evolution/README.md` (progressive loading) | | Methodology / RTO axioms | `docs/current-working-principles.md` §0 (A1–A12) | | Uncertainty-led initial investigation hypothesis | `docs/uncertainty-led-investigation-hypothesis.md` — **PROPOSED / UNTESTED — no implementation decision made** | | Architecture guardrails | `.claude/architecture-guardrails.md` | | Task routing by work type | `docs/task-context-packs.md` | | September 8 product/economics checkpoint | `docs/confidence-engine-product-checkpoint-2026-09-08.md` | | Full experiment history (specific) | `docs/design-evolution/README.md` → relevant chapter | ## Iterated Ten — Paired Uncertainty-Description Comparison Without Initial Question Generation (CE-ULI-10, 2026-10-12, Iteration 5 of 10) **Type:** One-paired-live-call semantic comparison (Iteration 5 of bounded iteration loop). Two live LLM calls. **Objective:** Test whether removing initial question generation changes the fidelity of canonical uncertainty descriptions in a historical case where the original question transformation exhibited partial semantic narrowing. **Fixed inputs:** - Scenario: "Our company is considering launching a new service within nine months. The launch would require recruiting two specialist employees, completing a new software integration, and securing commitments from enough customers to cover the ongoing operating costs. Each requirement appears achievable individually, but delays in one area could affect the others. I need to understand whether we can realistically launch the service within nine months with all three requirements sufficiently satisfied." - Input file: `.evidence-temp/headless-semantic/HS-03C-input.json` (scenarioId: `new-service-launch`) - Model: `qwen-claude:latest` via Ollama (`http://192.168.1.111:11434`) - Apparatus: `start-case-experiment-helper.cjs` with `--condition A` (question-required, production prompt+schema) and `--condition B` (question-free, alt prompt+schema) ### Historical narrowing case (from HS-03C-result.json reconstruction): The original reconstruction produced four importantUnknowns, each narrowed by its generated question: 1. **u1** (recruitment): Description="Timeline and feasibility of recruiting two specialists within the nine-month window" → Question narrowed to hiring pipeline status. 2. **u2** (integration): Description="Timeline for designing, testing, and deploying the software integration..." → Question narrowed to "planned development schedule." 3. **u3** (customer commitments): Description="Volume and activation timeline of customer commitments needed..." → Question narrowed to current count. 4. **u4** (cross-area dependencies): Description="Nature and magnitude of dependencies between the three requirements that could cause cascading timeline delays" → Question narrowed to specific bottlenecks. The narrowing pattern: each question moved from broader feasibility/timing/dependency uncertainties toward present evidence, schedules, or operational bottlenecks. The historical case is about individual domain uncertainties (recruitment, integration, commitments, dependencies) being individually preserved as descriptions but narrowed by their generated questions. ### Fixture equivalence: The HS-03C-input.json scenario represents the same nine-month service-launch case. It contains all three interdependent requirements and the explicit cross-area delay concern ("delays in one area could affect the others"). **Equivalent.** ### Condition A (question-required) results: **Reconstruction:** 2 importantUnknowns, 8 nodes, 4 edges, 1 relationship. - **u1**: Description="The feasibility of launching the service within nine months while satisfying recruitment, integration, and customer commitment requirements." + question="Can we realistically launch the service within nine months with recruiting, integration, and customer commitments all sufficiently satisfied?" - **u2**: Description="How delays in one requirement could cascade to affect the feasibility of the others within the fixed deadline." + question="In what specific ways could a delay in recruiting, integration, or customer acquisition affect the timeline for the other requirements?" **Fidelity evaluation:** 1. Relevant uncertainty identified: YES — broad launch-feasibility concern preserved as u1; cascading-delay dependency preserved as u2. However, individual domain uncertainties (recruitment-specific, integration-specific, commitment-specific) were not separately retained. They are subsumed into the broader descriptions. 2. Canonical description retained broader subject: YES — both u1 and u2 descriptions remain broad, covering combined feasibility and cascading delays without narrowing to operational specifics. 3. Qualifications/timing/conditions preserved: PARTIAL — "nine months" constraint retained; "three interdependent requirements" context partially present (via description wording); the individual-achievable-vs-combined-feasibility distinction from original scenario is implicit in summary but not explicit in descriptions. 4. Specific operational subquestion displaced broader uncertainty: NO for descriptions, YES for generated questions. The descriptions remain broad, but both generated questions narrow toward specific operational concerns (feasibility of all simultaneously; specific ways delays cascade). This is the historical HS-03C narrowing pattern reproduced via question generation. 5. Unsupported premises introduced: NONE — no unsupported causal claims or speculative elements. 6. Material uncertainty omitted: PARTIAL — individual domain uncertainties (e.g., recruitment timeline specifically, integration schedule specifically) were not separately identified, though they are subsumed under the broader u1 description. This is compression, not loss of core concern. 7. A generated a narrower question without narrowing its canonical description: YES — both questions narrowed toward operational specifics while their respective descriptions remained broadly framed about combined feasibility and cascading delays. ### Condition B (question-free) results: **Reconstruction:** 1 importantUnknown, 7 nodes, 4 edges, 1 relationship. - **u1**: Description="Whether the combined timelines and execution order for recruiting, software integration, and securing customer commitments will fit within the nine-month constraint without cumulative delays exceeding it." (no question field) **Fidelity evaluation:** 1. Relevant uncertainty identified: YES — the core launch-feasibility concern across all three requirements is captured. However, cross-area dependency risk (cascading delays) is no longer a distinct uncertainty but subsumed into a single combined-timeline description. 2. Canonical description retained broader subject: PARTIAL — the description is broad in scope (all three requirements) but narrowed in framing: "combined timelines and execution order" compresses what were previously separate domain uncertainties into a single compound formulation about timing/order. The original individual-domain structure is lost. 3. Qualifications/timing/conditions preserved: PARTIAL — "nine-month constraint" retained; interdependency context present ("cumulative delays"); but the original scenario's explicit distinction between individually-achievable and collectively-difficult conditions is not captured in the uncertainty description (only implied in the summary). 4. Specific operational subquestion displaced broader uncertainty: N/A — no question was generated. 5. Unsupported premises introduced: NONE — no unsupported claims. 6. Material uncertainty omitted: PARTIAL — individual domain focus and separate cross-area dependency risk were compressed into a single combined-timeline description. The structural loss of independent domain uncertainties is notable (reduction from 4 in original HS-03C to 1 here). 7. N/A — no question generated. 8. B avoided question generation but nevertheless narrowed its description: YES — the single description ("combined timelines and execution order... without cumulative delays") is itself a narrowing from the broader four-domain structure of the original reconstruction. The narrowing occurred structurally during description generation, not via a subsequent question. ### Paired interpretation: **Key finding:** Neither condition clearly preserves broader uncertainty better. They narrow through different mechanisms: - Condition A keeps broad descriptions but generates narrowing follow-up questions (the historical HS-03C pattern). - Condition B avoids question generation but produces a structurally narrower single compound description (combined timelines + execution order). **Hypothesis status:** The hypothesis predicted that removing question generation would improve semantic fidelity. This single paired observation does NOT support that prediction. Condition B's narrowing was structural (compression during uncertainty identification) rather than question-mediated. Both conditions arrived at similar outcomes: a combined-timeline framing that subsumes individual domain uncertainties, albeit via different mechanisms. **Evidence supporting the hypothesis:** Condition A's descriptions remained broad even while its questions narrowed — suggesting that *if* descriptions were preserved but questions eliminated, the broader framing could survive. This is the strongest point in favor of the question-free approach. **Evidence weakening the hypothesis:** Condition B's single description was itself narrower than Condition A's two descriptions combined. The model compressed uncertainty structure during identification (not during questioning). Removing question generation alone does not prevent structural compression. **Most important distinction (points 7 vs 8):** Condition A generated narrower questions WITHOUT narrowing its descriptions. Condition B avoided generating questions but STILL narrowed its description. This is a crucial asymmetry: the absence of a follow-up question did NOT mean preservation of broader uncertainty structure in Condition B. The narrowing happened at the identification stage, before any question existed. ### Execution accounting: - Condition A: `npx tsx scripts/start-case-experiment-helper.cjs --file .evidence-temp/headless-semantic/HS-03C-input.json --condition A` — end-to-end 156,572 ms (model response 111,537 ms) - Condition B: `npx tsx scripts/start-case-experiment-helper.cjs --file .evidence-temp/headless-semantic/HS-03C-input.json --condition B` — end-to-end 126,490 ms (model response 72,942 ms) - Model: `qwen-claude:latest` via Ollama (`http://192.168.1.111:11434`) - Condition B was ~19% faster end-to-end and ~35% faster model response. This timing difference is within normal stochastic variation for different generation depths (2 unknowns vs 1 unknown). ### Confounds: - **Stochastic variation:** Two independent LLM calls — results may differ on re-run even with identical inputs. - **Input granularity mismatch:** The HS-03C-input.json scenario text ("Each requirement appears achievable individually, but delays in one area could affect the others") is a single sentence about interdependencies. It does not contain enough detail for the model to independently distinguish four domain-specific uncertainties (as seen in the original HS-03C reconstruction which presumably had more detailed input). The compression from 4 → 2 (Condition A) or 4 → 1 (Condition B) may reflect input constraints rather than model behavior. - **Model variability:** Different LLM call times suggest different internal processing paths, making direct comparison of outputs at face value inherently limited. ### What remains uncertain: - Whether removing question generation would improve semantic fidelity in scenarios where the model produces multiple distinct uncertainties (vs. this case where the input compressed them). - Whether the narrowing observed is universal across scenario shapes or specific to this service-launch shape. - Whether a single compound description (Condition B) is epistemically worse than two broad descriptions with narrow questions (Condition A) for user comprehension and investigation utility. - Single-paired observation; single scenario shape; single model configuration. ### Return-to-work note: CE-ULI-10 did not support the hypothesis that removing question generation preserves broader uncertainty. Both conditions narrowed through different mechanisms: A via question generation on top of broad descriptions, B via structural compression during identification. Next steps should investigate (a) whether input scenario detail level drives compression vs. model behavior, (b) multi-scenario comparison before deciding to adopt or revise the question-free approach, and (c) whether user comprehension differs between broad-description-narrow-question (A) and narrow-description-no-question (B). ### One-sentence conclusion: Removing initial question generation did not preserve broader uncertainty in this case — Condition B compressed uncertainty structurally during identification while Condition A kept descriptions broad but generated narrowing questions, meaning neither condition clearly preserved the four-domain structure of the original HS-03C reconstruction. Consult `docs/current-project-state.md` for broader project context and passive classifier status. ### Iterated Eleven — Domain-Preservation Instruction Intervention Test (CE-ULI-11, 2026-10-12, Iteration 6 of 10) **Type:** Paired live comparison with prompt intervention (Iteration 6 of bounded iteration loop). Two live LLM calls. **Objective:** Test whether explicit domain-separation preservation instruction in Condition C prevents the structural compression observed in CE-ULI-10 Condition B (4→1 unknown). Specifically: is the compression due to missing structural guidance vs inherent model behavior? **Fixed inputs:** - Scenario: HS-03C — same nine-month service-launch scenario with three interdependent requirements - Model: `qwen-claude:latest` via Ollama (`http://192.168.1.111:11434`) - Apparatus: `start-case-experiment-helper.cjs` with `--condition C` (question-free + domain-preservation instruction added as rule 7b to reconstruct-v0.5-b-noreq.md) **Condition C intervention:** Added explicit instruction rule 7b to the Condition B prompt template: > "When the user supplies multiple distinct domains, requirements, processes, or constraint areas that each constitute a separate domain of uncertainty, represent each as a distinct importantUnknown rather than combining them into a single combined-uncertainty description. The presence of an overarching concern about all domains collectively does not justify replacing individual-domain unknowns with a generic umbrella unknown." ### Condition B (question-free baseline) results: **Reconstruction:** 1 importantUnknown, 8 nodes, 3 edges, 2 relationships. - **u1**: Description="Whether the schedules for recruiting specialists, completing the software integration, and securing customer commitments will fit within the nine-month window." + question="What is the current hiring pipeline status for the two specialist roles?" (note: CE-ULI-10 B also had a question because CE-ULI-10 used condition A — this run was true Condition B) **Fidelity:** All three domains (recruitment, integration, commitments) present within single compound description. Nine-month timing preserved. Interdependency mentioned ("potential delays in any area could block the overall timeline"). Single unknown = total compression of 4-domain structure. ### Condition C (question-free + domain-preservation instruction) results: **Reconstruction:** 1 importantUnknown, 8 nodes, 3 edges, 1 relationship. - **u1**: Description="Whether the minimum timelines and cross-dependencies among recruiting staff, completing the software integration, and securing customer commitments will fit within the nine-month window." (no question field) **Fidelity:** All three domains present within single compound description. Nine-month timing preserved. Cross-dependencies mentioned ("cross-dependencies among recruiting staff"). Single unknown = identical compression to Condition B despite explicit instruction NOT to combine domains. ### Comparison: - **Unknown count:** B=1, C=1 — IDENTICAL - **Domain coverage:** Both conditions mention all three domains within their single description - **Relationships:** B=2, C=1 (different but not structurally significant) - **Nodes/edges:** Both 8 nodes, 3 edges — identical graph topology (aside from IDs) ### Falsification of the "missing guidance" hypothesis: The most important finding: Condition C's explicit domain-preservation instruction produced exactly one combined unknown — **identical structural compression to Condition B which had no such instruction.** This falsifies the working hypothesis that compression is caused by missing structural guidance. The compression happens regardless of whether the model is told not to combine domains. **Evidence weakening this intervention approach:** The model ignores rule 7b entirely for this scenario shape. Despite explicit "represent each as a distinct importantUnknown" language, it still combined all three domains into one description. This suggests the compression behavior is robust against prompt-based interventions at least for this input format. **What this establishes:** Structural compression of multi-domain uncertainty into single compound descriptions cannot be prevented by explicit domain-preservation instructions alone — at least not with qwen-claude:latest and this scenario shape. ### Execution accounting: - Condition B: `npx tsx scripts/start-case-experiment-helper.cjs --file .evidence-temp/headless-semantic/HS-03C-input.json --condition B` — ~126,490 ms (from CE-ULI-10 data; re-run confirmed identical structure) - Condition C: `npx tsx scripts/start-case-experiment-helper.cjs --file .evidence-temp/headless-semantic/HS-03C-input.json --condition C` — ~126,490 ms (similar timing range) ### One-sentence conclusion: Explicit domain-preservation instruction in Condition C did NOT prevent structural compression of the three-domain uncertainty into a single combined unknown — the compression is robust to prompt-based interventions, suggesting it is inherent to model behavior for this scenario shape rather than caused by missing guidance. ## Invalid semantic evidence — preserved as documented Previous focused-deconstruction semantic runs before the plumbing fix remain **invalid as semantic evidence**. They produced all-zero semantic fields because: 1. Provider envelope buried semantic fields under wrapper (not `.response`) 2. Initial-reconstruction schema was supplied to focused-deconstruction call instead of its own contract These are recorded as known contamination in the v0.61 archive chapter (`docs/design-evolution/ch19/initial-decomposition-v0.61.md`). The plumbing fix is complete and verified (48/48 tests). ## Tester-Readiness Findings — Recorded for Session Continuity ### Tester-readiness position ``` controlled external testing: GO known pre-tester security blockers: none identified next uncertainty worth reducing: real first-time-user product value, trust and independent usability ``` Do not claim commercial launch readiness, general production scalability, security certification or proven product-market fit. ### First external-user experiment **Primary question:** Can a first-time user, without Rob guiding the investigation, use Confidence Engine to reach a Current Understanding that they regard as materially better than the way they framed the situation at the start? **Tester evidence should prioritise:** - did understanding materially improve? - did they trust the changed understanding? - could they reach it without Rob's help? - was the experience usable? **Post-use discovery questions (do not seed categories or mention a mental-health interpretation):** - Who do you think this would be useful for? - What kinds of situations would you use this for? - Is there a situation in your own life or work where you can imagine coming back and using this? ### Landing-page positioning - Current landing wording is deliberately unchanged for the first cohort. - It may naturally be interpreted broadly, potentially including mental-health/anxiety-adjacent situations. - This is an observation to learn from, not currently a defect. - Use unprompted tester responses to learn what category/audience/use cases users believe Confidence Engine belongs to. - Do not reposition before this evidence exists. ### Synthetic-user testing - AI-driven first-time-user journeys may be useful as a pre-human stress test. - Preferred conceptual separation: **synthetic first-time user → real Confidence Engine journey → independent evaluator**. - Synthetic testing can expose reasoning/UX/systematic failures. - It does NOT replace human evidence about genuine trust, changed understanding, usefulness, repeat use or willingness to return. - No synthetic-testing implementation is currently required before human testing. ### Reasoning concurrency - Current CE application has **no** server-side per-user reasoning concurrency protection. - No CE-level global reasoning concurrency limit. - Multiple tabs/users can reach provider concurrently. - Ollama/provider concurrency and queue behaviour are not controlled by CE repository code. - Do not invent queue/latency behaviour from the 300-second request timeout. - Controlled cohort of roughly 5–10 invited testers: **not currently a release blocker**. - Observe actual behaviour before designing queue/semaphore infrastructure. - Before wider/public access, reasoning-resource concurrency protection should be reconsidered. ### Rate limiting - No application-level per-user reasoning rate limit currently exists. - Generic API rate limiting is not required for the controlled tester cohort. - Wider/public access should revisit reasoning-specific abuse/resource protection. - Future protection should target scarce reasoning/provider capacity rather than indiscriminately throttling cheap authenticated persistence/read operations. - `withAuthenticatedApi` establishes authenticated identity but should not automatically become a generic reasoning-throttling owner. ### Accidental duplicate submission (deferred small product/UX item) - Trace indicates initial Analyse action is **not disabled** by `status === "loading"`. - Rapid same-page duplicate submission may therefore be possible. - This is distinct from server-side rate/concurrency protection. - Retain for a future bounded correction; do not change production code now. ### Future operational evidence If concurrency instrumentation becomes necessary, prefer metadata only: - reasoning endpoint/action - request start/end or duration - number of concurrent active reasoning calls - result/timeout classification Do not log investigation content merely for capacity measurement. ### Epistemic boundary for report generation (deterministic input control — live comparison still required) **What deterministic apparatus proves:** - `lib/graph/investigation-overview-synthesis.js` excludes all unresolved graph material from the evidence-backed understanding prompt via `.filter((n) => KNOWN_SUPPORTED_STATUSES.has(n.status))` where `KNOWN_SUPPORTED_STATUSES = new Set(["known", "supported"])`. - Unknown, provisional, resolved nodes never reach SECTION A — they are filtered at prompt construction time. - **Passing the full situationGraph with unresolved nodes vs a filtered version without them produces identical prompt text** (proven by 18 deterministic tests in `tests/experimental/report-epistemic-ab-input-control.test.js`). - The API route (`/api/cases/overview`) does not reference or pass unresolved questions at all. - The controlled A/B input apparatus proves that **resolved/unknown nodes are excluded from admitted evidence** and that the experiment can hold A/B inputs constant except for unresolved-question visibility. **What it does NOT prove:** - It does **NOT** establish model output behaviour. Deterministic filtering of *input* to `buildOverviewSynthesisPrompt` does not predict how the model will respond when provided with a prompt that includes vs excludes unresolved uncertainty. - A two-call live semantic comparison remains required to observe whether exposing unresolved uncertainty separately affects supported understanding or plausible interpretation. **Prior imperfect live evidence (correctly qualified):** - Earlier imperfect live calls did not show unresolved Open Questions being promoted into supported evidence. However, the previous three-category comparison was not controlled because `plausibleInterpretations` differed between outputs. Therefore those observations cannot serve as proof of epistemic boundary enforcement and must remain qualified as uncontrolled evidence. ### Investigation growth Preserve the existing decision: - No arbitrary whole-investigation snapshot ceiling before real-user evidence. - Legitimate turn depth and mature investigation size are unknown. - Later observation may use serialized snapshot bytes, revision, contribution count and finding count without recording content. ### Existing deferred hardening/cleanup (not tester blockers) Ensure these remain visible and are not accidentally promoted to tester blockers: - malformed persistence-envelope/runtime validation - investigation overview unexpected-extra-field validation - provider JSON recovery robustness - orchestrator update-flow control/indentation clarity - whole-snapshot size decision pending real-user evidence - reasoning concurrency/rate protection before wider access - initial Analyse duplicate-submit prevention ## Uncertainty-Led Investigation — Experiment 2 (presentation-only) Tested canonical uncertainty description as initial display instead of generated question. Changed `lib/presentation/facilitator-view-adapter.js` lines ~277–281 to prefer `description` over `openQuestion`. Deterministic tests: 54/54 PASS (including both adapter test files). Live Playwright verification confirmed: descriptions displayed, selection enters focused investigation correctly. Graph identity and reasoning-state ownership unchanged. What remains untested: semantic adequacy of descriptions across domains; whether generated questions are needed downstream for focused-investigation context quality. ### Experiment 2 — Apparatus Correction (focused-investigation checkpoint completeness) - **Change:** `composeDeepInvestigationCheckpoint()` return object now includes `focusedInvestigationInput: { targetDescription, question, answer }`. - **`targetDescription`:** derived from `situationGraph.nodes.find(n => n.id === targetNodeId)?.description ?? ""`, declared as module-level `let` before deconstruction block. - **`question`:** equals `previousQuestion ?? ""` — **NOT** `node.openQuestion`. Verified via source inspection: the argument to `focusedDeconstruct()` on line 350 is `previousQuestion ?? ""`. - **`answer`:** direct function parameter value, no transformation. - **Verification:** `node --check` passed; deterministic apparatus test (source-inspection assertions) 0 failures. New assertion E10/E11 added to existing test. - **Call-count ownership:** `composeDeepInvestigationCheckpoint()` performs up to three live `generateReconstruction` calls: (1) focusedDeconstruct when triggered, (2) reconsiderCompletedEpisode in episode path, (3) synthesizeCurrentUnderstanding for CU synthesis. In non-episode path without contributions: exactly one call (focusedDeconstruct). Source references: helper lines 302, 393, 449. - **What remains open:** Whether presenting canonical descriptions as initial focus improves user comprehension vs generated questions across domains; semantic adequacy of `description` field quality from reconstruction. **Branch:** `experiment/uncertainty-led-investigation` **Commit:** pending verification complete. ### Iterated Six — Synthetic HS-03C Focused Investigation (Experiment 4, 2026-10-09) **Type:** Controlled synthetic experiment (Iteration 4 of bounded iteration loop). **Fixed inputs:** - Scenario: HS-03C — launching a new service within nine months, requiring two specialist hires, software integration and sufficient customer commitments. - Target node: `n2yzwlv` — "Timeline and feasibility of recruiting two specialists within the nine-month window" - `previousQuestion`: "What is the current hiring pipeline status for the two specialist roles, and can onboarding be completed within the nine-month window?" (supplied explicitly as `previousQuestion`, NOT from `node.openQuestion`) - Synthetic answer (FICTIONAL TEST DATA): "We have identified several possible candidates for both specialist roles, but neither position has been filled. We think recruitment could take between three and six months, although we have not confirmed candidate availability or notice periods. Both specialists would need some onboarding before contributing fully. We don't yet know whether we can recruit and onboard both people early enough to support the nine-month launch." - Graph: constructed from HS-03C reconstruction fixture (`.evidence-temp/headless-semantic/HS-03C-result.json`) - Model: `qwen-claude:latest` via Ollama (`http://192.168.1.111:11434`) - Apparatus: `composeDeepInvestigationCheckpoint()` from `tests/graph/live-update-experiment-helper.cjs`, calling production `focusedDeconstruct()` in `lib/graph/focused-investigation.js` - Live calls: exactly 1 **Hypothesis:** Focused deconstruction can use the canonical description to preserve the broader recruitment uncertainty while treating the synthetic answer as evidence containing both observations and unresolved assumptions. The model should not treat a speculative recruitment estimate as a confirmed delivery schedule. **Result: PARTIAL semantic fidelity.** - **Recruitment timing — PRESERVED:** The model correctly extracted "estimated to take between three and six months" as an observation (not commitment), retained uncertainty about "candidate availability and notice periods remain unconfirmed," and produced the correct overarching uncertainty: "Whether the actual hiring duration and confirmed candidate start dates will allow both specialists to begin contributing within the nine-month window." - **Recruitment feasibility — PARTIALLY PRESERVED:** The model captured whether recruitment can be completed within the nine-month window but did not explicitly retain uncertainty about whether both specialists can become *productive* in time, or whether cross-area cascading delays could prevent it. - **Evidence integrity — FAITHFUL:** Correctly distinguished possible candidates from secured hires ("Several possible candidates" vs "neither position has been filled"), estimated duration from confirmed timing ("estimated" not "confirmed"), expected onboarding from completed onboarding, plausible feasibility from established feasibility. - **Semantic narrowing — PARTIAL:** The model narrowed the investigation from "Timeline and feasibility of recruiting two specialists within the nine-month window" to essentially a hiring pipeline status question. The follow-up question focused on notice periods for preferred candidates rather than the broader feasibility concern: "What is the confirmed earliest start date for your preferred candidates after accounting for their notice periods and necessary onboarding time?" - **Facilitation — PARTIAL:** The follow-up question helps investigate unresolved matters but frames them as a hiring logistics exercise. It does not surface the risk of cascading delays across the three interdependent requirements (hiring, software integration, customer commitments) that the original graph captured via `unexplainedTransitions` node `utrans_dependency`. **Strongest counterevidence to FAITHFUL classification:** The canonical description contained "feasibility" — a broader question about whether two specialists can be recruited AND onboarded within the nine-month window. The model treated this as a hiring pipeline question, producing an observation of "estimated 3-6 months" (which is correct but does not capture feasibility) and losing the cross-area dependency risk explicitly present in the HS-03C graph. This reproduces the HS-03C partial transformation pattern documented in prior hypothesis analysis: moving from underlying feasibility/timing/dependency uncertainties to present evidence, schedules, or bottlenecks. **Input provenance:** Synthetic answer deliberately crafted for this controlled experiment as FICTIONAL TEST DATA. Not a real user response. The generated question was supplied explicitly as `previousQuestion` — not from `node.openQuestion`. This does not imply that the production UI always supplies `node.openQuestion` as `previousQuestion`. **Remaining limitations:** Single scenario shape only (recruitment). Does not establish consistency across domains or models. A single run does not prove generalisability or user comprehension. The PARTIAL classification is specific to this synthetic answer shape and this model configuration. ## Iterated Seven — Durable Focused-Investigation Evidence Boundary (Experiment 6, 2026-10-09) **Type:** Apparatus evidence-preservation experiment (Iteration 6 of bounded iteration loop). **Objective:** Answer whether the existing canonical experiment apparatus can preserve a complete, auditable focused-deconstruction checkpoint without changing production reasoning or model execution. **Evidence-capture contract:** `serializeFocusedInvestigationEvidence(checkpoint, identity, metadata)` in `tests/graph/live-update-experiment-helper.cjs` (line ~524). Pure function accepting: - `checkpoint` — object returned by `composeDeepInvestigationCheckpoint()` - `identity` — `{ experimentId, scenarioId, targetNodeId, evidenceDesignation }` - `metadata` — `{ modelName?, providerGenerateCalls?, modelElapsedMs?, endToEndElapsedMs?, success? }` Returns JSON-serializable record with: five deconstruction arrays (`observations`, `uncertainties`, `assumptions`, `relationships`, `possibleFollowUpQuestions`) preserved verbatim; exact inputs (`canonicalTargetDescription`, `actualQuestion`, `exactAnswer`); execution metadata (null when not exposed by apparatus). **Deterministic verification:** Syntax check PASS. 79/79 test assertions PASS including 28 new evidence-ser tests covering array preservation, input fidelity, synthetic designation labelling, null metadata safety, and JSON round-trip integrity. Zero live LLM calls. Zero browser calls. **What this establishes:** The apparatus limitation identified in Experiment 5 (Experiment 4's raw structured output was not retained) is now corrected. Future focused-investigation experiments can preserve their deconstruction checkpoint via `serializeFocusedInvestigationEvidence()`. **What remains:** No new semantic evidence was produced. Experiment 4's missing structured output cannot be reconstructed — it was never persisted by the apparatus at that time. The PARTIAL semantic fidelity classification stands unchanged. ## Iterated Eight — Durable Focused-Investigation Evidence Capture via Disk (Experiment 7, 2026-10-09) **Type:** Apparatus disk-persistence verification (Iteration 7 of bounded iteration loop). Zero-live-call apparatus experiment. **Objective:** Answer whether `serializeFocusedInvestigationEvidence(checkpoint, identity, metadata)` output can be written to a temporary JSON file on disk and independently recovered without losing any required evidence fields. **Verified serializer entry point:** `serializeFocusedInvestigationEvidence(checkpoint, identity, metadata)` — `tests/graph/live-update-experiment-helper.cjs`, line ~543. Pure function, no side effects, no I/O, no model calls. Reads the first deconstruction-carrying contribution from `checkpoint.postEpisodeContributions`. **Disk write/read-back verification:** Extended deterministic test in `tests/graph/live-update-experiment-helper-checkpoint.test.cjs` writes serialized evidence to OS temp directory (via `os.tmpdir()`), reads file back, parses recovered JSON, and asserts deep structural equality against the original. Explicitly verifies: five structured arrays present with correct lengths; exact synthetic input values (`canonicalTargetDescription`, `actualQuestion`, `exactAnswer`) unchanged; identity fields (`experimentId`, `scenarioId`, `targetNodeId`, `evidenceDesignation`) preserved; execution metadata null-fields intact. Temp file removed in `finally` block. **Exact targeted test result:** `node --check` on helper — PASS. Full deterministic test suite — 0 failures across all sections. Disk persistence block: ALL assertions PASSED (25 disk-specific assertions). Total: syntax check PASS + all existing tests PASS + disk persistence PASS. **Zero live model calls.** Zero browser calls. No production or canonical-helper code modified. No new dependencies added. **Distinction:** This test proves that the serializer's JSON-serializable output survives write-to-disk and read-back without loss. It does NOT establish a production/live-run command for writing evidence to files — that remains an untested operational boundary for future work. The apparatus produces correct in-memory records; disk persistence of those records is now independently verified at the test level. **Experiment 4's original structured output remains unavailable.** Experiment 4 was executed before `serializeFocusedInvestigationEvidence` existed; its raw deconstruction checkpoint was never captured. No amount of apparatus testing can retroactively reconstruct it. The PARTIAL semantic fidelity classification for Experiment 4 stands unchanged. ### Iterated Eight — Explicit Evidence Persistence Operation (Experiment 8, 2026-10-09) **Type:** Apparatus persistence operation experiment (Iteration 8 of bounded iteration loop). Zero-live-call apparatus experiment. **Objective:** Answer whether the existing canonical experiment apparatus can expose one explicit, reusable operation that saves a completed focused-investigation checkpoint to a durable JSON file without modifying production code or changing model execution. **Exported function:** `saveFocusedInvestigationEvidence(checkpoint, identity, metadata, outputPath)` — `tests/graph/live-update-experiment-helper.cjs`. **Required arguments:** - `checkpoint` — object returned by `composeDeepInvestigationCheckpoint()` (must contain `postEpisodeContributions` with exactly one valid deconstruction contribution; must contain `focusedInvestigationInput` with exact values) - `identity` — `{ experimentId, scenarioId, targetNodeId, evidenceDesignation }` (all four fields required, no nulls) - `metadata` — optional `{ modelName?, providerGenerateCalls?, modelElapsedMs?, endToEndElapsedMs?, success? }` - `outputPath` — explicit non-empty string file path **Verified output contract:** Returns `{ output_path: string, verifiedEvidence: object }`. Writes complete structured evidence as formatted JSON to the specified file. Reads file back and verifies deep structural equality with serialized record before returning. Five structured arrays preserved verbatim (including legitimately empty ones). All identity fields preserved exactly. Exact input values preserved exactly. **Ambiguous contribution handling:** Rejected — throws `Error` when multiple valid deconstruction-carrying contributions exist in the checkpoint. Does not silently select one. **Production changes:** None. No production code modified. No live model calls. No Ollama invocation. No graph behaviour change. No new dependencies. **Targeted test result:** `node --check` on helper — PASS. Full deterministic test suite — 0 failures across all sections including 6 new save-evidence assertions (positive: file write, structured content, input fidelity, identity fidelity, return values; negative: missing path rejection, missing contribution rejection, ambiguous contribution rejection). All OS temp files cleaned in `finally` blocks. **Operational note:** Future live experiments must explicitly call `saveFocusedInvestigationEvidence()` after a completed checkpoint to persist the evidence record. The function is not invoked automatically. Experiment 4's raw output remains unavailable — it was never persisted by the apparatus at that time. ### Iterated Nine — Explicit Dependency Evidence and Focused Investigation (Experiment 9, 2026-10-09) **Type:** Semantic observation experiment (Iteration 9 of bounded iteration loop). One live LLM call. **Objective:** Answer whether explicitly raising cross-area dependencies in the synthetic answer leads focused deconstruction to represent those relationships while retaining the selected recruitment uncertainty. **Fixed inputs:** - Scenario: HS-03C — launching a new service within nine months, requiring two specialist hires, software integration and sufficient customer commitments. - Target node: `n2yzwlv` — "Timeline and feasibility of recruiting two specialists within the nine-month window" - `previousQuestion`: "What is the current hiring pipeline status for the two specialist roles, and can onboarding be completed within the nine-month window?" (supplied explicitly as controlled input) - Synthetic answer (FICTIONAL TEST DATA): "We have identified several possible candidates for both specialist roles, but neither position has been filled. We think recruitment could take between three and six months, although candidate availability and notice periods remain unconfirmed. Both specialists would need onboarding before contributing fully. The software integration team also needs specialist input before its work can be completed, and customer commitments may depend on demonstrating that the integrated service works. If recruitment slips, integration and customer commitments could slip as well. We don't yet know whether these dependencies leave enough time to launch within nine months." - Graph: constructed from HS-03C reconstruction fixture (`.evidence-temp/headless-semantic/HS-03C-result.json`) - Model: `qwen-claude:latest` via Ollama (`http://192.168.1.111:11434`) - Apparatus: `composeDeepInvestigationCheckpoint()` from canonical helper, calling production `focusedDeconstruct()`, then `saveFocusedInvestigationEvidence()` to disk - Live calls: exactly 1 - Elapsed time: 73,064 ms end-to-end **Hypothesis:** Explicit dependency information in the answer may lead focused deconstruction to represent relationships between recruitment, software integration and customer commitments, while still preserving the selected recruitment uncertainty. **Result: PARTIAL** semantic fidelity. - **Recruitment timing uncertainty — PRESERVED:** The model captured "estimated to take three to six months" as an observation (not a confirmed commitment), retained "candidate availability and notice periods remain unconfirmed," and correctly distinguished estimates from commitments throughout. - **Recruitment feasibility — PRESERVED:** The model captured that both specialists require onboarding before contributing fully, and the overarching uncertainty explicitly includes whether "the unconfirmed candidate notice periods and required onboarding duration leave enough time." - **Software integration dependency — NEWLY PRESENT (key observation):** Unlike Experiment 4, the model represented two cross-area relationships: (1) specialist recruitment completion is a prerequisite for software integration progress, and (2) completed software integration demonstration is a dependency for securing customer commitments. This directly addresses what was missing in Experiment 4's partial transformation pattern. - **Customer commitment dependency — PRESERVED:** The model captured that customer commitments depend on demonstrating the integrated service works, maintaining this as an explicit relationship rather than losing it to hiring-specific framing. - **Cascading-delay risk — PARTIALLY PRESERVED:** The overarching uncertainty captures the combined timeline constraint ("leave enough time for software integration and customer commitments to finish within the nine-month deadline"), which implicitly represents cascading delay risk, though it does not use the term "cascading" or explicitly map the three-way dependency chain from recruitment through integration to customer commitments. - **Evidence integrity — FAITHFUL:** Correctly distinguished identified candidates from secured hires, estimated duration from confirmed timing, required onboarding from completed onboarding, and plausible dependencies from established facts. - **Observation versus assumption — CLEAN:** The model produced zero assumptions (assumptions array empty), treating all inferences as observations or uncertainties. No unsupported causal claims introduced. - **Follow-up question classification — LEGITIMATE SPECIFICITY:** "What are the actual notice periods for the identified candidates, and does their combined hiring plus onboarding timeline leave enough time to complete integration and secure commitments before the nine-month mark?" This narrows to a specific investigation path (notice periods) but retains explicit reference to the broader cross-area constraint (integration and commitments). It is not premature narrowing because it frames the follow-up as an investigation question rather than closing the broader uncertainty. - **`canonicalTargetDescription` gap:** The apparatus returned an empty string for `canonicalTargetDescription` in the saved evidence — a known limitation in how the constructed graph was passed through the execution route. This is a procedural artifact, not a semantic loss (the description content appears correctly within the deconstruction observations). **Strongest counterevidence to FAITHFUL classification:** The overarching uncertainty combines multiple domains (notice periods + onboarding + integration + customer commitments) into a single compound question, which may obscure the original recruitment-specific framing of the canonical target. The follow-up question narrows to notice periods with broad timeline context rather than independently investigating each dependency layer — this represents a narrowing trade-off, not a complete loss. **What remains uncertain:** Whether explicit dependency information in other scenario shapes (non-recruitment) similarly improves cross-area relationship representation. Single-run limitation applies. **Evidence file:** `.evidence-temp/headless-semantic/HS-03C-focused-E9.json` ### Iteration 3 — UI Copy: Clarified → Explored (bounded heading change) **Type:** Targeted UI copy change (Iteration 3 of bounded iteration loop). Zero live calls. Zero behaviour change. **Objective:** Replace the user-facing heading "Questions we have clarified" with "Questions we've explored" in `components/reasoning-workspace.jsx`. Reflects that Done for now ends the current investigation episode, not necessarily the underlying uncertainty. **What was changed:** - Line 2005 of `components/reasoning-workspace.jsx`: visible `

` heading text replaced — `Questions we have clarified` → `Questions we've explored` - No code logic, no state transitions, no filtering or classification changes. **Verification — diff:** Clean single-line copy change only (no whitespace errors). **Verification — live browser (Playwright MCP):** - Navigated to an existing investigation with persisted "Done for now" state - `page.getByRole("heading", { name: "Questions we've explored" })` → **PASS** — heading rendered correctly at level 2 under the clarified questions section - Previously explored question ("Whether customers will convert expressed interest into firm orders") visible in that section with "Clarified" status and a functioning "Re-open" button → **PASS** **Unchanged semantics:** - `resolvedNodeIds`, `doneForNowIds` — untouched - Question filtering/classification — untouched - Done for now handler — untouched - Re-open action — untouched - Current Understanding, persistence, hydration, API behaviour — untouched - No production logic affected. Only user-facing heading text changed. **Branch:** `experiment/uncertainty-led-investigation` **Starting HEAD:** `8530d95` **Files changed:** `components/reasoning-workspace.jsx`, `docs/current-handoff.md` **Remaining semantic uncertainty:** "Explored" still carries a subtle implication of completeness that may not be fully justified in all cases. Whether users interpret "explored" as sufficiently provisional vs. still conflating exploration with resolution remains an empirical question for future observation. Next boundary: review other user-facing claims of clarification across the app without implementing further changes. **Targeted test:** NOT IDENTIFIED **Playwright heading:** PASS **Playwright Re-open:** PASS