Cover image for I validated the product with the actual user across 7 sessions before scaffolding production

I validated the product with the actual user across 7 sessions before scaffolding production


June 02, 2026

Cover image for I validated the product with the actual user across 7 sessions before scaffolding production
Timeline of 7 validation sessions across 6 weeks: Sessions 1-6 per-screen, Session 7 task-based, v1 scope locked

I'm setting up a screen-share with my friend. She runs a private therapy practice and has been managing everything in a Google Sheet for years. The sixteen spec documents are done. The prototypes are rendered. This is the first time she's seeing any of it.

The question isn't whether she'll recognize what I've built. The question is whether the design matches how she actually works. There's a long gap between "based on what she told me in interviews" and "based on watching her hands."

Session 1 is about to answer that question.

Per-screen, one session at a time

The format for Sessions 1 through 6: one static prototype per session, one screen per walkthrough. Patient management, session registration, payment tracking, invoicing, the waitlist, the schedule. Six sessions, six screens, structured walkthroughs with a script written in Spanish.

Each session runs off a walkthrough script organized into sections mapped to specific user stories, each with questions, probes, and hypothesis tests. The script tells me what to ask. Her answers tell me what the spec missed.

Session 1 opens with the patient management screen. I'm expecting confirmation. What I get instead is a finding that invalidates a core assumption in the data model.

Her spreadsheet uses a naming convention throughout: two names, the second inside parentheses. I had analyzed this pattern for months. My model said it was couples data, two patients encoded together in a single name field because the spreadsheet offered no better way.

She explains it in the first fifteen minutes.

The first name in the row is always whoever should receive the invoice. The name inside the parentheses is the actual patient. She developed this workaround because the spreadsheet doesn't separate billing identity from patient identity. It applies to parents paying for their children in therapy, family members covering costs for patients living abroad, anyone where the invoice should go to a different name than the person who came in.

Five years of operational data encoded this way. The parentheses aren't a couples signal. They're a billing-recipient workaround. The domain model, the migration plan, and several acceptance criteria had this wrong.

That's the first fifteen minutes of Session 1.

The pattern continues across Sessions 2 through 6. The payment tracking screen surfaces the most structurally load-bearing set of findings. What I had modeled as a payment_method field and a payment_status field turns out to be something closer to a per-session payment ledger: a session might involve cash, a bank transfer, a confirmed transfer still waiting on the bank deposit, a split between two methods with the amounts tracked in a notes column, or a partial payment with the balance still outstanding. Each variant has its own visual encoding in the spreadsheet, using cell colors as a status system she's built and maintained across fifty monthly tabs.

The data model had to change. The migration script had to change. The payment UI had to change. By the time Session 6 closes, the design is significantly different from what the spec docs described in February.

The synthesis problem

After each session I have a recording, a transcript, and impressions that are vivid immediately and gone within 48 hours.

The impressions are the dangerous part. The important material is in specific quotes at specific moments in the walkthrough, not in the overall feeling of the conversation. "She seemed a bit uncertain about the invoicing screen" is useless six weeks later. The verbatim quote and the exact hypothesis it was testing are what matter.

The manual version of the post-session process: re-read the transcript, map each statement to a user story, flag which assumptions changed, write proposed edits to the spec files, capture anything that didn't come up for the next session. A 45-minute session takes a full day to process carefully.

I built a Claude Code skill for this.

The skill runs a seven-step debrief pipeline on each session transcript.

The validation-session-debrief 7-step pipeline: transcript in, structured artifacts out, with proposals-before-writes at every step that changes a file

Step 1 produces a structured bloque summary: a narrative in English that preserves the original Spanish quotes verbatim, organized by the user stories covered in that session.

Step 2 fills a per-bloque session notes template, with a field for each story's hypothesis, what she said, what she didn't address.

Step 3 surfaces proposed insight deltas: new pain points, workflows, and design considerations identified in the session, each tagged with a build-implication flag (yes, no, maybe). This step always surfaces proposals first and waits for explicit approval before writing anything to the insights database.

