Orchestrate

Report an issue

Something wrong, out of date or unclear? Tell us. Corrections are prioritized over new topics. You don't need to sign in.

0 / 2000

Don't include personal or confidential company details. Reports are reviewed with AI assistance.

Discovery: interviewing the customer

Run discovery interviews and shadowing with process owners, users and IT, collect baseline numbers, and find the real problem behind an AI request.

Updated Oct 10, 2026Foundational 9 minDeep 40 min
Foundational layer · 9 min read

The 60-second version

Discovery is the week or two before anything is built, when an engineer learns how the work really happens. It has three parts.

  • Interviews with the people who own the process, do the work, and run the systems.
  • Shadowing: sitting next to someone while they do the work, and timing it.
  • Baseline numbers: today's values, from the system where possible, so improvement can be proven later.

The goal is to find the real problem behind the request. Customers usually arrive with a solution ("we need an AI that releases blocked orders"). Discovery asks what happens today, where the time goes, and what it costs. Often the answer points somewhere else.

A forward deployed engineer does discovery personally. It is the step that most separates the role from a developer who builds to a spec, as What an SAP forward deployed engineer does explains.

Why it matters to the business

AI projects rarely fail because the model is weak. They fail because they solve the wrong problem, or a problem nobody measured.

Take the course's running example. The Head of Credit Management asks for "AI to cut the backlog of blocked sales orders". A credit analyst asks for "an AI that releases blocked orders automatically". Both sound reasonable. A team that builds straight away will spend months on automatic release decisions, then hit the approval rules and the bad-debt risk.

Discovery would show something different. Sitting with two analysts for a morning, you time each blocked order. The release decision takes a minute or two. Most of the time goes on gathering: opening several screens, adding up open items in a spreadsheet, and emailing a sales rep for the story behind a big order. Half the orders then wait an hour or more for a reply.

That changes the project. The valuable, low-risk first step is an assistant that gathers the facts and drafts a note, while the analyst still decides. It is cheaper, it respects the approval rules, and it can be measured against the hours orders spend blocked.

Discovery costs a week or two of an engineer's time and a few hours from each interviewee. Skipping it can cost the whole budget.

How SAP does it

SAP uses the word "discover" in several places. They do different jobs. As of October 2026:

  • SAP Activate. SAP's implementation method starts with a Discover phase. SAP Learning calls it a "non-committal phase" in which customers research SAP offerings and decide which innovations suit them. It is about exploring SAP, not about interviewing the users of one process. The later Explore phase runs fit-to-standard workshops and records gaps in a backlog.
  • Design-led development. SAP's Fiori design guidelines name interviews, surveys and shadowing as the research methods of the Discover phase, and say research should ideally happen in all three phases.
  • SAP AppHaus workshops. The Innovation Toolkit for AI offers four workshop formats. One, the Joule Agent Discovery Workshop, gathers 3 to 10 business and IT people for two to three hours to find and rank agent use cases. It ends with a current and future process sketch for the top ideas.
  • SAP Signavio Process Insights, discovery edition. It analyzes one process flow from your SAP ERP data and suggests corrections and innovations. An SAP team blog says the analysis can be requested for free. SAP also sells an assessment service built on it, with a workshop with the process owner.

Use the workshops to find candidates and the process analytics for system numbers. Interviews and shadowing check both against what people really do.

A discovery week at a glance

Day Who What you leave with
1 Sponsor and process owner The ask, the number they watch, who decides, what must not get worse
2 Two or three users, shadowed A timed log of real cases, workarounds, quotes
3 IT, SAP basis or integration, security Where the data lives, how it can be reached, who may see it
4 You, with an extract Baseline numbers from the system, compared with what people estimated
5 Everyone from days 1 to 3 A playback: what you saw, the problem you think matters most, the open questions

Five days is a guide, not a rule. A small process can take three days; a process across several countries can take three weeks. The order matters more than the length: hear the ask, watch the work, check the data, then play it back.

Questions to ask

Ask your team before discovery starts:

  • Who owns this process, who does the work, and who runs the systems? Have we booked time with each?
  • Can someone sit with users while they work? Do we need approval from HR or employee representatives?
  • Which numbers already exist in SAP or in process analytics, and who can pull them?

Ask a partner or vendor who proposes an AI project:

  • How many users did you watch working, and for how long?
  • Which baseline numbers come from the system, and which from estimates?
  • What did people ask for, and what did you find the real problem to be? Where did those differ?
  • What would make you recommend not using AI here?

Common misconceptions

  • "The customer told us what they need." They told you a solution. Discovery finds the problem it is meant to solve.
  • "A workshop is discovery." A workshop collects ideas from a room. Shadowing shows the work itself. You need both.
  • "Users' time estimates are good enough." People estimate their own work poorly. Time real cases, then compare.
  • "Discovery delays the project." It replaces months of building the wrong thing with a week of checking.
  • "SAP Activate's Discover phase covers this." That phase is about choosing SAP offerings. Process interviews are a separate job.
  • "Interviews are for consultants, not engineers." The engineer who will build the system hears constraints a handover would lose.

Key terms

All course terms, A to Z, in the glossary

  • Discovery: the time before building, spent learning how the process works today and what limits a solution.
  • Shadowing: watching someone do their real work, in their place, and noting each step and its time.
  • Contextual inquiry: a structured kind of shadowing in which the user is the expert and the researcher asks questions while the work happens.
  • Baseline: the value of a metric before any change, from a stated source and period.
  • Leading question: a question that suggests its own answer, such as "Wouldn't AI make this easier?"
  • Playback: a short session where you show interviewees what you heard and saw, so they can correct it.
  • Process owner: the person accountable for a business process and its results.

Check yourself

Pick one answer for each question. The explanation appears after you choose.

1A sales director asks for "an AI that releases blocked orders automatically". What should discovery treat this as?

Answer: D. Customers usually arrive with a solution. Discovery asks what happens today and what it costs. In the blocked-order example, the time went on gathering facts, not on the decision itself.

2What did shadowing show in the blocked-order example?

Answer: C. The decision took a minute or two. Gathering facts, spreadsheets and emails to sales reps took most of the time, and half the orders waited for a reply. That points to an assistant that gathers and drafts, while the analyst still decides.

3Your partner says their discovery was a two-hour ideation workshop with managers. What is missing?

Answer: D. A workshop collects ideas from a room. Shadowing shows how the work really happens, and system data checks the estimates. Both are needed before choosing what to build.

4How does SAP Activate's Discover phase relate to an FDE's discovery interviews?

Answer: C. SAP Learning describes Discover as a non-committal phase in which customers research SAP offerings and decide which innovations suit them. Interviewing the people in one process is a separate job.

5Users estimate a task takes 10 minutes. What should you do with that number?

Answer: C. People estimate their own work poorly, so an estimate is a starting point, not a baseline. Time real cases while shadowing and take numbers from the system where you can, then compare.

6Which question belongs in a vendor review of a proposed AI project?

