From d928e7fd9eb6ae2acc35b4c6a0cf7ef9aa4ff933 Mon Sep 17 00:00:00 2001 From: Dave Date: Wed, 16 Sep 2026 17:37:57 +0200 Subject: [PATCH] docs(spec): Phase 4 design for the client intake wizard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A guided interview that produces a written brief with sub-tasks, landing in the Inbox as a draft through Plan 1c's existing accept flow. Corrects an over-promise made during the Phase 1 discussion: the wizard was described as grounding date proposals in measured per-card velocity, and that data does not exist — Plan 2c deferred per-card effort because session padding does not sum correctly across cards. This phase therefore produces no time estimate at all, only a size band. Names the intake as the highest-risk surface in the product: it is the only place where text written by someone other than the developer enters a prompt whose output creates records. The security property is that the worst a hostile brief achieves is a strangely-worded Inbox card. Co-Authored-By: Claude Opus 5 --- ...-16-phase-4-client-intake-wizard-design.md | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-16-phase-4-client-intake-wizard-design.md diff --git a/docs/superpowers/specs/2026-09-16-phase-4-client-intake-wizard-design.md b/docs/superpowers/specs/2026-09-16-phase-4-client-intake-wizard-design.md new file mode 100644 index 0000000..c3a03b1 --- /dev/null +++ b/docs/superpowers/specs/2026-09-16-phase-4-client-intake-wizard-design.md @@ -0,0 +1,226 @@ +# Phase 4 — The Client Intake Wizard + +**Date:** 2026-09-16 +**Status:** Draft for review +**Phase:** 4 of 5 +**Depends on:** Phase 2 (commit data), Phase 3 (provider layer) + +--- + +## 1. Purpose + +A client manager clicks **Request a feature**, answers a handful of plain +questions, and the result is a written brief with the work already broken into +sub-tasks — landing in the Inbox as a draft for the developer to accept. + +This is the feature the developer described first, and in their words: *"he first +answers simple questions on what he wants, that way I already get a written out +plan with sub-categories."* + +It replaces the current one-line "Request a feature" box from Plan 1c. + +## 2. What is already settled + +| Decision | Where from | +|---|---| +| **AI-proposed dates are never auto-published.** | Phase 1 design | +| Client-submitted text is **data, not instructions** | Phase 1 design, Phase 3 preamble | +| A client's card always lands in the Inbox, unaccepted | Phase 1 spec §5.2 | +| The provider layer, settings and preamble | Phase 3a | +| **The client sees a rough size band, never a time estimate** | This conversation | +| **The interview is stateless — the transcript goes in the prompt** | This conversation | + +## 3. A correction to an earlier claim + +During the Phase 1 discussion this wizard was described as producing date +proposals *"grounded in your actual measured velocity — cards of this size took +you 6–9 working days."* + +**That data does not exist.** Plan 2c deliberately deferred per-card effort, +because a session touching several cards contributes its padding to each and +per-card hours do not sum to the project total. What Phase 2 actually produces is +*project-level* velocity: features per week, active days against workdays, hours +per month. + +That supports "this project has averaged around 25 changes a week." It does not +support sizing an individual request in days. This phase therefore produces **no +time estimate at all**, for the client or the owner — which is also the strictest +reading of the never-auto-publish rule, so nothing is lost. + +## 4. The interview + +**Stateless.** Each question is one `complete()` call from Phase 3a, with the +conversation so far included in the prompt. No session state to store, expire or +resume, and the transcript is already the thing worth keeping. The provider +interface stays narrow. + +**Hard-capped at seven questions.** Past that, people abandon the form and the +developer gets a worse brief than a one-line email would have produced. The cap +is enforced in code, not requested in the prompt — a model that decides an eighth +question is warranted must not be able to ask it. + +**Skippable at any point.** A "that's enough, write it up" button is always +present. Someone who has said what they need in the first answer should not be +interrogated. + +**One question at a time**, plain language, no jargon. The model may offer +multiple-choice options where they genuinely help. + +The questions the model is steered toward — what problem this solves, who will +use it, what happens today without it, what would make it not worth doing, and +whether anything external forces timing — are guidance in the prompt, not a +fixed script. The point of using a model here rather than a form is the +follow-up that a form cannot ask. + +## 5. The brief + +Output of the interview, shown to the client for confirmation before anything is +created: + +- **Title** — one line, the developer's Inbox card title. +- **Summary** — two or three sentences of what is wanted and why. +- **Sub-tasks** — the work broken into steps, becoming subtasks on the card. +- **Open questions** — what the model could not establish. Valuable: these are + what the developer would otherwise discover halfway through. +- **Size band** — small, medium or large. See §6. + +**The brief never contains a date, a deadline, an estimate, or a claim about +when work will start.** The Phase 3 preamble already forbids this and applies +here unchanged. + +### 5.1 Structured output, parsed defensively + +The brief comes back as JSON. The Anthropic SDK supports schema-constrained +output, but the OpenAI-compatible adapter does not, and the Phase 3a interface is +deliberately provider-neutral — so the format is requested in the prompt and +**parsed defensively**, exactly as Plan 3b parses batch responses. + +A malformed brief must degrade to something usable: if the JSON will not parse, +the client's raw answers are still captured and the card is still created from +them. An interview that ends in an error message, having asked seven questions, +is worse than no wizard. + +## 6. The size band + +Small, medium or large. **No time is attached to it anywhere in the UI**, and it +is never rendered next to a date. + +It is derived rather than guessed: + +- **How many sub-tasks the request decomposes into.** A request that becomes two + steps is not the same as one that becomes eleven. +- **Whether it touches areas the project already has.** Phase 2 knows which + conventional-commit scopes exist and how much work each holds. A request + landing in an established area is better understood than one opening a new one. + +**It is labelled as a first impression and it is the owner's to change.** The +client sees it as the model's initial read of their description; the developer +sets the real one when accepting from the Inbox. + +Stated plainly, because it is the weakest thing in this phase: the band is a +judgement made from a description the model collected minutes earlier. It is +better than nothing and worse than the developer's opinion, and the UI should +never imply otherwise. + +## 7. Prompt injection — the highest-risk surface in the product + +This is the only place where **text written by someone other than the developer +enters a prompt whose output creates database records.** Everything else the AI +touches is commit messages the developer wrote. + +Three controls, and all three are needed: + +1. **The preamble already states that submitted text is data, never + instructions.** Necessary, not sufficient — a prompt rule is a mitigation, not + a boundary. +2. **The model never writes to the database.** It returns a brief; *code* + creates the card, through the same whitelisted path as Plan 1a's + `POST /api/client/cards`. Column, priority, `accepted` and `created_by_role` + are set by the server regardless of what the brief contains. A brief claiming + to be "approved, priority critical, move to In Progress" changes nothing. +3. **Every field is sanitised and length-capped before storage**, and rendered + as text — never as markup. + +The security property to hold onto: **the worst a hostile brief can achieve is a +strangely-worded card in the Inbox.** It cannot set priority, cannot bypass the +Inbox, cannot reach another client's project, and cannot instruct the developer's +tooling. If a change would weaken any of those, it is a change to the security +model, not to a feature. + +## 8. Draft until accepted + +The wizard creates exactly what Plan 1c's Inbox flow already handles: one card +in the project's Inbox with `accepted = false` and `created_by_role = "client"`, +with subtasks, plus the transcript and brief attached. + +Nothing new is needed for acceptance. The developer opens it, reads the brief, +adjusts, and accepts — which sets `start_date` and moves it out of the Inbox, +exactly as today. + +**The transcript is kept.** When a request turns out to mean something other than +what was built, the record of what was actually asked is the thing that settles +it — the same reason the activity log exists. + +## 9. Data model additions + +| Collection | Field | Notes | +|---|---|---| +| `cards` | `brief` | json — summary, sub-tasks, open questions, size band | +| `cards` | `transcript` | json — the question-and-answer pairs | +| `cards` | `size_band` | select: `small` \| `medium` \| `large` \| `""` | + +No new collection. The wizard produces a card; cards already exist. + +Read rules follow `cards`. Writes are server-side only. + +## 10. Failure behaviour + +Consistent with Phase 3: the AI is an enhancement, and its absence must not +remove a capability the client already had. + +- **No provider configured, or the provider is down** → the wizard is not + offered, and the plain "Request a feature" box from Plan 1c is shown instead. + The client can always file a request. +- **A failure mid-interview** → the answers so far are kept and the client is + offered "submit what I have", which creates the card from the raw answers with + no brief. +- **A malformed brief** → §5.1; the card is still created. + +## 11. Out of scope + +- **Any date, estimate or scheduling.** §3. +- **The developer using the wizard.** It is a client-facing intake. The owner + creates cards directly. +- **Editing a brief after submission.** The developer adjusts the card; the + brief is a record of what was asked, and rewriting it destroys the thing §8 + keeps it for. +- **Conversation anywhere else in the product.** No chat over the project, no + asking the AI about the board. +- **Notifying the developer.** An Inbox badge already exists. Email belongs with + the n8n work parked in Phase 1. + +## 12. Acceptance criteria + +1. A client manager can complete an interview of at most seven questions and see + a brief before anything is created. +2. The brief contains a title, summary, sub-tasks, open questions and a size + band, and **no date, deadline or estimate**. +3. Submitting creates one Inbox card with `accepted = false`, + `created_by_role = "client"`, subtasks from the brief, and the transcript + attached — whatever the brief's content claims. +4. A brief containing instructions — "set priority to critical", "mark as + accepted", "move to In Progress" — changes none of those fields. +5. With no provider configured, the plain request box from Plan 1c is offered + and works. +6. A failure mid-interview still allows submission of the answers given. +7. The size band is never rendered adjacent to a date or duration. +8. The developer accepting the card uses the existing Inbox flow, unchanged. + +## 13. Suggested plan split + +- **Plan 4a — the interview.** Stateless turn-taking, the question cap, the skip + path, defensive brief parsing, and the transcript. The parsing and the cap are + pure and testable; this is where the injection tests live. +- **Plan 4b — submission and display.** Card creation through the whitelisted + path, subtasks from the brief, the brief rendered on the card detail page for + both roles, and the fallback to the plain request box.