Step 4 proposes spec amendments: specific edits to the user stories file, the UI requirements doc, the domain model, or any other spec file the session touched. Again: proposals surface, I approve, then the files change.

Step 5 handles anything that doesn't have a clear build implication but needs to be remembered: open questions, things she said she'd think about, probes that didn't land.

The autonomy boundary is the core design decision. Any step that writes to a canonical file (the insights database, the specs, the build queue) stops and surfaces a proposal. I do the judgment pass. The AI does the synthesis pass. This isn't a small distinction. Carla's actual words, mapped to the correct user story, with the correct interpretation — that's what makes the output usable six months later.

What used to take a full day takes about an hour.

What accumulated across six sessions

Six sessions, six screens, six debrief cycles. The insights database went from thirty pain points identified in discovery to forty-six total: sixteen new ones that only surfaced because I was watching her use the design rather than asking her about her workflow.

Seven new workflow patterns documented. Forty-one new design considerations added. Every finding traced back to a verbatim quote at a specific point in a specific session.

Some of the findings were small: a label she read differently than I intended, an expected state that wasn't there. Some were structural, and those compounded across sessions as the debrief skill cross-referenced prior findings and caught confirmations.

Session 7: the integrated test

Sessions 1 through 6 are per-screen static prototypes. Session 7 is different.

I've built a navigable integrated prototype: Vite + React, ~8,500 lines, 12 routes. The same screens, now connected. She can move between them. Session 7's format switches from bloques to tasks: seven things she might actually do, with no explanation of which screen to use or how to get there.

The first task: open your day. Tell me what you have today, what you have tomorrow, and how the month is going.

She opens the dashboard. Reads the agenda widget first. Reads the pending payments widget. Then she lands on a stat tile labeled "Cobrado este mes" — collected this month.

She's quiet for a moment.

"The number there is only what's been paid. But what I need to see is what I worked."

She says it again, more precisely: if she's owed a certain amount, then the real number for the month is the sum of all sessions she's conducted, not the sum of what's landed in her account. She's been using her spreadsheet for years, and what she looks at in the morning is the total count of work done for the month, whether paid or not. The stat tile she'd been looking at showed her something different.

She says it a third time and gives the math: if I've done X sessions and I'm owed Y, then what I've earned this month is X + Y. The tile should say "ganado este mes" (earned this month), not "cobrado este mes."

Three articulations of the same thing, each more precise. That's the signal that something needs to change, not a UI preference but a model problem.

That finding reshaped the dashboard tile, the monthly report surface, and how the back-end aggregation counts sessions for reporting.

Task 4 is a patient lookup. She finds the patient's most recent session in the dashboard table directly, without navigating anywhere, which I hadn't anticipated. Then she immediately probes the harder case: "What if that session had been older, outside this window? What would I do then?"

She tries the search bar in the top navigation. It's a decorative placeholder in the prototype: visible, styled correctly, but not wired to anything yet. She types, hits a dead end, and looks for another route.

That's a soft fail. The feature is planned and in the spec. But a placeholder that looks functional and isn't costs trust, and her spontaneous attempt at it is exactly the kind of demand signal that should move something up the build queue.

The question at the end

Session 7 closes with two questions.

"Of everything you did today, was anything harder than using your spreadsheet?"

Her answer: the app isn't difficult. What's difficult is switching from something I've used for fifteen years. That's the friction. Not the design.

"If the app were ready tomorrow and you had to switch, what would make you hesitate?"

Her answer: nothing.

That answer is what the validation phase was built to produce. Not "this is great" — she's been using her spreadsheet for years and it works. But zero structural objections is a different signal than "it looks okay." It means the case for switching is there. The fit is real. The path to adoption is clear.

v1 scope locks the next day.

Across 7 sessions over roughly six weeks: 16 new pain points I hadn't found in discovery, 7 new workflow observations, 41+ new design considerations. The debrief skill processed each session into amendments that traced back to specific quotes. The code running now reflects all of it.

The upfront cost wasn't small. The downstream cost of not doing it would have been higher.


#BuildInPublic #ClaudeCode #AIEngineering #AIAgenticEngineer