Answer: D. The answer shows whether the proposal rests on observed work or on assumptions. Model choice comes later, after the problem and the baseline are clear.

7Why end a discovery week with a playback session?

Answer: B. A playback shows interviewees your findings and the problem you think matters most. They correct mistakes before anything is built, and they see their input was used.
Deep layer · 40 min read

Mental model

People tell you summaries. The work shows you details.

Ask a credit analyst how they handle a blocked order and you get a tidy answer: "I check the exposure and decide." Sit next to them and you see four screens, a spreadsheet, an email to a sales rep, an hour of waiting and a note typed twice. The contextual inquiry literature makes the same point: interview accounts are summaries, and people forget details or describe what they meant to do rather than what happened.

So discovery runs on three kinds of evidence, in rising order of trust:

Evidence Example Trust it for
Told "It takes about 10 minutes." What people care about, what hurts, the words they use
Seen Timed while shadowing: 17 minutes, most of it gathering How the work really happens, workarounds, hidden waits
System 19.7 hours median time blocked, from an SAP report Volumes, durations and trends over many cases

A finding is strong when two kinds agree. When "told" and "seen" disagree, you have found something worth asking about. The rest of this topic is about collecting each kind well and putting them side by side.

How it works

Before the first interview

  1. Write down the ask in the requester's words. "An AI that releases blocked orders automatically." You will compare it with what you find.
  2. List the roles. At least: the process owner (accountable for the result), two or three users (do the work), and IT (systems, data, access). Add security, a sponsor, or the people downstream, such as sales reps, when they are part of the process.
  3. Agree the ground rules. What you will note, that you will not record customer names, and whether you may watch real cases on screen. Screens show customer data, so check that the people watching are allowed to see it.
  4. Prepare questions, then check them. Leading questions suggest their answer. Nielsen Norman Group defines them as questions that include or imply the desired answer, and suggests neutral wording such as "What was easy or difficult about it?"

Interviewing: past specifics, not opinions

The most useful habit comes from Rob Fitzpatrick's The Mom Test: ask about specifics in the past instead of generics or opinions about the future. Its other two rules fit discovery too: talk about their life rather than your idea, and talk less.

Instead of Ask Why
"Would you use an AI that explains blocks?" "Walk me through the last blocked order you handled." People are optimistic about the future; the past already happened
"Don't you find the credit check frustrating?" "What was easy or difficult about the last one?" The first suggests the answer
"Do you check open items?" "What do you check that the system doesn't show you?" Yes/no questions end the story
"How long does it take, and who do you ask?" Two questions, one at a time People answer only the easier half

After each answer, three follow-ups do most of the work: "Can you show me?", "What happened next?" and "How often?"

Shadowing: the user is the expert

Contextual inquiry, from Hugh Beyer and Karen Holtzblatt's contextual design, frames shadowing as a master and an apprentice. The user does the work and explains it; you ask about what you see. Its four principles are context (watch the work where it happens), partnership (alternate between watching and asking), interpretation (say what you think a step means, and let the user correct you), and focus (know what you're looking for, but follow surprises).

For AI discovery, add a stopwatch. For each case, note every step, which tool it used, how long it took, and whether it was gathering information, deciding, recording the result, or waiting for someone. Waiting is elapsed time, not work, so keep it separate.

Collecting baseline numbers

A baseline needs a value, a source and a period. "Median 19.7 hours blocked, SAP report, last 8 weeks" is a baseline. "About a day" is a starting point.

Collect three things:

  1. The number the owner watches. Ask which report shows it and copy its definition.
  2. Volumes and durations from the system. An extract of last quarter's cases, approved by IT and the data owner. Defining success metrics with the business shows how to turn it into a metric agreement.
  3. Your own timings, from shadowing, for steps the system can't see: emails, phone calls, spreadsheets.

Write down every estimate you hear, with who said it. Comparing estimates with measurements is one of the fastest ways to find the real problem.

Spotting the real problem behind the request

Look for these signs:

  • The ask names a technology. "AI", "chatbot", "agent". The problem is somewhere underneath.
  • The pain is told by several roles and seen while shadowing. That is the strongest evidence you will get in a week.
  • Time sits in gathering or waiting, not deciding. Then automating the decision won't help much.
  • A workaround keeps appearing. A spreadsheet, a shared mailbox, a personal note. It marks what the system doesn't give people.
  • Something upstream causes the work. For example, credit limits nobody reviews create blocks that shouldn't happen. That is a master data problem, and maybe not an AI one.

Asking "why?" repeatedly helps you move from symptom to cause. Use it with care: the five whys method, which comes from Toyota, is criticized for stopping at symptoms, finding only causes the investigator already knows, and reducing several causes to one. Treat each answer as a hypothesis to check against what you saw and the data.

flowchart LR
  A[The ask] --> I[Interviews<br/>told]
  A --> S[Shadowing<br/>seen]
  A --> D[System data<br/>measured]
  I --> C{Compare}
  S --> C
  D --> C
  C --> H[Problem hypothesis]
  H --> P[Playback]
  P --> F[Problem framing]

The playback

End with a 30 to 45 minute session for everyone you interviewed. Show what you saw, the numbers, the themes ranked by evidence, and your working hypothesis. Ask what you got wrong. The playback corrects mistakes cheaply and gives people a reason to support what comes next. The next topic in Unit 14 turns the hypothesis into a framed problem with a metric, target and constraints.

Build it yourself: a discovery kit

You will build a small command-line tool for a discovery week. It prints interview guides for each role, checks your own questions for leading or hypothetical wording, summarizes a shadowing time log, and combines interview notes and timings into a one-page discovery summary. You will run it on made-up notes for the blocked-order example, then on your own.

Before you start: complete Set up your computer for this course and Set up for Unit 14. They create your orchestrate-course folder, its .venv and the unit14 folder. This script uses only Python's built-in modules, so there is nothing new to install.

