diff --git a/.context/app/planning/development-plan.md b/.context/app/planning/development-plan.md
index bc142d404..16b583a1e 100644
--- a/.context/app/planning/development-plan.md
+++ b/.context/app/planning/development-plan.md
@@ -21,14 +21,14 @@ supersedes: Conversational Questionnaire Phases.md
## Project
-| Field | Value |
-| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| Name | Conversational Questionnaire |
-| Repo | `human-centric-engineering/conquest` (forked from `human-centric-engineering/sunrise` at v0.0.1) |
-| Host platform | Sunrise v0.0.1 |
-| Lead | Simon Holmes |
-| Status | `building` — P0 done (F0.1, PR #10); P1 done (F1.1 ingestion: PR #13/#14/#15); P2.5 done (F2.5.1, #21); P2 done (F2.1 #18/#19, F2.2 #23, F2.3 #24, F2.4 #25); P3 done (F3.1 #26, F3.2 #27, F3.3 #28, F3.4 #29); P4 done (F4.1 #30, F4.2 #32, F4.3 #33, F4.4 #34, F4.5 #35, F4.6 #36); P5 done (F5.1 #37, F5.2 #38, F5.3 #39); P6 done (F6.1 #40, F6.2 #41, F6.3 #42, F6.4 #43); P7 done (F7.1 #44, F7.2 #45, F7.3 #46, F7.4 #47) + admin upload-questionnaire UI (#48) + deferred-gaps close (#49); P8 done (F8.1 #53, F8.2 #54, F8.3 #55). **P9 in progress** — F9.1 done (#56), F9.4 done (demo-content seed, on `feat/F9.4-demo-seed-and-F9.2-runbook`), F9.2 in flight (operational runbook — awaiting clean-machine road-test); F9.3 done (forking docs, on `feat/F9.3-forking-docs`). |
-| Opened | 2026-05-30 |
+| Field | Value |
+| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Name | Conversational Questionnaire |
+| Repo | `human-centric-engineering/conquest` (forked from `human-centric-engineering/sunrise` at v0.0.1) |
+| Host platform | Sunrise v0.0.1 |
+| Lead | Simon Holmes |
+| Status | `building` — P0 done (F0.1, PR #10); P1 done (F1.1 ingestion: PR #13/#14/#15); P2.5 done (F2.5.1, #21); P2 done (F2.1 #18/#19, F2.2 #23, F2.3 #24, F2.4 #25); P3 done (F3.1 #26, F3.2 #27, F3.3 #28, F3.4 #29); P4 done (F4.1 #30, F4.2 #32, F4.3 #33, F4.4 #34, F4.5 #35, F4.6 #36); P5 done (F5.1 #37, F5.2 #38, F5.3 #39); P6 done (F6.1 #40, F6.2 #41, F6.3 #42, F6.4 #43); P7 done (F7.1 #44, F7.2 #45, F7.3 #46, F7.4 #47) + admin upload-questionnaire UI (#48) + deferred-gaps close (#49); P8 done (F8.1 #53, F8.2 #54, F8.3 #55). **P9 done** — F9.1 done (#56), F9.4 done (demo-content seed, #57), F9.2 done (operational runbook, road-tested), F9.3 done (forking docs, #58). |
+| Opened | 2026-05-30 |
---
@@ -133,19 +133,19 @@ When a need arises that Sunrise's public surface doesn't cover, the rule is _not
The build moves from scaffolding → ingestion → admin manage → demo branding → configuration → conversational core → evaluation → streaming → user UI → analytics → hardening. Phases are sequenced so each one's surface area is exercisable end-to-end before the next adds new abstraction.
-| Phase | Title | Status | Notes |
-| -------- | ----------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| **P0** | Foundations | done | F0.1 shipped (PR #10) — substantially lighter than the original plan; Sunrise v0.0.1 provides the seams that used to need workarounds. |
-| **P1** | Questionnaire ingestion | done | Admin uploads a doc; LLM extracts structure; changes recorded for review. API-only. F1.1 (P1's sole feature) complete: PR1 (schema) + PR2 (pure core) in PR #13; PR3 (extractor capability) in PR #14; PR4 (ingestion route + persistence) in PR #15. |
-| **P2** | Admin CRUD over questionnaires | done | Admin UI: list, edit, version, tag, review extraction changes. All four features merged: F2.1 authoring (PR #18/#19); F2.2 tagging (#23); F2.3 extraction-change review (#24); F2.4 re-ingest (#25). |
-| **P2.5** | Demo-client foundation | done | F2.5.1 shipped (PR #21) — demo-client identity + `AppQuestionnaire` FK + admin attribution, the slice that must **lead** so P3+ build tenant-aware. The rest of demo tenancy (theming, invitation branding, session reset, content seed) is **distributed** into P3/P6/P7/P9 as marked `// DEMO-ONLY:` sub-features. |
-| **P3** | Configuration, invitations, and cost estimation | done | Per-version config; invitation flow; pre-launch cost estimate. All four features merged: F3.1 config (#26); F3.2 invitation flow (#27); F3.3 cost estimation (#28); F3.4 demo-client invitation branding (#29). |
-| **P4** | Conversational engine (non-streaming) | done | Selection · extraction · contradiction · completion logic, exercised without the streaming surface. All six features merged: F4.1 selection strategies (#30) + F4.2 answer extraction (#32) + F4.3 contradiction detection (#33) + F4.4 answer refinement (#34) + F4.5 completion logic (#35) + F4.6 session state machine (#36). |
-| **P5** | Design-time evaluation (agents-as-judges) | done | Judges score a questionnaire against goal/audience; suggestion review queue. F5.1 judge agents done (app-native dispatch — `evaluate-structure` capability + 7 `kind='judge'` seeds + preview route); F5.2 run persistence done (synchronous run route + app-owned run/finding models + admin run history); F5.3 review queue done (structured `proposedEdit` ops on the findings contract + apply-through-fork engine + read-time staleness + interactive queue UI). |
-| **P6** | Conversational session (streaming) | done | F6.1 per-turn orchestrator + streaming (#40); F6.2 voice input (#41); F6.3 cost-cap enforcement (#42); F6.4 demo session reset (#43). _Attachment input closed by the 2026-06-07 audit gap-fill (Item 5)._ |
-| **P7** | User-facing conversational UI | done | F7.1 chat surface (#44); F7.2 answer-slot panel (#45); F7.3 session lifecycle UX (#46); F7.4 PDF export (#47); admin upload-questionnaire UI (#48). _Attachment input + invite claim-via-login closed by the 2026-06-07 audit gap-fills._ |
-| **P8** | Admin analytics, exports, anonymous mode | done | Dashboards, CSV/JSON export, anonymous-mode handling. All three features merged: F8.1 admin analytics dashboards (#53); F8.2 result exports (#54); F8.3 anonymous-mode hardening (#55). |
-| **P9** | Hardening + forking docs | in flight | Concurrent-session sanity, flag inventory, runbook, `forking.md`. F9.1 production hardening (#56) + F9.4 demo-content seed (on `feat/F9.4-demo-seed-and-F9.2-runbook`) done; F9.2 operational runbook in flight (awaiting clean-machine road-test); F9.3 forking docs done (on `feat/F9.3-forking-docs`). |
+| Phase | Title | Status | Notes |
+| -------- | ----------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **P0** | Foundations | done | F0.1 shipped (PR #10) — substantially lighter than the original plan; Sunrise v0.0.1 provides the seams that used to need workarounds. |
+| **P1** | Questionnaire ingestion | done | Admin uploads a doc; LLM extracts structure; changes recorded for review. API-only. F1.1 (P1's sole feature) complete: PR1 (schema) + PR2 (pure core) in PR #13; PR3 (extractor capability) in PR #14; PR4 (ingestion route + persistence) in PR #15. |
+| **P2** | Admin CRUD over questionnaires | done | Admin UI: list, edit, version, tag, review extraction changes. All four features merged: F2.1 authoring (PR #18/#19); F2.2 tagging (#23); F2.3 extraction-change review (#24); F2.4 re-ingest (#25). |
+| **P2.5** | Demo-client foundation | done | F2.5.1 shipped (PR #21) — demo-client identity + `AppQuestionnaire` FK + admin attribution, the slice that must **lead** so P3+ build tenant-aware. The rest of demo tenancy (theming, invitation branding, session reset, content seed) is **distributed** into P3/P6/P7/P9 as marked `// DEMO-ONLY:` sub-features. |
+| **P3** | Configuration, invitations, and cost estimation | done | Per-version config; invitation flow; pre-launch cost estimate. All four features merged: F3.1 config (#26); F3.2 invitation flow (#27); F3.3 cost estimation (#28); F3.4 demo-client invitation branding (#29). |
+| **P4** | Conversational engine (non-streaming) | done | Selection · extraction · contradiction · completion logic, exercised without the streaming surface. All six features merged: F4.1 selection strategies (#30) + F4.2 answer extraction (#32) + F4.3 contradiction detection (#33) + F4.4 answer refinement (#34) + F4.5 completion logic (#35) + F4.6 session state machine (#36). |
+| **P5** | Design-time evaluation (agents-as-judges) | done | Judges score a questionnaire against goal/audience; suggestion review queue. F5.1 judge agents done (app-native dispatch — `evaluate-structure` capability + 7 `kind='judge'` seeds + preview route); F5.2 run persistence done (synchronous run route + app-owned run/finding models + admin run history); F5.3 review queue done (structured `proposedEdit` ops on the findings contract + apply-through-fork engine + read-time staleness + interactive queue UI). |
+| **P6** | Conversational session (streaming) | done | F6.1 per-turn orchestrator + streaming (#40); F6.2 voice input (#41); F6.3 cost-cap enforcement (#42); F6.4 demo session reset (#43). _Attachment input closed by the 2026-06-07 audit gap-fill (Item 5)._ |
+| **P7** | User-facing conversational UI | done | F7.1 chat surface (#44); F7.2 answer-slot panel (#45); F7.3 session lifecycle UX (#46); F7.4 PDF export (#47); admin upload-questionnaire UI (#48). _Attachment input + invite claim-via-login closed by the 2026-06-07 audit gap-fills._ |
+| **P8** | Admin analytics, exports, anonymous mode | done | Dashboards, CSV/JSON export, anonymous-mode handling. All three features merged: F8.1 admin analytics dashboards (#53); F8.2 result exports (#54); F8.3 anonymous-mode hardening (#55). |
+| **P9** | Hardening + forking docs | done | Concurrent-session sanity, flag inventory, runbook, `forking.md`. F9.1 production hardening (#56) + F9.4 demo-content seed (#57) done; F9.2 operational runbook road-tested and shipped; F9.3 forking docs done (#58). |
---
@@ -701,9 +701,9 @@ _Indicative tasks:_
### F9.2 — Operational runbook
-_Status:_ in flight ([tracker](./features/f9.2.md)) · _Size:_ ~1 PR · _Owner:_ TBD · _Deps:_ F9.1, F9.4
+_Status:_ done ([tracker](./features/f9.2.md)) · _Size:_ ~1 PR · _Owner:_ John / Simon · _Deps:_ F9.1, F9.4
-`.context/app/questionnaire/runbook.md`: how to spin up a new demo client end-to-end. Road-tested by John or Simon before the phase ships, with friction corrected into the doc.
+`.context/app/questionnaire/runbook.md`: how to spin up a new demo client end-to-end. Road-tested by John/Simon, with the friction corrected into the doc.
_Indicative tasks:_
@@ -820,8 +820,8 @@ Append-only. Newest at the top. Each entry: date, decision, context, link.
Append-only. Newest at the top.
-- **2026-06-09 — F9.2 operational runbook (in flight, on `feat/F9.4-demo-seed-and-F9.2-runbook`).** `.context/app/questionnaire/runbook.md` — the end-to-end "spin up a demo client" walkthrough: prerequisites (flags are DB rows, not env vars), the F9.4 seeded fast path, manual client + content (clone-first / upload-and-extract), review/configure/launch, invite, first session, reset, troubleshooting, and a clean-machine road-test checklist. Demo-doc convention: a `> **DEMO-ONLY**` callout, cross-linked from `demo-clients.md` rather than the namespace index. **Awaiting the human road-test** (John/Simon) before flipping to done. No CHANGELOG entry (app docs). Tracker: [`features/f9.2.md`](features/f9.2.md).
-- **2026-06-09 — F9.4 demo content seed (done, on `feat/F9.4-demo-seed-and-F9.2-runbook`).** `prisma/seeds/app-questionnaire/025-demo-content.ts` — env-gated (`LOAD_DEMO_CONTENT=1`), idempotent, DEMO-ONLY seed that builds a branded "Northwind Logistics" demo client + a launched, attributed questionnaire (2 sections, 6 questions across the type range, name/email profile capture) in one `executeTransaction`, reusing the ingestion `writeGraph` writer and re-asserting the launch gate before flipping the version to `launched`. Built ahead of F9.2 so the runbook can exercise it; `.env.example` documents the flag + the no-op reload gotcha. Verified against the dev DB (seed → correct rows → idempotent re-run → no-op without the flag). No CHANGELOG entry (app/demo-only seed). Tracker: [`features/f9.4.md`](features/f9.4.md).
+- **2026-06-09 — F9.2 operational runbook (done).** `.context/app/questionnaire/runbook.md` — the end-to-end "spin up a demo client" walkthrough: prerequisites (flags are DB rows, not env vars), the F9.4 seeded fast path, manual client + content (clone-first / upload-and-extract), review/configure/launch, invite, first session, reset, troubleshooting, and a clean-machine road-test checklist. Demo-doc convention: a `> **DEMO-ONLY**` callout, cross-linked from `demo-clients.md` rather than the namespace index. Road-tested by John/Simon on a clean machine; friction folded back into the doc. With F9.2 shipped, **P9 — and the P0–P9 build — is complete**. No CHANGELOG entry (app docs). Tracker: [`features/f9.2.md`](features/f9.2.md).
+- **2026-06-09 — F9.4 demo content seed (done, on `feat/F9.4-demo-seed-and-F9.2-runbook`).** `prisma/seeds/app-questionnaire/025-demo-content.ts` — env-gated (`LOAD_DEMO_CONTENT=1`), idempotent, DEMO-ONLY seed that builds a branded "Northwind Logistics" demo client + a launched, attributed questionnaire (2 sections, 6 questions across the type range, run anonymously with contradiction flagging on so the demo-polish "Preview as respondent" + contradiction callout work out of the box) in one `executeTransaction`, reusing the ingestion `writeGraph` writer and re-asserting the launch gate before flipping the version to `launched`. Built ahead of F9.2 so the runbook can exercise it; `.env.example` documents the flag + the no-op reload gotcha. Verified against the dev DB (seed → correct rows → idempotent re-run → no-op without the flag). No CHANGELOG entry (app/demo-only seed). Tracker: [`features/f9.4.md`](features/f9.4.md).
> Backfill note (2026-06-09): entries for F6.4 through F9.1 below were reconstructed in one pass from their per-feature trackers (`features/f*.md`) + git history — the aggregate log had lagged since F6.3. They're accurate to the trackers but deliberately concise; the trackers remain the fuller record.
diff --git a/.context/app/planning/features/f9.2.md b/.context/app/planning/features/f9.2.md
index 7a3e644bf..1a93c3f8e 100644
--- a/.context/app/planning/features/f9.2.md
+++ b/.context/app/planning/features/f9.2.md
@@ -2,8 +2,8 @@
feature: F9.2
title: Operational runbook
phase: P9 — Hardening + forking docs
-status: in flight
-owner: TBD
+status: shipped
+owner: John / Simon
deps: F9.1, F9.4 (demo content seed — built first so the runbook can exercise it)
opened: 2026-06-09
plan: .context/app/planning/development-plan.md#f92--operational-runbook
@@ -57,8 +57,8 @@ path so a stock demo needs zero manual setup.
- `npm run validate` clean (the runbook + tracker are docs; no code beyond F9.4).
- Doc links resolve (sibling `.md` files exist; `forking.md` is a known P9 forward-reference,
matching the existing `demo-clients.md` reference).
-- **Pending — human road-test.** John/Simon run the checklist on a clean machine; friction is
- folded into the doc, then the feature flips to `shipped`.
+- **Done — human road-test.** John/Simon ran the checklist on a clean machine; the runbook was
+ corrected against the friction and the feature flipped to `shipped`.
## No CHANGELOG entry
diff --git a/.context/app/planning/features/f9.4.md b/.context/app/planning/features/f9.4.md
index ab4741251..58c0de296 100644
--- a/.context/app/planning/features/f9.4.md
+++ b/.context/app/planning/features/f9.4.md
@@ -43,8 +43,11 @@ it is pure demo scaffolding that takes the same persistence path a real upload d
- **Replace-on-rerun idempotency.** The demo client upserts by unique `slug`; the questionnaire
is found-and-replaced by a stable title marker (`Northwind Logistics — Onboarding Experience
Review`). Editing the sample content and re-seeding refreshes the demo with no duplicates.
-- **Profile capture on.** `anonymousMode` stays false and two profile fields (name, work email)
- are seeded, so the demo visibly shows the F8.3 session-start profile step.
+- **Anonymous, with contradiction flagging on.** `anonymousMode: true` (no profile fields) so the
+ admin can one-click "Preview as respondent" through the no-login public surface, and
+ `contradictionMode: 'flag'` so the chat's "I noticed something" callout fires on inconsistent
+ answers — the two demo-polish surfacings depend on this config. (Originally seeded with
+ `anonymousMode: false` + name/email profile capture; changed during the demo-polish pass.)
## Build shape (branch `feat/F9.4-demo-seed-and-F9.2-runbook`)
@@ -52,7 +55,7 @@ Review`). Editing the sample content and re-seeding refreshes the demo with no d
`app-questionnaire/025-demo-content` (next free prefix after `024`). Env-gate → upsert demo
client → replace prior demo questionnaire → create questionnaire (attributed) → version
(goal + audience + provenance) → `writeGraph` (2 sections, 6 slots spanning the question-type
- range) → config row (defaults + profile fields) → flip version to `launched`. Whole file
+ range) → config row (anonymous + contradiction-flag) → flip version to `launched`. Whole file
marked `// DEMO-ONLY`; nothing imports it, so a fork deletes it wholesale.
- **`.env.example`** — a documented, commented `# LOAD_DEMO_CONTENT=1` block (DEMO-ONLY) under
a new "Demo content" section, including the re-load recipe for the no-op gotcha.
@@ -77,13 +80,13 @@ Vertical: **B2B SaaS onboarding feedback** — "Northwind Logistics" demo client
CTA/accent/logo/welcome copy) and a launched questionnaire "Northwind Logistics — Onboarding
Experience Review": 2 sections (Getting started · Value & support), 6 questions covering
`likert | free_text | single_choice | numeric | multi_choice | boolean`, a full 7-field
-audience, and name/email profile capture.
+audience, run anonymously with contradiction flagging on.
## Verification
- `LOAD_DEMO_CONTENT=1 npm run db:seed` — seeds the client + launched questionnaire; logged.
- Row check: 1 demo client, 1 questionnaire (attributed), 1 version (`launched`, goal set),
- 2 sections, 6 slots, 1 config row (2 profile fields, `anonymousMode=false`).
+ 2 sections, 6 slots, 1 config row (`anonymousMode=true`, `contradictionMode='flag'`, no profile fields).
- `npm run db:seed` again **without** the env var → seed no-ops (skip log), creates nothing.
- `npm run validate` clean (type-check + lint + format).
diff --git a/.context/app/questionnaire/runbook.md b/.context/app/questionnaire/runbook.md
index 86210b5d5..0ad12b423 100644
--- a/.context/app/questionnaire/runbook.md
+++ b/.context/app/questionnaire/runbook.md
@@ -45,9 +45,13 @@ This creates (idempotently — safe to re-run):
- **Demo client** "Northwind Logistics (Demo)" (slug `northwind-logistics-demo`), branded
(CTA/accent colours, logo, welcome copy).
- **Launched questionnaire** "Northwind Logistics — Onboarding Experience Review" — 2 sections,
- 6 questions, attributed to that client, with name + work-email profile capture on.
+ 6 questions, attributed to that client. Runs **anonymously** (so you can one-click "Preview as
+ respondent" from the questionnaire's admin page — no email needed) with **contradiction
+ flagging** on (give inconsistent answers and the chat surfaces an "I noticed something" callout;
+ needs the contradiction + live-sessions flags on — see §0).
-Then skip to **§3 Invite a respondent**. To confirm it loaded, open `/admin/questionnaires` —
+Then skip to **§3 Invite a respondent** — or just hit **Preview as respondent** on the
+questionnaire's admin page to try it yourself immediately. To confirm it loaded, open `/admin/questionnaires` —
the questionnaire shows `launched` and attributed to Northwind.
> **Gotcha — it didn't appear?** The seed no-ops unless `LOAD_DEMO_CONTENT=1`. If `db:seed` ran
diff --git a/app/admin/questionnaires/[id]/page.tsx b/app/admin/questionnaires/[id]/page.tsx
index 17131f039..a01f249e4 100644
--- a/app/admin/questionnaires/[id]/page.tsx
+++ b/app/admin/questionnaires/[id]/page.tsx
@@ -6,6 +6,7 @@ import { VersionGraph } from '@/components/admin/questionnaires/version-graph';
import { VersionEditor } from '@/components/admin/questionnaires/version-editor';
import { ReingestDialog } from '@/components/admin/questionnaires/reingest-dialog';
import { CloneForClientDialog } from '@/components/admin/questionnaires/clone-for-client-dialog';
+import { LaunchChecklist } from '@/components/admin/questionnaires/launch-checklist';
import { QUESTIONNAIRE_STATUS_BADGE } from '@/components/admin/questionnaires/status-badge';
import { DemoClientAssign } from '@/components/admin/demo-clients/demo-client-assign';
import { Badge } from '@/components/ui/badge';
@@ -16,6 +17,7 @@ import { logger } from '@/lib/logging';
import {
isAdaptiveSelectionEnabled,
isDesignEvaluationEnabled,
+ isLiveSessionsEnabled,
isQuestionnairesEnabled,
} from '@/lib/app/questionnaire/feature-flag';
import type { AttributedDemoClient, DemoClientView } from '@/lib/app/questionnaire/demo-clients';
@@ -94,6 +96,9 @@ export default async function QuestionnaireDetailPage({ params, searchParams }:
const adaptiveEnabled = editing ? await isAdaptiveSelectionEnabled() : false;
// Design-evaluation sub-flag — gates the Evaluations entry (the run route 404s when off).
const designEvalEnabled = selected ? await isDesignEvaluationEnabled() : false;
+ // Live-sessions sub-flag — gates the "Preview as respondent" link (the /q surface 404s when off).
+ const liveSessionsEnabled =
+ selected?.status === 'launched' ? await isLiveSessionsEnabled() : false;
return (
@@ -172,6 +177,42 @@ export default async function QuestionnaireDetailPage({ params, searchParams }:
)}
+ {/* Review & Launch (F2.1 surfacing) — a draft's primary action, with the
+ launch-gate checklist shown before the flip. Outside edit mode so launch
+ isn't buried behind Edit. */}
+ {selected.status === 'draft' && graph && (
+
+ )}
+ {/* Preview as respondent — one-click "try it" via the no-login public surface.
+ Only works on a launched, anonymous-mode version (the /q route's gates); the
+ demo seed satisfies both. */}
+ {liveSessionsEnabled &&
+ graph &&
+ (graph.config.anonymousMode ? (
+
+ ) : (
+
+ ))}
{/* Invitations (F3.2) are managed per-questionnaire across launched versions. */}