flowchart LR
  G[guide] --> Q[check-questions]
  Q --> N[(notes/*.txt)]
  N --> Y[synthesize]
  T[(timelog.csv)] --> L[timelog]
  L --> Y
  Y --> M[discovery_summary.md]

What you need

  • Your course folder from the setup topics.
  • About 45 to 60 minutes.
  • No accounts and no cost. The sample notes and time log are made up.
  • Optional, for the Exercise: notes from a real conversation with someone about their work.

Step 1: Open your course folder

  1. Open VS Code, choose File > Open Folder, and open orchestrate-course.

  2. Open a terminal: Terminal > New Terminal.

  3. If the prompt doesn't start with (.venv), turn it on:

    • Windows (PowerShell):

      .venv\Scripts\Activate.ps1
    • macOS / Linux:

      source .venv/bin/activate
  4. If you don't have a unit14 folder yet, create it. The same command works in PowerShell and on macOS/Linux:

    mkdir unit14

Step 2: Create the script

  1. In VS Code, right-click the unit14 folder, choose New File, name it discovery_kit.py, paste the code below and save.
"""Unit 14: a discovery kit for AI use cases.

Four commands, used in the order of a discovery week:

  guide            print an interview guide for one role from the built-in question bank
  check-questions  flag leading, hypothetical, closed and solution-first questions in your own list
  timelog          summarize a shadowing time log: minutes per case and where the time goes
  synthesize       read interview notes and the time log, write discovery_summary.md

  sample           write made-up notes and a time log for the blocked-order example

Uses only Python's built-in modules. No account, no network.
"""
import argparse
import csv
import json
import re
import statistics
import sys
from collections import defaultdict
from pathlib import Path

HERE = Path(__file__).resolve().parent
DEFAULT_DIR = HERE / "discovery"

# ---------------------------------------------------------------------------
# 1. The question bank: (question, what it is for), per role
# ---------------------------------------------------------------------------
OPENING = [
    ("What does your role own in this process, from start to finish?", "context"),
    ("Walk me through the last time you handled one. What happened first?", "problem"),
]
CLOSING = [
    ("What should I have asked that I didn't?", "close"),
    ("Who else should I talk to, and may I sit with someone while they work?", "close"),
]
BANK = {
    "owner": [
        ("Which number tells you this process is going well or badly?", "baseline"),
        ("What was that number last month, and which report shows it?", "baseline"),
        ("Tell me about the last case that went wrong. What did it cost?", "problem"),
        ("What have you already tried to fix this, and what happened?", "problem"),
        ("Who decides whether a change here goes live?", "decision"),
        ("What must not get worse, whatever we change?", "constraint"),
    ],
    "user": [
        ("Walk me through the last order you worked on today, screen by screen.", "problem"),
        ("Where did you have to wait, or ask someone else?", "problem"),
        ("Which part of that took longest? Show me.", "baseline"),
        ("What do you check that the system doesn't show you?", "data"),
        ("What workarounds do you keep, such as spreadsheets, notes or emails?", "data"),
        ("Tell me about the last time you disagreed with a rule or a decision.", "constraint"),
    ],
    "it": [
        ("Where does the data for these steps live, system by system?", "data"),
        ("Which interfaces or released APIs already expose it?", "data"),
        ("Who may see this data today, and which authorizations control that?", "constraint"),
        ("What changes in this area are planned for the next year?", "constraint"),
        ("What would you need to see before something new connects to production?", "decision"),
        ("Who approves an extract of last quarter's cases, and how long does that take?", "baseline"),
    ],
}
ROLES = sorted(BANK)                       # roles every discovery should cover
KNOWN_ROLES = ROLES + ["security", "sponsor", "other"]


def show(path):
    """Print a path relative to the current folder when possible."""
    try:
        return str(path.resolve().relative_to(Path.cwd().resolve()))
    except ValueError:
        return str(path)

# ---------------------------------------------------------------------------
# 2. Question checks (heuristics, not grammar rules)
# ---------------------------------------------------------------------------
CHECKS = [
    ("leading", re.compile(r"\b(don't you|doesn't it|isn't it|wouldn't|aren't you|agree|how much (easier|better|faster)|frustrat)", re.I),
     "Suggests the answer. Ask neutrally, e.g. 'What was easy or difficult about it?'"),
    ("hypothetical", re.compile(r"^(would|will|if we|if you had|imagine)\b|\bwould you (use|pay|like|want)\b", re.I),
     "Asks about the future. Ask about the last time it happened instead."),
    ("solution-first", re.compile(r"\b(ai|chatbot|agent|copilot|automat\w*|machine learning)\b", re.I),
     "Talks about a solution. Ask about their work and the problem first."),
    ("closed", re.compile(r"^(do|does|did|is|are|was|were|can|could|have|has)\b", re.I),
     "Invites yes or no. Start with 'Walk me through', 'Tell me about' or 'How'."),
    ("double", re.compile(r"\?.*\?"),
     "Two questions in one. Split it."),
]


def check_question(text):
    """Return a list of (flag, advice) for one question."""
    return [(name, advice) for name, pattern, advice in CHECKS if pattern.search(text.strip())]


# ---------------------------------------------------------------------------
# 3. Reading notes and the time log
# ---------------------------------------------------------------------------
TAGS = {"WHO", "ROLE", "DATE", "ASK", "PAIN", "SAW", "NUM", "DATA", "RISK", "QUOTE"}
THEME = re.compile(r"#([a-z0-9-]+)")
NUM_LINE = re.compile(r"^([a-z0-9_]+)\s*=\s*([0-9.]+)\s*(?:\|\s*(.*))?$")


def read_note(path):
    """One interview: TAG: text lines. Unknown lines are kept as free text."""
    note = defaultdict(list)
    note["file"] = path.name
    for raw in path.read_text(encoding="utf-8").splitlines():
        line = raw.strip()
        if not line or line.startswith("//"):
            continue
        tag, sep, rest = line.partition(":")
        tag = tag.strip().upper()
        if sep and tag in TAGS:
            note[tag].append(rest.strip())
        else:
            note["TEXT"].append(line)
    return note


def read_timelog(path):
    need = {"session", "case", "step", "category", "minutes", "tool"}
    with path.open(newline="", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        missing = need - set(reader.fieldnames or [])
        if missing:
            sys.exit(f"{path.name} lacks columns: {', '.join(sorted(missing))}")
        rows = []
        for n, r in enumerate(reader, start=2):
            try:
                r["minutes"] = float(r["minutes"])
            except ValueError:
                sys.exit(f"{path.name} line {n}: minutes '{r['minutes']}' is not a number")
            r["category"] = r["category"].strip().lower()
            rows.append(r)
    return rows


def measure(rows):
    """Turn the shadowing log into numbers. 'wait' is elapsed time, not handling time."""
    per_case = defaultdict(float)
    wait_case = defaultdict(float)
    by_cat = defaultdict(float)
    by_tool = defaultdict(float)
    for r in rows:
        if r["category"] == "wait":
            wait_case[r["case"]] += r["minutes"]
            continue
        per_case[r["case"]] += r["minutes"]
        by_cat[r["category"]] += r["minutes"]
        by_tool[r["tool"]] += r["minutes"]
    handling = sum(by_cat.values())
    cases = sorted(set(per_case) | set(wait_case))
    waited = [c for c in cases if wait_case[c] > 0]
    return {
        "cases": len(cases),
        "sessions": len({r["session"] for r in rows}),
        "handling_minutes_total": round(handling, 1),
        "minutes_per_order": round(statistics.median(per_case.values()), 1) if per_case else 0.0,
        "minutes_per_order_min": min(per_case.values(), default=0.0),
        "minutes_per_order_max": max(per_case.values(), default=0.0),
        "share_by_category": {k: round(v / handling, 3) for k, v in sorted(by_cat.items(), key=lambda kv: -kv[1])} if handling else {},
        "share_by_tool": {k: round(v / handling, 3) for k, v in sorted(by_tool.items(), key=lambda kv: -kv[1])} if handling else {},
        "share_of_cases_waiting": round(len(waited) / len(cases), 3) if cases else 0.0,
        "wait_minutes_median": round(statistics.median(wait_case[c] for c in waited), 1) if waited else 0.0,
    }


# ---------------------------------------------------------------------------
# 4. Commands
# ---------------------------------------------------------------------------
def cmd_guide(args):
    roles = ROLES if args.role == "all" else [args.role]
    for role in roles:
        print(f"Interview guide: {role}  (about 45 minutes)\n")
        items = OPENING + BANK[role] + CLOSING
        for i, (q, purpose) in enumerate(items, start=1):
            print(f"{i:2}. [{purpose:10}] {q}")
        print("\nAfter each answer: 'Can you show me?'  'What happened next?'  'How often?'\n")


def cmd_check_questions(args):
    path = Path(args.file)
    if not path.exists():
        sys.exit(f"No file {path}. Write one question per line, then run again.")
    questions = [l.strip() for l in path.read_text(encoding="utf-8").splitlines() if l.strip()]
    flagged = 0
    for q in questions:
        flags = check_question(q)
        if not flags:
            print(f"OK    {q}")
            continue
        flagged += 1
        print(f"FIX   {q}")
        for name, advice in flags:
            print(f"        {name}: {advice}")
    print(f"\n{len(questions)} questions, {flagged} to rework.")
    return 1 if flagged else 0


def cmd_timelog(args):
    path = Path(args.dir) / "timelog.csv"
    if not path.exists():
        sys.exit(f"No time log at {path}. Run: python unit14/discovery_kit.py sample")
    m = measure(read_timelog(path))
    print(f"Shadowing log: {m['cases']} orders, {m['sessions']} sessions, "
          f"{m['handling_minutes_total']:.0f} handling minutes observed")
    print(f"Handling minutes per order: median {m['minutes_per_order']}, "
          f"min {m['minutes_per_order_min']:.0f}, max {m['minutes_per_order_max']:.0f}")
    print("Where the handling time goes:")
    for k, v in m["share_by_category"].items():
        print(f"  {k:8} {v:6.0%}  {'#' * round(v * 40)}")
    print("By tool:")
    for k, v in m["share_by_tool"].items():
        print(f"  {k:12} {v:6.0%}")
    print(f"Orders that waited for someone: {m['share_of_cases_waiting']:.0%} "
          f"(median wait {m['wait_minutes_median']:.0f} minutes)")
    out = Path(args.dir) / "measured.json"
    out.write_text(json.dumps(m, indent=2), encoding="utf-8")
    print(f"Saved {show(out)}")


def cmd_synthesize(args):
    base = Path(args.dir)
    notes_dir = base / "notes"
    files = sorted(notes_dir.glob("*.txt")) if notes_dir.exists() else []
    if not files:
        sys.exit(f"No notes in {notes_dir}. Run: python unit14/discovery_kit.py sample")
    notes = [read_note(p) for p in files]
    measured = {}
    if (base / "timelog.csv").exists():
        measured = measure(read_timelog(base / "timelog.csv"))

    warnings = []
    roles = defaultdict(list)
    for n in notes:
        role = (n["ROLE"] or ["?"])[0].lower()
        if role not in KNOWN_ROLES:
            warnings.append(f"{n['file']}: ROLE '{role}' is not one of {', '.join(KNOWN_ROLES)}")
        roles[role].append((n["WHO"] or [n["file"]])[0])
    for r in ROLES:
        if r not in roles:
            warnings.append(f"No interview with the '{r}' role yet")
    if not any(n["SAW"] for n in notes):
        warnings.append("No SAW lines: nothing was observed, only told")
    if not measured:
        warnings.append("No timelog.csv: every number is an estimate")

    # Themes: who mentioned them, and whether anyone saw them happen
    told = defaultdict(set)
    seen = defaultdict(int)
    for n in notes:
        for line in n["PAIN"]:
            for t in THEME.findall(line):
                told[t].add(n["file"])
        for line in n["SAW"]:
            for t in THEME.findall(line):
                seen[t] += 1
    themes = sorted(set(told) | set(seen), key=lambda t: (-(len(told[t]) + 2 * seen[t]), t))

    # Numbers: estimates from notes against measured values
    numbers = []
    for n in notes:
        who = (n["WHO"] or [n["file"]])[0]
        for line in n["NUM"]:
            m = NUM_LINE.match(line)
            if not m:
                warnings.append(f"{n['file']}: NUM line not in 'key = value | source' form: {line}")
                continue
            key, value, source = m.group(1), float(m.group(2)), (m.group(3) or "no source").strip()
            numbers.append((key, value, source, who))
    gaps = []
    for key, value, source, who in numbers:
        if key in measured and isinstance(measured[key], (int, float)) and measured[key]:
            ratio = measured[key] / value if value else float("inf")
            if ratio > 1.5 or ratio < 0.67:
                gaps.append(f"`{key}`: {who} said {value:g} ({source}); shadowing measured {measured[key]:g}")

    asks = [(a, (n["WHO"] or [n["file"]])[0]) for n in notes for a in n["ASK"]]
    lines = ["# Discovery summary", ""]
    lines += ["## Who we heard from", ""]
    for r in ROLES + sorted(set(roles) - set(ROLES)):
        lines.append(f"- **{r}**: {', '.join(roles[r]) if roles.get(r) else 'nobody yet'}")
    lines += ["", "## What was asked for", ""]
    lines += [f"- \"{a}\" ({who})" for a, who in asks] or ["- No ASK lines recorded"]
    lines += ["", "## Themes, ranked by evidence", "",
              "| Theme | Interviews that mention it | Times observed | Evidence |",
              "| --- | --- | --- | --- |"]
    for t in themes:
        kind = "told and seen" if told[t] and seen[t] else ("seen only" if seen[t] else "told only")
        lines.append(f"| {t} | {len(told[t])} | {seen[t]} | {kind} |")
    if measured:
        lines += ["", "## Measured while shadowing", "",
                  f"- Orders observed: {measured['cases']} in {measured['sessions']} sessions",
                  f"- Handling minutes per order: median {measured['minutes_per_order']}",
                  "- Share of handling time: " + ", ".join(f"{k} {v:.0%}" for k, v in measured["share_by_category"].items()),
                  f"- Orders that waited for someone: {measured['share_of_cases_waiting']:.0%}"]
    lines += ["", "## Numbers to confirm", "", "| Number | Value | Source | From |", "| --- | --- | --- | --- |"]
    lines += [f"| {k} | {v:g} | {s} | {w} |" for k, v, s, w in numbers] or ["| none | | | |"]
    lines += ["", "## Said versus seen", ""]
    lines += [f"- {g}" for g in gaps] or ["- No large gaps between estimates and measurements"]
    lines += ["", "## Data mentioned", ""]
    lines += [f"- {d} ({(n['WHO'] or [n['file']])[0]})" for n in notes for d in n["DATA"]] or ["- none"]
    lines += ["", "## Risks and constraints", ""]
    lines += [f"- {d} ({(n['WHO'] or [n['file']])[0]})" for n in notes for d in n["RISK"]] or ["- none"]
    lines += ["", "## Working hypothesis", ""]
    if themes:
        top = themes[0]
        lines.append(f"The strongest evidence points to **{top}** "
                     f"({len(told[top])} interviews, observed {seen[top]} times).")
        if asks:
            lines.append("Compare it with what was asked for above. If they differ, the ask is a "
                         "proposed solution; take the theme into problem framing.")
    else:
        lines.append("No #themes tagged on PAIN or SAW lines yet.")
    lines += ["", "## Gaps in this discovery", ""]
    lines += [f"- {w}" for w in warnings] or ["- none"]

    out = base / "discovery_summary.md"
    out.write_text("\n".join(lines) + "\n", encoding="utf-8")
    print(f"Read {len(notes)} interviews, {len(numbers)} numbers, "
          f"{'a' if measured else 'no'} time log.")
    print("Top themes: " + (", ".join(f"{t} ({len(told[t])} told, {seen[t]} seen)" for t in themes[:3]) or "none"))
    for g in gaps:
        print("Said vs seen: " + g.replace("`", ""))
    for w in warnings:
        print("Gap: " + w)
    print(f"Wrote {show(out)}")


# ---------------------------------------------------------------------------
# 5. Sample data: made-up, SAP-shaped, for the blocked-order example
# ---------------------------------------------------------------------------
SAMPLE_NOTES = {
    "01_credit_analyst.txt": """WHO: Credit analyst A
ROLE: user
DATE: 2026-10-05
ASK: An AI that releases blocked orders automatically
PAIN: #chasing-info I spend half the day waiting for sales reps to explain an order
PAIN: #manual-lookup I open three or four screens to see one customer's exposure
SAW: #chasing-info Emailed the sales rep about order 4500123 and moved on while waiting
SAW: #manual-lookup Copied open items into a spreadsheet to add them up
SAW: #chasing-info Phoned a rep about a second order; voicemail
NUM: minutes_per_order = 10 | estimate by analyst
NUM: blocked_orders_per_day = 40 | estimate by analyst
DATA: Credit exposure and open items in SAP; the reason for a big order is in reps' emails
QUOTE: "The decision takes a minute. Finding out takes the morning."
""",
    "02_head_of_credit.txt": """WHO: Head of Credit Management
ROLE: owner
DATE: 2026-10-06
ASK: Use AI to cut the backlog of blocked orders
PAIN: #backlog Orders sit blocked overnight and customers complain to sales
PAIN: #stale-limits Some credit limits haven't been reviewed in two years
NUM: median_hours_blocked = 19.7 | system report, last 8 weeks
NUM: minutes_per_order = 8 | estimate by owner
RISK: Releases above an agreed amount need a second approver
RISK: Bad debt must not rise; finance reports it quarterly
DATA: Weekly blocked-order report from the SAP system
""",
    "03_sap_integration_lead.txt": """WHO: SAP integration lead
ROLE: it
DATE: 2026-10-07
PAIN: #chasing-info Sales asks IT for order status because they can't see credit notes
DATA: Sales orders and credit status through a released API; emails are outside SAP
RISK: Credit data is restricted; the assistant must respect the analyst's authorizations
RISK: No new access to production before a security review
NUM: api_extract_days = 5 | estimate for approval of a test extract
""",
}

SAMPLE_TIMELOG = [
    # session, case, step, category, minutes, tool
    ("S1", "4500123", "open order and credit block", "gather", 2, "SAP"),
    ("S1", "4500123", "check exposure and open items", "gather", 6, "SAP"),
    ("S1", "4500123", "email sales rep for context", "gather", 4, "email"),
    ("S1", "4500123", "wait for reply", "wait", 95, "email"),
    ("S1", "4500123", "read reply and decide", "decide", 2, "SAP"),
    ("S1", "4500123", "write release note", "record", 4, "SAP"),
    ("S1", "4500124", "open order and credit block", "gather", 2, "SAP"),
    ("S1", "4500124", "check exposure and open items", "gather", 5, "SAP"),
    ("S1", "4500124", "add up open items", "gather", 6, "spreadsheet"),
    ("S1", "4500124", "decide", "decide", 1, "SAP"),
    ("S1", "4500124", "write release note", "record", 3, "SAP"),
    ("S1", "4500131", "open order and credit block", "gather", 2, "SAP"),
    ("S1", "4500131", "check exposure and open items", "gather", 7, "SAP"),
    ("S1", "4500131", "phone sales rep", "gather", 5, "phone"),
    ("S1", "4500131", "wait for call back", "wait", 140, "phone"),
    ("S1", "4500131", "decide", "decide", 2, "SAP"),
    ("S1", "4500131", "write rejection note", "record", 5, "SAP"),
    ("S1", "4500135", "open order and credit block", "gather", 1, "SAP"),
    ("S1", "4500135", "check exposure", "gather", 3, "SAP"),
    ("S1", "4500135", "decide", "decide", 1, "SAP"),
    ("S1", "4500135", "write release note", "record", 2, "SAP"),
    ("S2", "4500140", "open order and credit block", "gather", 2, "SAP"),
    ("S2", "4500140", "check exposure and open items", "gather", 6, "SAP"),
    ("S2", "4500140", "email sales rep for context", "gather", 3, "email"),
    ("S2", "4500140", "wait for reply", "wait", 60, "email"),
    ("S2", "4500140", "decide", "decide", 2, "SAP"),
    ("S2", "4500140", "write release note", "record", 4, "SAP"),
    ("S2", "4500142", "open order and credit block", "gather", 2, "SAP"),
    ("S2", "4500142", "check exposure and open items", "gather", 8, "SAP"),
    ("S2", "4500142", "add up open items", "gather", 7, "spreadsheet"),
    ("S2", "4500142", "ask team lead (above limit)", "decide", 4, "chat"),
    ("S2", "4500142", "write release note", "record", 4, "SAP"),
    ("S2", "4500147", "open order and credit block", "gather", 1, "SAP"),
    ("S2", "4500147", "check exposure and open items", "gather", 6, "SAP"),
    ("S2", "4500147", "email sales rep for context", "gather", 4, "email"),
    ("S2", "4500147", "wait for reply", "wait", 120, "email"),
    ("S2", "4500147", "decide", "decide", 1, "SAP"),
    ("S2", "4500147", "write release note", "record", 3, "SAP"),
    ("S2", "4500150", "open order and credit block", "gather", 2, "SAP"),
    ("S2", "4500150", "check exposure", "gather", 4, "SAP"),
    ("S2", "4500150", "decide", "decide", 1, "SAP"),
    ("S2", "4500150", "write release note", "record", 3, "SAP"),
]

SAMPLE_QUESTIONS = """Wouldn't it be faster if AI released these orders for you?
Do you find the credit check frustrating?
Walk me through the last blocked order you handled today.
Would you use a chatbot that explains each block?
How long did the last one take? Who did you have to ask?
Tell me about a release you later regretted.
"""


def cmd_sample(args):
    base = Path(args.dir)
    notes = base / "notes"
    notes.mkdir(parents=True, exist_ok=True)
    targets = [notes / n for n in SAMPLE_NOTES] + [base / "timelog.csv", base / "my_questions.txt"]
    if any(p.exists() for p in targets) and not args.force:
        sys.exit(f"Sample files already exist in {show(base)}. Use --force to overwrite them.")
    for name, text in SAMPLE_NOTES.items():
        (notes / name).write_text(text, encoding="utf-8")
    with (base / "timelog.csv").open("w", newline="", encoding="utf-8") as f:
        w = csv.writer(f)
        w.writerow(["session", "case", "step", "category", "minutes", "tool"])
        w.writerows(SAMPLE_TIMELOG)
    (base / "my_questions.txt").write_text(SAMPLE_QUESTIONS, encoding="utf-8")
    print(f"Wrote {len(SAMPLE_NOTES)} interview notes, timelog.csv ({len(SAMPLE_TIMELOG)} rows) "
          f"and my_questions.txt to {show(base)}")
    print("All of it is made up. Next: python unit14/discovery_kit.py timelog")


def main(argv=None):
    p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    p.add_argument("--dir", default=str(DEFAULT_DIR), help="folder with notes/, timelog.csv (default: unit14/discovery)")
    sub = p.add_subparsers(dest="cmd", required=True)
    s = sub.add_parser("sample", help="write made-up notes, time log and questions")
    s.add_argument("--force", action="store_true", help="overwrite existing sample files")
    g = sub.add_parser("guide", help="print an interview guide")
    g.add_argument("--role", choices=ROLES + ["all"], default="all")
    c = sub.add_parser("check-questions", help="check your own questions")
    c.add_argument("file")
    sub.add_parser("timelog", help="summarize the shadowing time log")
    sub.add_parser("synthesize", help="write discovery_summary.md")
    args = p.parse_args(argv)
    handler = {"sample": cmd_sample, "guide": cmd_guide, "check-questions": cmd_check_questions,
               "timelog": cmd_timelog, "synthesize": cmd_synthesize}[args.cmd]
    return handler(args) or 0


if __name__ == "__main__":
    sys.exit(main())

Step 3: Write the sample files

  1. In the terminal, run:

    python unit14/discovery_kit.py sample
  2. You should see:

    Wrote 3 interview notes, timelog.csv (42 rows) and my_questions.txt to unit14/discovery
    All of it is made up. Next: python unit14/discovery_kit.py timelog
  3. Open unit14/discovery/notes/01_credit_analyst.txt in VS Code. Each line starts with a tag:

    Tag Meaning
    WHO, ROLE, DATE Who you spoke to (a role, not a name), their role group, and when
    ASK What they asked for, in their words
    PAIN A problem they told you about, with a #theme
    SAW Something you saw happen while shadowing, with a #theme
    NUM A number, as key = value | source
    DATA Where information lives
    RISK A rule, limit or risk any solution must respect
    QUOTE A short quote worth playing back

    ROLE is one of owner, user or it, which every discovery should cover, or security, sponsor or other.

If you see Sample files already exist, you ran this before. Add --force to overwrite them.

Step 4: Print an interview guide

  1. Run:

    python unit14/discovery_kit.py guide --role user
  2. You should see ten questions, each labelled with what it is for:

    Interview guide: user  (about 45 minutes)
    
     1. [context   ] What does your role own in this process, from start to finish?
     2. [problem   ] Walk me through the last time you handled one. What happened first?
     3. [problem   ] Walk me through the last order you worked on today, screen by screen.
     4. [problem   ] Where did you have to wait, or ask someone else?
     5. [baseline  ] Which part of that took longest? Show me.
     6. [data      ] What do you check that the system doesn't show you?
     7. [data      ] What workarounds do you keep, such as spreadsheets, notes or emails?
     8. [constraint] Tell me about the last time you disagreed with a rule or a decision.
     9. [close     ] What should I have asked that I didn't?
    10. [close     ] Who else should I talk to, and may I sit with someone while they work?
    
    After each answer: 'Can you show me?'  'What happened next?'  'How often?'
  3. Try --role owner and --role it, or --role all for all three. Notice that no question mentions AI.

Step 5: Check your own questions

  1. Open unit14/discovery/my_questions.txt. It holds six questions a hurried team might write.

  2. Run:

    python unit14/discovery_kit.py check-questions unit14/discovery/my_questions.txt
  3. You should see four questions marked FIX, each with a reason, and two marked OK:

    FIX   Wouldn't it be faster if AI released these orders for you?
            leading: Suggests the answer. Ask neutrally, e.g. 'What was easy or difficult about it?'
            solution-first: Talks about a solution. Ask about their work and the problem first.
    FIX   Do you find the credit check frustrating?
            leading: Suggests the answer. Ask neutrally, e.g. 'What was easy or difficult about it?'
            closed: Invites yes or no. Start with 'Walk me through', 'Tell me about' or 'How'.
    OK    Walk me through the last blocked order you handled today.
    FIX   Would you use a chatbot that explains each block?
            hypothetical: Asks about the future. Ask about the last time it happened instead.
            solution-first: Talks about a solution. Ask about their work and the problem first.
    FIX   How long did the last one take? Who did you have to ask?
            double: Two questions in one. Split it.
    OK    Tell me about a release you later regretted.
    
    6 questions, 4 to rework.
  4. Rewrite the four FIX questions in the file, save, and run the command again until it says 0 to rework.

The checks are simple word patterns, not grammar. They catch common slips and miss subtle ones, so read your questions aloud too.

Step 6: Summarize the shadowing time log

  1. Open unit14/discovery/timelog.csv. Each row is one step of one blocked order, timed while shadowing: the session, the order (case), the step, its category (gather, decide, record or wait), minutes and the tool used.

  2. Run:

    python unit14/discovery_kit.py timelog
  3. You should see:

    Shadowing log: 8 orders, 2 sessions, 130 handling minutes observed
    Handling minutes per order: median 17.0, min 7, max 25
    Where the handling time goes:
      gather      68%  ###########################
      record      22%  #########
      decide      11%  ####
    By tool:
      SAP             75%
      spreadsheet     10%
      email            8%
      phone            4%
      chat             3%
    Orders that waited for someone: 50% (median wait 108 minutes)
    Saved unit14/discovery/measured.json

Read it like a discovery finding. Deciding is 11% of the handling time; gathering is 68%. Half the orders waited a median of 108 minutes for someone. An AI that makes the decision would speed up the smallest part.

Step 7: Write the discovery summary

  1. Run:

    python unit14/discovery_kit.py synthesize
  2. You should see:

    Read 3 interviews, 5 numbers, a time log.
    Top themes: chasing-info (2 told, 2 seen), manual-lookup (1 told, 1 seen), backlog (1 told, 0 seen)
    Said vs seen: minutes_per_order: Credit analyst A said 10 (estimate by analyst); shadowing measured 17
    Said vs seen: minutes_per_order: Head of Credit Management said 8 (estimate by owner); shadowing measured 17
    Wrote unit14/discovery/discovery_summary.md
  3. Open unit14/discovery/discovery_summary.md. Right-click its tab and choose Open Preview to see it formatted. It has these sections: who you heard from, what was asked for, themes ranked by evidence, measured numbers, numbers to confirm, said versus seen, data, risks, a working hypothesis, and gaps.

The hypothesis says the strongest evidence points to chasing-info: gathering context from sales reps. Both requests asked for AI on the decision or the backlog. That difference is the main output of discovery.

The Gaps section says none for the sample. With your own notes, it warns when a role is missing, when nothing was observed, or when there is no time log. An empty gaps list doesn't prove the discovery was good; it means the basic coverage is there.

How the code works

Part of the script What it does
OPENING, BANK, CLOSING The question bank: opening and closing questions for everyone, and six per role, each labelled with its purpose
CHECKS and check_question() Five word patterns for leading, hypothetical, solution-first, closed and double questions, each with advice
read_note() Reads one notes file line by line and groups lines by tag; lines without a known tag are kept as free text
read_timelog() Reads the CSV, checks the columns and that minutes are numbers
measure() Adds up handling minutes per case and per category and tool; keeps wait apart because it is elapsed time, not work
cmd_timelog() Prints the measurements and saves them to measured.json
cmd_synthesize() Ranks #themes (an observation counts twice as much as a mention), compares NUM estimates with measured values of the same name, flags gaps in coverage, and writes the summary
cmd_sample() Writes the made-up notes, time log and questions; refuses to overwrite without --force

The ranking rule is deliberately simple: one point per interview that mentions a theme, two per observation. You can argue with it, and you should. The point is that the ranking is written down, so the playback audience can argue with it too.

An estimate counts as a gap when the measured value is more than 1.5 times it, or less than two thirds of it. Change those limits in cmd_synthesize() if your process needs different ones.

Use your own notes

  1. Create a new folder for a real discovery, for example unit14/discovery-myprocess/, with a notes folder inside.

  2. Write one .txt file per conversation in notes/, using the tags above. Use roles, not names, in WHO.

  3. If you shadowed someone, save a timelog.csv with the same header as the sample.

  4. Run the commands with --dir before the command name:

    python unit14/discovery_kit.py --dir unit14/discovery-myprocess timelog
    python unit14/discovery_kit.py --dir unit14/discovery-myprocess synthesize

To compare an estimate with a measurement, give the NUM line the same key the time log produces, minutes_per_order.

If something goes wrong

What you see What it means What to do
python is "not recognized" or "command not found" Python isn't installed or isn't on the path Turn on .venv (Step 1); see Set up your computer
can't open file ... discovery_kit.py You aren't in the course folder, or the file has another name Run from orchestrate-course; check the file is unit14/discovery_kit.py
No notes in ... or No time log at ... sample hasn't run, or --dir points to the wrong folder Run python unit14/discovery_kit.py sample, or fix the --dir path
lacks columns: ... Your own CSV uses other column names Copy the header line from the sample timelog.csv
minutes '...' is not a number A minutes cell has text or a comma decimal Use a plain number with a dot, such as 4.5
NUM line not in 'key = value | source' form A NUM line has a different shape Write it as NUM: minutes_per_order = 12 | measured
invalid choice after --role A role the guide doesn't have Use owner, user, it or all
ModuleNotFoundError You copied code that imports a library this script doesn't use Re-paste the script; it needs only built-in modules
A network or proxy error Not expected: this script makes no network calls Check you are running this script, not another unit's

The SAP way

SAP has no single "discovery interview" product. It has methods and tools that cover parts of the job, and they fit around the interviews and shadowing above. As of October 2026:

SAP Activate: where discovery sits in a project

SAP Learning describes SAP Activate's phases. Discover is a "non-committal phase" in which customers research SAP offerings; its deliverables include an innovation strategy and roadmap, a value and impact analysis and an implementation strategy. Prepare defines the scope of work and governance. Explore runs fit-to-standard workshops with SAP Best Practices content and records fit findings, gaps and configuration needs in the product backlog.

An FDE's discovery for one AI use case doesn't map neatly onto these phases. On a running S/4HANA system, it often happens long after go-live. In a new implementation, it fits best next to Explore: fit-to-standard shows what standard SAP covers, and your interviews show where people still lose time. Writing a solution design document picks up from there.

Design-led development and user research

SAP's Fiori design guidelines describe design-led development in three phases: Discover, Design and Deliver. For Discover they name interviews, surveys and shadowing, to understand users' needs, behaviors and pain points. They say user research should ideally happen in all three phases, and SAP recruits real users through its SAP User Research Panel. If your customer's UX team works this way, your discovery notes are input to theirs.

SAP AppHaus workshops for AI

SAP AppHaus publishes an Innovation Toolkit for AI with four workshop formats: Business AI Explore, Business AI Design, Joule Agent Discovery and Joule Agent Design.

The Joule Agent Discovery Workshop facilitation guide (version 3, March 2026) is the closest SAP material to this topic:

  • Who: 3 to 10 strategic decision makers and IT experts, in breakout teams of at most six, plus AI experts to clarify limitations early.
  • How long: two to three hours, on site or virtual.
  • What happens: inspiration, silent individual ideation of automation scenarios, prioritization, then detailing the chosen ideas.
  • How ideas are rated: 1 to 5 on complexity and variability, rules versus judgement, system interaction and business value. A Reason and Act Framework places each idea by its need to reason and its need to act.
  • What comes out: the top one to three ideas, an agentic use case template with the current steps, roles and automation steps, and who joins the follow-up Joule Agent Design Workshop.

The guide itself doesn't cover interviewing users or checking data. Use the workshop to collect and rank candidates, then interview and shadow to check the top ideas before anyone designs an agent. The Joule agents and agent orchestration topic covers what such an agent can do.

Process data for the baseline

SAP Signavio Process Insights, discovery edition analyzes your own SAP ERP process data. A post by the SAP Signavio Discovery team says it is a one-time analysis of one process flow, chosen from three: supplier invoice issuing, sales billing document creation to FI-AR clearing, and purchase order item creation. It returns correction recommendations and more than 800 innovation recommendations, and the post says the analysis can be requested for free.

SAP Store also lists a business process assessment service built on the discovery edition. When checked on 10 October 2026, it showed a one-time fee of USD 8,340, prerequisites of the ST-A/PI plug-in and two SAP Notes in the ERP production system, and deliverables of an assessment report, a workshop with your process owner and an executive summary. Check the current scope and price with SAP before you plan around it.

None of the three discovery-edition flows is the credit block on sales orders. For the running example, the system baseline still comes from the blocked-order report the owner watches, or from an extract like the one in Defining success metrics with the business. The blocked-order count from your first prototype in What an SAP forward deployed engineer does is also a start.

Build vs. SAP

Situation Lean towards Why
Many departments, no idea yet where AI fits SAP AppHaus Business AI Explore or Joule Agent Discovery workshop Collects and ranks candidates from a room in hours
One candidate chosen, need to know how the work happens Your own interviews and shadowing, with this kit Only watching the work shows hidden steps and waits
One of the three discovery-edition flows, on SAP ERP SAP Signavio Process Insights, discovery edition System numbers and recommendations for that flow
Company already runs SAP Signavio Baselines from its process analytics Event data and cycle times already exist
New S/4HANA implementation under way Join the Explore phase's fit-to-standard results Avoid building AI for a gap the standard closes
Steps outside SAP: email, phone, spreadsheets Shadowing time logs No SAP system records them

Production concerns

  • Personal data in notes. Notes can hold names, opinions and performance details. Use roles instead of names, keep notes in a private location with access limited to the project team, and delete raw notes when the project's retention rule says so.
  • Observing people at work. Shadowing records how long individuals take. Tell participants what you record and why, and present results by step and role, never as a ranking of people. In some companies or countries, observing work may need agreement from HR or employee representatives; ask before you schedule sessions.
  • Seeing customer data. While shadowing, you will see real orders, amounts and customer names on screen. Make sure your contract and the customer's rules allow it, and never copy them into notes.
  • SAP authorizations for extracts. A system extract for the baseline must be approved by the data owner and pulled by someone allowed to see that data. Ask for only the fields the baseline needs.
  • Bias in who you hear from. The loudest user, or the one the manager picks, may not be typical. Ask to shadow at least two people, ideally from different teams or shifts.
  • The observer effect. People often work more carefully while watched. Treat shadowing times as a rough measure and check them against system data where you can.
  • Clean core. Discovery changes nothing in SAP. It reads reports and extracts and watches people work.

Pitfalls

  • Pitching instead of listening. Showing an AI demo in the first interview turns every answer into an opinion about your demo.
  • Interviewing only managers. They describe the process as designed. Users show the process as it runs.
  • Only asking, never watching. Without shadowing, every number is an estimate, and workarounds stay hidden.
  • Taking estimates as the baseline. Write them down, then measure. The gap is often the finding.
  • Stopping at the first "why". "Sales reps reply slowly" is a symptom. Why is the context not in the order already?
  • Skipping IT until later. The data you need may be outside SAP, restricted, or behind a months-long approval.
  • No playback. People who never saw your findings won't trust what you build on them.
  • Over-reading a small sample. Eight orders show a pattern. They don't give a baseline for a business case.

Exercise

Add a fourth interview, see how the evidence shifts, and write the problem hypothesis that the next Unit 14 topic will frame.

  1. In VS Code, create the file unit14/discovery/notes/04_sales_rep.txt and paste:

    WHO: Sales rep B
    ROLE: other
    DATE: 2026-10-08
    PAIN: #chasing-info Credit emails me for context I already put in the order text
    PAIN: #backlog My customer called twice about a blocked order last week
    DATA: Context for big orders is in the order header text and in my emails

    Save the file.

  2. Run:

    python unit14/discovery_kit.py synthesize
  3. Check the first lines. They now say Read 4 interviews and chasing-info (3 told, 2 seen). The theme gained support from a role downstream of the process.

  4. Open discovery_summary.md. Under Data mentioned, note the new clue: some context is already in the order header text. That is a question for the IT interview: can the assistant read it through a released API?

  5. Write five rewritten interview questions for a sales rep in unit14/discovery/sales_questions.txt, one per line. Run:

    python unit14/discovery_kit.py check-questions unit14/discovery/sales_questions.txt

    Rework them until the last line says 0 to rework.

  6. Create unit14/discovery/problem_hypothesis.md with four lines:

    • The ask: what was requested, in the requester's words.
    • What we found: the top theme and its evidence (told, seen, measured).
    • Baseline so far: each number with its source, marked as estimate, measured or system.
    • Open questions: what you still need to check, and with whom.
  7. Save your work:

    git add unit14/discovery_kit.py unit14/discovery/sales_questions.txt unit14/discovery/problem_hypothesis.md
    git commit -m "Unit 14: discovery kit and problem hypothesis"

Done when synthesize reports four interviews with chasing-info (3 told, 2 seen), your sales questions pass the check with 0 to rework, and problem_hypothesis.md holds the four lines. Keep it: the problem framing topic, next in Unit 14, starts from this hypothesis.

Check yourself

Pick one answer for each question. The explanation appears after you choose.

1An analyst says the task takes 10 minutes; your shadowing log shows a median of 17. What is the best next step?

Answer: D. A gap between told and seen is a finding to explore, not a number to settle by averaging. Eight shadowed orders show a pattern but not a baseline; the system gives volume and durations across many cases.

2Why does measure() keep wait steps out of handling minutes?

Answer: C. Handling time measures work; waiting measures delay. Mixing them hides both findings. The script reports waits separately: half the sample orders waited a median of 108 minutes.

3How does synthesize rank themes, and why is that rule written down?

Answer: C. Seeing something happen is stronger evidence than hearing about it, so observations count double. Because the rule is explicit, the playback audience can see and question how the ranking was made.

4Which question would check-questions flag as hypothetical?

Answer: D. It asks about future behavior, which people tend to overestimate, and it names a solution. The Mom Test's advice is to ask about specifics in the past, such as the last case.

5A team runs SAP AppHaus's Joule Agent Discovery Workshop and ranks an agent for credit releases top. What should an FDE do next?

Answer: C. The workshop collects and rates ideas from a room in two to three hours; its guide doesn't cover interviewing users or checking data. Watching the work and checking the numbers shows whether the ranked idea targets where the time really goes.

6Your customer runs SAP ERP and asks if SAP Signavio Process Insights, discovery edition can give the blocked-order baseline. What is the accurate answer?

Answer: B. The SAP Signavio team describes a one-time analysis of one flow: supplier invoice issuing, sales billing to FI-AR clearing, or purchase order item creation. The credit-block baseline comes from the owner's report or a system extract.

7While shadowing, an analyst's screen shows customer names and order amounts. What do you write in your notes?

Answer: A. Notes record how the work happens, not whose data it was. Use roles instead of names, keep notes private, and check that your contract allows you to see the data at all.

8Discovery shows many blocks come from credit limits nobody has reviewed in two years. What does that suggest?

Answer: D. Stale limits create blocks that shouldn't happen. Fixing the cause upstream may remove work that an AI would only speed up. Asking "why?" past the first symptom is how discovery finds this.

Sources

Sign in to track your progress

We'll email you a one-time sign-in link. No password needed.

or

Tell us a little about you

Optional, every field. It helps us pitch answers to your questions at the right level and decide which topics to write next. It is never shown publicly, and you can change or clear it anytime from the account menu.

SAP areas you work in