Home/Unit 14 · The FDE operating system and capstone
Problem framing: from 'we need AI' to a measurable problem
Turn a vague AI request into a framed problem with an actor, a metric, a baseline, a target, constraints and a stop rule, before anyone picks a technology.
Most AI projects start with a sentence like "we need AI for MRP" or "we need an agent that clears blocked invoices". That sentence names a technology. It doesn't say who has a problem, how big it is, or how anyone would know it was solved.
Problem framing turns that sentence into a short, signed statement:
For who, in which process step, move which number from today's value to a target by a date, without making something else worse, within these limits.
For example: "For credit analysts reviewing blocked sales orders, reduce handling time per order from 17 minutes (measured) to 10 minutes by the end of January, without more released orders going overdue, with the analyst still deciding every release."
Notice what is missing: the word AI. The framed problem describes the business change. The technology is chosen afterwards, and it might turn out to be a report, a rule or a training session.
Framing is the step after discovery. Discovery finds the real problem behind the request. Framing writes it down so precisely that everyone can agree on it, and argue with it.
A request that names a solution hides the problem. Software support has a name for this, the XY problem: someone asks how to make their attempted fix work, instead of describing what they were trying to do. The cure is the same in an SAP project: ask why.
Take a request from a plant: "We need AI for MRP." Asked why, the planning lead says planners lose their mornings to exception messages, "about three hours a day". Asked what success looks like, she says "thirty minutes". That is a useful start, but it is not yet a problem anyone can fund:
Three hours is an estimate. Nobody timed it. If it is really ninety minutes, the business case halves.
Thirty minutes may be impossible. If only part of those hours is spent looking things up, a tool that speeds up the lookup can't remove the rest.
Nothing says what must not get worse. A faster review that lets more shortages reach production is a loss, not a win.
Nobody owns the number. Without an owner, nobody can say "this worked" or "stop".
Framing fixes these before money is spent. It costs a few hours with the process owner. It decides what the team will build, what it will measure, and when it will stop. Getting it wrong costs a pilot that "went well" but proved nothing.
SAP doesn't sell a problem-framing product. It offers workshop methods and tools that help, and the SAP applications where the framed problem lives. As of October 2026:
SAP AppHaus Business AI Explore Workshop. Its facilitation guide starts from an Existing Challenge template: the process or activity to improve, why it needs improving, and who is affected. Chosen ideas get a Use Case Brief with a business view, a technical view and an ethical view. The ethical view asks yes, no or "not clear yet" questions, for example about personal data and automated decision-making.
SAP AppHaus Business AI Design Workshop. It maps the current process and its pain points, then describes a future scenario with a trigger, a "moment of success" and its impact. Each idea gets a Capability Idea Napkin: input data, expected output, and how the output is verified.
SAP Business AI Feature Catalog, in SAP Discovery Center. It lists embedded AI features with use cases, value and metrics. A companion Feature Estimator estimates the AI units a feature would need.
The SAP applications themselves. A framed problem names the place where people work. For credit blocks, SAP Learning describes the Manage Documented Credit Decisions app. For MRP, planners use apps such as Manage Material Coverage. For blocked supplier invoices, SAP describes Release Blocked Invoices (transaction MRBR).
The workshops help a room agree on the challenge. They don't measure anything. Framing adds the numbers, the owner and the stop rule. And a framed problem written without technology is easy to compare with the catalog: an embedded SAP feature may already address it.
Each row starts with a real-sounding request. The numbers are made up for illustration.
The request
What's wrong with it
A framed problem
"AI to cut the backlog of blocked sales orders"
Names a tool; "backlog" has no number
For credit analysts, cut handling time per blocked order from 17 to 10 minutes (measured) by January, overdue receivables no worse, analyst decides every release
"We need AI for MRP"
No process step, no number, no owner
For planners, cut daily exception-analysis time from 180 minutes (estimate, to be measured) to 90 minutes by March, without more shortages reaching production
"An agent that clears blocked invoices"
Changes SAP data with nobody approving
For AP clerks, cut handling time per blocked invoice from 22 to 12 minutes (measured), clerk approves every release, no rise in payments made in error
"Predict which deliveries will be late"
A prediction nobody acts on
For order managers, raise the share of at-risk orders where the customer is told before the promised date, from 20% to 60% (system, last quarter)
"Roll out Joule to everyone"
Adoption is not a business problem
Name the two or three processes where people should save time, and frame each one like the rows above
Two patterns stand out. First, the framed version always names a person and a number. Second, three of the five got smaller while being framed. That is normal. A small, clear problem gets solved; a big, vague one gets a steering committee.
"The request is the problem." A request is usually a proposed solution. Framing asks what it is meant to fix.
"A bigger target makes a stronger case." A target the solution can't reach makes the whole case look careless. Check it against what the solution can touch.
"We'll define success after the pilot." Then any result can be called success. Agree the number and the stop rule first.
"Framing is a document for consultants." It is a one-page agreement. The engineer who builds the system needs it most.
"AI must be part of the answer." A good frame often points to a simpler fix: a report, a rule, a field that must be filled in.
"Constraints come later, from IT." Approval rules, authorizations and data access shape what can be built. They belong in the frame.
Pick one answer for each question. The explanation appears after you choose.
1A sponsor asks for "an AI agent for blocked invoices". What should the first framing step produce?
Answer: C. The request names a solution. Framing first describes who has which problem, so that the technology can be chosen afterwards, and might not be AI at all.
2The planning lead says exception analysis takes "about three hours a day". How should the frame treat that number?
Answer: B. An estimate is a starting point, not a baseline. If the real figure is lower, the whole business case shrinks, so the frame marks it as an estimate until someone times real days.
3Only part of a planner's analysis time is spent looking up context, and the solution only speeds up the lookup. What does that mean for the target?
Answer: D. A solution can only change the part of the work it touches. A target that needs more than that part removed can't be met, however good the solution is.
4Which line best protects the business while the main metric improves?
Answer: B. That line is a guardrail: a number that must not get worse. Faster decisions that let more bad orders through would be a loss, and only a guardrail catches it.
5A proposal says the AI will release blocked invoices in SAP by itself. What should a framed problem require?
Answer: C. Anything that changes SAP data needs an explicit approval step in the frame. It also forces the question of who acts on the output, which a fully automatic design leaves unanswered.
6Why write down the best non-AI fix in the frame?
Answer: A. A simpler fix, such as SAP's automatic release of invoices whose blocks no longer apply, may solve most of the problem. If the AI can't clearly beat it, the simpler fix wins.
7When should the team agree what result means "stop"?
Answer: D. A stop rule agreed afterwards bends to fit the result. Written into the frame, it lets the owner end a project that isn't working without a long argument.
Ask a question
Testing: only staff see this
Stuck on something in this layer? Ask it here. Questions are answered in the order they arrive, and the answer appears under My questions.
Sign in (free) to ask a question. You can ask anonymously.
A framed problem is a small contract with three parts:
Part
Question it answers
Blocked-order example
The change
Which number moves, for whom, from where to where, by when?
Analyst handling minutes per order, 17 to 10, by 29 January
The boundary
What must not get worse, what must the solution respect, what is out?
Overdue receivables no worse; read-only access; analyst decides; no automatic release
The action
What does the solution hand over, and who does what with it?
A drafted note; the analyst reads it and decides in Manage Documented Credit Decisions
Google's problem framing course makes the same split in its own words. It says to begin "by stating your goal in non-ML terms", and it separates the ideal outcome (what the product should achieve) from the model's goal (what a model predicts or generates to support it). It also warns that a prediction has no value unless it turns into an action that helps users. The frame writes down the ideal outcome and the action. The model's goal comes later, in design.
If you can fill in all three parts without naming a technology, you have a problem. If you can't, you have a request.
Framing starts where discovery ended: with the problem hypothesis from the discovery exercise, and the numbers behind it. It ends with one page the owner signs. The next Unit 14 topic, the opportunity assessment, then decides whether AI, plain automation or neither fits.
flowchart LR
H[Problem hypothesis] --> S[Strip the solution]
S --> A[Actor and unit]
A --> M[Metric and baseline]
M --> T[Target and ceiling]
T --> B[Guardrails, constraints, out of scope]
B --> O[Output, action, benchmark]
O --> F[Signed frame]
F --> N[Opportunity assessment]
Write the ask down exactly as it was said. Then rewrite it as a problem, removing every technology word: AI, agent, chatbot, model, Joule. The XY problem gives the method: ask why the requester wants that solution, until the answer is about their work, not about the tool.
"An agent that clears blocked invoices" becomes "clerks spend most of each blocked invoice finding out why it is blocked and whether the reason still holds". The second sentence can be measured. The first can only be built.
The actor is the person whose work changes: a credit analyst, a production planner, an accounts payable clerk. The unit is one case of the work: one blocked order, one planner day, one blocked invoice. Every number in the frame is per unit, so it can be counted.
One actor per frame. If two roles both benefit, write two frames. They often need different solutions.
#3. Pick one metric and record its baseline with a source
The metric counts something per unit: minutes per order, share of orders decided within a day, shortages per week. Words like "improve", "efficiency" or "faster" are wishes, not metrics. Defining success metrics with the business shows how to turn the metric into an exact definition with a formula and population; at framing time, the name and unit are enough.
Every baseline carries one of three source labels, from the discovery topic:
Source
Meaning
Use it for a target?
system
Counted from SAP or another system over a stated period
Yes
measured
Timed by you while shadowing real cases
Yes, with the sample size stated
estimate
Someone's guess
Only once measured; until then, label every number built on it
Google's course adds a timing question for success metrics: decide in advance when you will measure them, for example after days, weeks or months. Put that in the date.
#4. Set the target, then check it against the ceiling
A target needs a number and a date. Then check it is possible.
A solution can only change the part of the metric it touches. Call that the addressable share. Discovery measures it: in the course's blocked-order example, 68% of handling time went on gathering information, so an assistant that gathers information addresses at most 68%.
The arithmetic is simple. If the baseline is B and the addressable share is a, then even a perfect solution leaves B × (1 − a).
Frame
Baseline
Addressable
Best case
Target
Verdict
Blocked orders
17 min
68%
5.4 min
10 min
Possible: needs 61% of the addressable part removed
MRP exceptions, first draft
180 min
70% (estimate)
54 min
30 min
Impossible: below the best case
MRP exceptions, revised
180 min
70% (estimate)
54 min
90 min
Possible, but both numbers are estimates
The first MRP draft is the classic "3 hours to 30 minutes" target. It may be right, but only if more than 83% of the time is addressable. Either show that with measurements, widen the scope to touch more of the work, or lower the target.
A target that needs nearly all of the addressable part removed is a warning sign too. Real tools rarely remove every minute of the steps they touch.
#5. Draw the boundary: guardrails, constraints, out of scope
Guardrails are numbers that must not get worse: overdue receivables, shortages reaching production, payments made in error, cash discounts lost.
Constraints are limits the solution must respect: read-only access, the user's own SAP authorizations, a person approving every change, cost per case, response time.
Out of scope lists what the project won't do: automatic release, changing credit limits, changing MRP parameters or master data.
One constraint is not optional in this course. If the output would change SAP data, a person approves it first. The frame says so in writing. SAP's own processes already carry such rules. For invoice release, for example, SAP Learning names the authorization object M_RECH_SPG, which controls which blocking reasons a user may delete. A solution that works on a clerk's behalf must not do more than that clerk may.
The SAP AppHaus Use Case Brief's ethical view is a useful prompt here. It asks about personal data, sensitive personal data, automated decision-making, possible harm to individuals and high-risk domains such as HR. Any "yes" or "not clear yet" belongs in the constraints.
#6. Say what the solution hands over, who acts, and what it must beat
Output: a number, a category, a ranked list, a drafted text, or a proposed change. Google's course says to "predict the decision" the application will take, where possible. The closer the output is to the actor's next step, the more useful it is.
Action: who does what with it, and in which app. "The planner works the list from the top in Manage Material Coverage" is an action. "Nobody, the agent does it" is not.
Benchmark: the best non-AI fix. Google's course says not to build a complex ML solution when a simpler non-ML one will work, and to treat that simpler solution as the benchmark. For blocked invoices, SAP already offers automatic release of invoices whose blocking reasons no longer apply. Any AI has to beat that.
Owner and stop rule: who signs the frame, and what result means stop or rethink.
The whole frame fits in about twenty lines. Writing it as a plain text file means you can check it with a script, keep it in Git, and compare versions as the problem gets sharper. That is what you will build next.
You will build a small command-line tool that checks a problem frame the way a skeptical sponsor would. It flags technology words in the problem, wishes posing as metrics, estimates posing as baselines, targets the solution can't reach, changes to SAP data without approval, and missing guardrails or stop rules. Then it writes the one-sentence problem and a one-page frame for sign-off.
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
S[sample or new] --> F[(frame files)]
F --> L[lint]
L -->|fix and rerun| F
L -->|FRAMED| T[statement]
T --> P[one-page frame for sign-off]
In VS Code, right-click the unit14 folder, choose New File, name it problem_framer.py, paste the code below and save.
"""Problem framer: turn a vague AI request into a framed, measurable problem.
Commands:
sample write three made-up problem frames for SAP processes
new write an empty frame to fill in
lint check one or more frames and say what is missing or weak
statement print the one-sentence problem and write a one-page frame
Uses only Python's built-in modules. No account, no network.
"""
import argparse
import datetime as dt
import re
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
DEFAULT_DIR = HERE / "framing"
# ---------------------------------------------------------------------------
# 1. The fields of a frame. One "FIELD: value" per line; list fields repeat.
# ---------------------------------------------------------------------------
SINGLE = ["ASK", "PROBLEM", "ACTOR", "PROCESS", "UNIT", "METRIC", "DIRECTION", "UNITS",
"BASELINE", "TARGET", "BY", "ADDRESSABLE", "OUTPUT", "ACTION", "CHANGES_SAP",
"BENCHMARK", "OWNER", "STOP"]
MULTI = ["GUARDRAIL", "CONSTRAINT", "OUT"]
REQUIRED = ["PROBLEM", "ACTOR", "PROCESS", "UNIT", "METRIC", "DIRECTION", "UNITS",
"BASELINE", "TARGET", "BY", "ACTION", "OWNER"]
SOURCES = ["system", "measured", "estimate"]
TECH_WORDS = re.compile(
r"\b(ai|a\.i\.|genai|llm|gpt|chatbot|bot|agent|agents|agentic|copilot|joule|"
r"machine learning|ml|model|rag)\b", re.I)
VAGUE_WORDS = re.compile(
r"\b(improve\w*|better|optimi[sz]\w*|efficien\w*|streamlin\w*|enhanc\w*|"
r"faster|quicker|easier|transform\w*|insights?)\b", re.I)
BLANK = """# Problem frame. One FIELD: value per line. Lines starting with # are ignored.
# GUARDRAIL, CONSTRAINT and OUT may appear several times.
ASK: (the request, in the requester's words)
PROBLEM: (the pain in business words, no technology)
ACTOR: (who does the work)
PROCESS: (process and step, e.g. order-to-cash, credit block review)
UNIT: (one case, e.g. one blocked sales order)
METRIC: (what you count, e.g. analyst handling minutes per order)
DIRECTION: down
UNITS: minutes
BASELINE: 0 | measured, (where it came from)
TARGET: 0
BY: 2027-01-31
ADDRESSABLE: 0.5 | measured, (share of the metric the solution can touch)
GUARDRAIL: (what must not get worse, with a limit)
CONSTRAINT: (a limit the solution must respect)
OUT: (what this project will not do)
OUTPUT: (what the solution hands over: a number, a category, a ranked list, a draft)
ACTION: (who does what differently with that output)
CHANGES_SAP: no
BENCHMARK: (the best non-AI fix, to compare against)
OWNER: (who signs this frame)
STOP: (when we stop or rethink)
"""
SAMPLES = {
"blocked_orders.txt": """# Made-up frame for the course's running example (order-to-cash).
ASK: AI to cut the backlog of blocked sales orders
PROBLEM: Credit analysts spend most of each blocked order gathering context from several screens and sales reps
ACTOR: Credit analyst
PROCESS: Order-to-cash, review of sales orders on credit block
UNIT: One credit-blocked sales order
METRIC: Analyst handling minutes per blocked order
DIRECTION: down
UNITS: minutes
BASELINE: 17 | measured, shadowing of 8 orders, discovery week
TARGET: 10
BY: 2027-01-29
ADDRESSABLE: 0.68 | measured, share of handling time spent gathering
GUARDRAIL: Released orders overdue after 30 days rise no more than 1 point
GUARDRAIL: Median hours from block to decision does not get worse
CONSTRAINT: Read-only access to SAP through released APIs, under the analyst's own authorizations
CONSTRAINT: The analyst makes every release or rejection decision
CONSTRAINT: Cost per order below 0.05 USD
OUT: Automatic release or rejection of orders
OUT: Changing credit limits
OUTPUT: A drafted note per order: exposure, open items, order context, with links to sources
ACTION: The analyst reads the note, then releases or rejects in Manage Documented Credit Decisions
CHANGES_SAP: no
BENCHMARK: A saved list layout with exposure and open items, plus a required context field on large orders
OWNER: Head of Credit Management
STOP: If handling time falls less than 3 minutes after four pilot weeks, rethink
""",
"mrp_exceptions.txt": """# Made-up frame for plan-to-produce. Numbers are estimates on purpose.
ASK: We need AI for MRP
PROBLEM: Planners spend the start of each day working through exception messages before they can act on shortages
ACTOR: Production planner
PROCESS: Plan-to-produce, daily review of MRP exceptions
UNIT: One planner working day
METRIC: Minutes per planner per day spent analyzing exceptions
DIRECTION: down
UNITS: minutes
BASELINE: 180 | estimate, the planning lead's estimate in the first interview
TARGET: 30
BY: 2027-03-31
ADDRESSABLE: 0.7 | estimate, share of analysis time spent looking up context
GUARDRAIL: Material shortages that reach production do not increase
CONSTRAINT: Planners keep the decision on every planned order and purchase requisition
OUT: Changing MRP parameters or master data
OUTPUT: A ranked list of today's exceptions, with the likely cause for each
ACTION: The planner works the list from the top in Manage Material Coverage
CHANGES_SAP: no
BENCHMARK: Filter and sort exceptions by the planner's own priority rules in the standard apps
OWNER: Head of Production Planning
""",
"invoice_agent.txt": """# Made-up frame for procure-to-pay, written the way requests often arrive.
ASK: We need an AI agent that clears blocked invoices
PROBLEM: An AI agent should clear the blocked invoice backlog automatically
ACTOR: Accounts payable clerk
PROCESS: Procure-to-pay, invoices blocked for payment after three-way match
UNIT: One blocked supplier invoice
METRIC: Improve efficiency of invoice processing
DIRECTION: down
UNITS: days
BASELINE: 9 | estimate
TARGET: 2
BY: 2027-06-30
OUTPUT: The agent releases the invoice in SAP
ACTION: Nobody, the agent does it
CHANGES_SAP: yes
OWNER: Head of Accounts Payable
""",
}
# ---------------------------------------------------------------------------
# 2. Reading a frame
# ---------------------------------------------------------------------------
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)
def read_frame(path):
"""Read FIELD: value lines into a dict. List fields become lists."""
frame = {name: [] for name in MULTI}
problems = []
for number, raw in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
line = raw.strip()
if not line or line.startswith("#"):
continue
if ":" not in line:
problems.append(f"line {number}: no 'FIELD:' at the start")
continue
name, value = line.split(":", 1)
name, value = name.strip().upper(), value.strip()
if name in MULTI:
frame[name].append(value)
elif name in SINGLE:
if name in frame:
problems.append(f"line {number}: {name} appears twice; keep one")
frame[name] = value
else:
problems.append(f"line {number}: unknown field '{name}'")
return frame, problems
def number_and_source(text):
"""Split '17 | measured, shadowing' into (17.0, 'measured', 'measured, shadowing')."""
value, _, source = text.partition("|")
try:
number = float(value.strip())
except ValueError:
return None, None, source.strip()
kind = source.strip().split(",")[0].strip().lower() if source.strip() else ""
return number, kind, source.strip()
def fmt(x):
return f"{x:g}"
# ---------------------------------------------------------------------------
# 3. The checks. Each returns ("FAIL" | "WARN" | "OK", message).
# ---------------------------------------------------------------------------
def lint(frame, today):
results = []
def add(level, text):
results.append((level, text))
missing = [f for f in REQUIRED if not frame.get(f) or frame[f].startswith("(")]
if missing:
add("FAIL", "Missing fields: " + ", ".join(missing))
for field in ["PROBLEM", "METRIC", "TARGET"]:
hit = TECH_WORDS.search(frame.get(field, ""))
if hit:
add("FAIL", f"{field} names a technology ('{hit.group(0)}'). "
"Describe the business problem; choose the technology later.")
vague = VAGUE_WORDS.search(frame.get("METRIC", ""))
if vague:
add("FAIL", f"METRIC is a wish ('{vague.group(0)}'), not a count. "
"Say what you count per case, e.g. 'minutes per order'.")
direction = frame.get("DIRECTION", "").lower()
if direction and direction not in ("down", "up"):
add("FAIL", "DIRECTION must be 'down' (lower is better) or 'up'.")
baseline, kind, source = number_and_source(frame.get("BASELINE", ""))
target, _, _ = number_and_source(frame.get("TARGET", ""))
if frame.get("BASELINE") and baseline is None:
add("FAIL", "BASELINE must start with a number, e.g. '17 | measured, shadowing'.")
elif baseline is not None:
if kind not in SOURCES:
add("FAIL", "BASELINE needs a source type after '|': system, measured or estimate.")
elif kind == "estimate":
add("WARN", "BASELINE is an estimate. Measure it, or label every number built on it as an estimate.")
elif "," not in source:
add("WARN", "BASELINE says its type but not where it came from (report, period, cases).")
if frame.get("TARGET") and target is None:
add("FAIL", "TARGET must be a number in the same units as the baseline.")
if baseline is not None and target is not None and direction in ("down", "up"):
if (direction == "down" and target >= baseline) or (direction == "up" and target <= baseline):
add("FAIL", f"TARGET {fmt(target)} does not move the metric {direction} from {fmt(baseline)}.")
elif baseline != 0:
change = abs(target - baseline) / abs(baseline)
add("OK", f"Target asks for a {change:.0%} change ({fmt(baseline)} to {fmt(target)} {frame.get('UNITS', '')}).")
# Ceiling check: a solution that only touches part of the metric can't remove more than that part.
share_text = frame.get("ADDRESSABLE")
if direction == "down" and baseline and target is not None:
if not share_text:
add("WARN", "No ADDRESSABLE share, so no ceiling check. What part of the metric can the solution touch?")
else:
share, share_kind, _ = number_and_source(share_text)
if share is None or not 0 < share <= 1:
add("FAIL", "ADDRESSABLE must be a share between 0 and 1, e.g. '0.68 | measured, ...'.")
else:
floor = baseline * (1 - share)
needed = (baseline - target) / (baseline * share)
if target < floor:
add("FAIL", f"Ceiling: removing all of the addressable {share:.0%} still leaves {fmt(round(floor, 1))}. "
f"Target {fmt(target)} is below that. Lower the ambition or widen the scope.")
elif needed > 0.8:
add("WARN", f"Ceiling: the target needs {needed:.0%} of the addressable time removed. Possible, rarely achieved.")
else:
add("OK", f"Ceiling: best case is {fmt(round(floor, 1))}; the target needs {needed:.0%} of the addressable part.")
if share_kind == "estimate":
add("WARN", "ADDRESSABLE is an estimate. Time real cases before you promise the target.")
by = frame.get("BY", "")
if by and not by.startswith("("):
try:
when = dt.date.fromisoformat(by)
if when <= today:
add("WARN", f"BY {by} is not in the future.")
except ValueError:
add("FAIL", "BY must be a date written YYYY-MM-DD.")
if not frame["GUARDRAIL"]:
add("WARN", "No GUARDRAIL. What must not get worse while the metric moves?")
if not frame["CONSTRAINT"]:
add("WARN", "No CONSTRAINT. Name data access, authorizations, approvals, cost or latency limits.")
if not frame["OUT"]:
add("WARN", "No OUT line. Say what this project will not do, so scope can't creep.")
if not frame.get("OUTPUT"):
add("WARN", "No OUTPUT. Say what the solution hands over: a number, a category, a ranked list or a draft.")
action = frame.get("ACTION", "")
if action and re.search(r"\b(nobody|no one|none|automatic\w*)\b", action, re.I):
add("FAIL", "ACTION has no person in it. Name who acts on the output, and how.")
changes = frame.get("CHANGES_SAP", "no").lower()
if changes not in ("yes", "no"):
add("FAIL", "CHANGES_SAP must be yes or no.")
elif changes == "yes" and not any(re.search(r"approv", c, re.I) for c in frame["CONSTRAINT"]):
add("FAIL", "The output changes SAP data, but no CONSTRAINT requires a person's approval first.")
if not frame.get("BENCHMARK"):
add("WARN", "No BENCHMARK. What is the best non-AI fix? The AI has to beat it.")
if not frame.get("STOP"):
add("WARN", "No STOP rule. Agree now what result means stop or rethink.")
return results
def verdict(results):
fails = sum(1 for level, _ in results if level == "FAIL")
warns = sum(1 for level, _ in results if level == "WARN")
if fails:
return f"NOT FRAMED: {fails} to fix, {warns} to consider"
return f"FRAMED: 0 to fix, {warns} to consider"
# ---------------------------------------------------------------------------
# 4. The one-sentence problem and the one-page frame
# ---------------------------------------------------------------------------
def sentence(frame):
baseline, kind, _ = number_and_source(frame["BASELINE"])
target, _, _ = number_and_source(frame["TARGET"])
verb = "reduce" if frame["DIRECTION"].lower() == "down" else "increase"
units = frame["UNITS"]
text = (f"For the {frame['ACTOR'][0].lower() + frame['ACTOR'][1:]} ({frame['PROCESS'][0].lower() + frame['PROCESS'][1:]}): {verb} "
f"{frame['METRIC'][0].lower() + frame['METRIC'][1:]} from {fmt(baseline)} {units} ({kind}) "
f"to {fmt(target)} {units} by {frame['BY']}")
if frame["GUARDRAIL"]:
text += ", while " + "; ".join(g[0].lower() + g[1:] for g in frame["GUARDRAIL"])
return text + "."
LABELS = {"CHANGES_SAP": "Changes SAP data", "BY": "By (date)", "STOP": "Stop rule"}
def one_page(frame, results):
lines = ["# Problem frame", "", f"**The ask:** {frame.get('ASK', '(not recorded)')}", "",
f"**The problem:** {sentence(frame)}", "",
"| Field | Value |", "| --- | --- |"]
for name in ["PROBLEM", "ACTOR", "PROCESS", "UNIT", "METRIC", "BASELINE", "TARGET", "BY",
"ADDRESSABLE", "OUTPUT", "ACTION", "CHANGES_SAP", "BENCHMARK", "OWNER", "STOP"]:
if frame.get(name):
label = LABELS.get(name, name.title())
lines.append(f"| {label} | {frame[name].replace('|', chr(92) + '|')} |")
for title, name in [("Guardrails", "GUARDRAIL"), ("Constraints", "CONSTRAINT"), ("Out of scope", "OUT")]:
lines += ["", f"## {title}", ""] + [f"- {item}" for item in frame[name] or ["(none)"]]
lines += ["", "## Open points", ""]
open_points = [f"- {level}: {text}" for level, text in results if level != "OK"]
lines += open_points or ["- none"]
lines += ["", f"_{verdict(results)}. Sign-off: {frame.get('OWNER', '(owner)')}_", ""]
return "\n".join(lines)
# ---------------------------------------------------------------------------
# 5. Commands
# ---------------------------------------------------------------------------
def load(path_text):
path = Path(path_text)
if not path.exists():
sys.exit(f"No frame at {path_text}. Run 'sample' first, or check the path.")
frame, problems = read_frame(path)
return path, frame, problems
def cmd_sample(args):
base = Path(args.dir)
base.mkdir(parents=True, exist_ok=True)
targets = [base / name for name in SAMPLES]
if any(p.exists() for p in targets) and not args.force:
sys.exit(f"Sample frames already exist in {show(base)}. Use --force to overwrite them.")
for name, text in SAMPLES.items():
(base / name).write_text(text, encoding="utf-8")
print(f"Wrote {len(SAMPLES)} frames to {show(base)}: " + ", ".join(SAMPLES))
print("All of them are made up. Next: python unit14/problem_framer.py lint \"unit14/framing/*.txt\"")
def cmd_new(args):
path = Path(args.out)
if path.exists() and not args.force:
sys.exit(f"{show(path)} already exists. Pick another name or use --force.")
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(BLANK, encoding="utf-8")
print(f"Wrote an empty frame to {show(path)}. Fill in every line, then run lint on it.")
def cmd_lint(args):
today = dt.date.fromisoformat(args.today) if args.today else dt.date.today()
files = []
for pattern in args.files: # PowerShell doesn't expand *.txt, so do it here
matches = sorted(Path().glob(pattern)) if any(c in pattern for c in "*?") else [Path(pattern)]
files += matches
if not files:
sys.exit("No frames matched. Run 'sample' first, or check the path.")
framed = 0
for path in files:
path, frame, problems = load(str(path))
results = [("FAIL", p) for p in problems] + lint(frame, today)
print(f"== {show(path)}")
for level, text in results:
print(f" {level:<4} {text}")
print(f" -> {verdict(results)}")
print()
framed += verdict(results).startswith("FRAMED")
print(f"{framed} of {len(files)} frames ready for the opportunity assessment.")
def cmd_statement(args):
today = dt.date.fromisoformat(args.today) if args.today else dt.date.today()
path, frame, problems = load(args.file)
results = [("FAIL", p) for p in problems] + lint(frame, today)
if any(level == "FAIL" for level, _ in results):
print(verdict(results) + ". Run lint and fix the FAIL lines first.")
return 1
print(sentence(frame))
out = path.with_name(path.stem + "_frame.md")
out.write_text(one_page(frame, results), encoding="utf-8")
print(f"Wrote {show(out)}")
return 0
def main(argv=None):
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
sub = p.add_subparsers(dest="cmd", required=True)
s = sub.add_parser("sample", help="write three made-up frames")
s.add_argument("--dir", default=str(DEFAULT_DIR), help="folder for the frames (default: unit14/framing)")
s.add_argument("--force", action="store_true", help="overwrite existing sample frames")
n = sub.add_parser("new", help="write an empty frame")
n.add_argument("out", help="file to create, e.g. unit14/framing/my_frame.txt")
n.add_argument("--force", action="store_true")
l = sub.add_parser("lint", help="check frames")
l.add_argument("files", nargs="+")
l.add_argument("--today", help="pretend today is this date (YYYY-MM-DD)")
t = sub.add_parser("statement", help="print the problem sentence and write a one-page frame")
t.add_argument("file")
t.add_argument("--today", help="pretend today is this date (YYYY-MM-DD)")
args = p.parse_args(argv)
handler = {"sample": cmd_sample, "new": cmd_new, "lint": cmd_lint, "statement": cmd_statement}[args.cmd]
return handler(args) or 0
if __name__ == "__main__":
sys.exit(main())
Wrote 3 frames to unit14/framing: blocked_orders.txt, mrp_exceptions.txt, invoice_agent.txt
All of them are made up. Next: python unit14/problem_framer.py lint "unit14/framing/*.txt"
Open unit14/framing/blocked_orders.txt. Each line is one field:
Field
What it holds
ASK
The request, in the requester's words. Technology words are fine here
PROBLEM
The pain in business words. No technology
ACTOR, PROCESS, UNIT
Who does the work, which process step, and what one case is
METRIC, DIRECTION, UNITS
What you count per case, whether lower (down) or higher (up) is better, and its unit
BASELINE
Today's value, then |, then system, measured or estimate and where it came from
TARGET, BY
The promised value and the date, written YYYY-MM-DD
ADDRESSABLE
The share of the metric the solution can touch, between 0 and 1, with its source
GUARDRAIL, CONSTRAINT, OUT
What must not get worse, limits to respect, and what is out of scope. Each may appear several times
OUTPUT, ACTION
What the solution hands over, and who does what with it
CHANGES_SAP
yes if the output would change SAP data, otherwise no
BENCHMARK
The best non-AI fix
OWNER, STOP
Who signs the frame, and the result that means stop or rethink
If you see Sample frames already exist, you ran this before. Add --force to overwrite them.
== unit14/framing/blocked_orders.txt
OK Target asks for a 41% change (17 to 10 minutes).
OK Ceiling: best case is 5.4; the target needs 61% of the addressable part.
-> FRAMED: 0 to fix, 0 to consider
== unit14/framing/invoice_agent.txt
FAIL PROBLEM names a technology ('AI'). Describe the business problem; choose the technology later.
FAIL METRIC is a wish ('Improve'), not a count. Say what you count per case, e.g. 'minutes per order'.
WARN BASELINE is an estimate. Measure it, or label every number built on it as an estimate.
OK Target asks for a 78% change (9 to 2 days).
WARN No ADDRESSABLE share, so no ceiling check. What part of the metric can the solution touch?
WARN No GUARDRAIL. What must not get worse while the metric moves?
WARN No CONSTRAINT. Name data access, authorizations, approvals, cost or latency limits.
WARN No OUT line. Say what this project will not do, so scope can't creep.
FAIL ACTION has no person in it. Name who acts on the output, and how.
FAIL The output changes SAP data, but no CONSTRAINT requires a person's approval first.
WARN No BENCHMARK. What is the best non-AI fix? The AI has to beat it.
WARN No STOP rule. Agree now what result means stop or rethink.
-> NOT FRAMED: 4 to fix, 7 to consider
== unit14/framing/mrp_exceptions.txt
WARN BASELINE is an estimate. Measure it, or label every number built on it as an estimate.
OK Target asks for a 83% change (180 to 30 minutes).
FAIL Ceiling: removing all of the addressable 70% still leaves 54. Target 30 is below that. Lower the ambition or widen the scope.
WARN ADDRESSABLE is an estimate. Time real cases before you promise the target.
WARN No STOP rule. Agree now what result means stop or rethink.
-> NOT FRAMED: 1 to fix, 3 to consider
1 of 3 frames ready for the opportunity assessment.
Read it like a sponsor would:
Blocked orders is framed. Its numbers are measured, its target is within reach, and it has guardrails, constraints and a stop rule.
The invoice agent is a request, not a problem. It names a technology, has no real metric, lets software change SAP data with nobody approving, and leaves out everything that protects the business.
MRP exceptions is almost there, but its "3 hours to 30 minutes" target is below what the solution could achieve even if it removed every addressable minute.
FAIL lines must be fixed before the frame is signed. WARN lines are for discussion: a frame can be signed with warnings, as long as the owner has seen them.
Open unit14/framing/invoice_agent.txt, select everything, and replace it with:
# Reframed: procure-to-pay invoices blocked for payment.
ASK: We need an AI agent that clears blocked invoices
PROBLEM: Clerks spend most of each blocked invoice finding out why it is blocked and whether the reason still holds
ACTOR: Accounts payable clerk
PROCESS: Procure-to-pay, invoices blocked for payment after three-way match
UNIT: One blocked supplier invoice
METRIC: Clerk handling minutes per blocked invoice
DIRECTION: down
UNITS: minutes
BASELINE: 22 | measured, shadowing of 10 invoices
TARGET: 12
BY: 2027-06-30
ADDRESSABLE: 0.6 | measured, share of handling time spent finding the cause
GUARDRAIL: Payments made in error do not increase
GUARDRAIL: Cash discounts lost do not increase
CONSTRAINT: The clerk approves every release; the solution only proposes
CONSTRAINT: Read access only to the documents the clerk is authorized to see
OUT: Releasing invoices without a clerk
OUT: Changing purchase orders or goods receipts
OUTPUT: Per blocked invoice: the blocking reasons, the likely cause, and a proposed next step
ACTION: The clerk checks the proposal, then releases, asks the buyer, or waits for the goods receipt
CHANGES_SAP: no
BENCHMARK: Schedule SAP's automatic release of invoices whose blocking reasons no longer apply
OWNER: Head of Accounts Payable
STOP: If the scheduled automatic release clears most of the backlog on its own, stop here
== unit14/framing/invoice_agent.txt
OK Target asks for a 45% change (22 to 12 minutes).
OK Ceiling: best case is 8.8; the target needs 76% of the addressable part.
-> FRAMED: 0 to fix, 0 to consider
1 of 1 frames ready for the opportunity assessment.
Look at what changed. The ask is still recorded, word for word, but the problem no longer mentions an agent. The output is a proposal, so CHANGES_SAP is no. And the benchmark and stop rule admit that a standard SAP function might solve most of this without any AI.
For the credit analyst (order-to-cash, review of sales orders on credit block): reduce analyst handling minutes per blocked order from 17 minutes (measured) to 10 minutes by 2027-01-29, while released orders overdue after 30 days rise no more than 1 point; median hours from block to decision does not get worse.
Wrote unit14/framing/blocked_orders_frame.md
Open unit14/framing/blocked_orders_frame.md. Right-click its tab and choose Open Preview to see it formatted. It holds the ask, the one-sentence problem, a table of every field, the guardrails, constraints and out-of-scope items, and the open points from the check.
You should see NOT FRAMED: 1 to fix, 3 to consider. Run lint and fix the FAIL lines first. The tool won't write a sign-off page for a frame with FAIL lines.
The fields a frame may have, which may repeat, and which must be filled in
TECH_WORDS, VAGUE_WORDS
Word patterns for technology names and for wishes such as "improve" or "faster"
read_frame()
Reads FIELD: value lines, skips # comments, and reports unknown fields and duplicates
number_and_source()
Splits 17 | measured, shadowing into the number, the source type and the note
lint()
Runs every check and returns OK, WARN or FAIL lines
The ceiling check inside lint()
Computes the best case, baseline × (1 − addressable share), and fails a target below it; warns when the target needs more than 80% of the addressable part
verdict()
FRAMED when there is no FAIL, otherwise NOT FRAMED, with counts
sentence(), one_page()
Build the one-sentence problem and the Markdown page for sign-off
cmd_lint()
Expands a glob itself, because PowerShell doesn't, then checks each file
The checks are heuristics, not rules of grammar. A metric called "faster delivery share" would be flagged as a wish even if it is well defined; rename it, or adjust VAGUE_WORDS. The 80% warning limit is a judgement call too. The point is that the checks are written down, so the owner can see what "framed" means.
SAP has no framing tool. It has workshop methods that feed a frame, catalogs to compare it with, and the applications where the actor works. As of October 2026:
The Business AI Explore Workshop facilitation guide (Release V2) is built for 3 to 10 people from business and IT, as a full day on site, 2½ days virtual, or a 3-hour mini format. Its full format starts from challenges, not from AI. Its materials map onto a frame like this:
AppHaus material
What it captures
Where it goes in the frame
Existing Challenge template
The activity to improve, why, and who is affected
PROBLEM, ACTOR, PROCESS
Use Case Brief, business view
Purpose and value for the business and end users
PROBLEM, first draft of METRIC
Use Case Brief, technical view
Data and systems needed, expected capabilities, limitations
CONSTRAINT, input for the opportunity assessment
Use Case Brief, ethical view
Personal data, automated decisions, effects on individuals, high-risk domains
CONSTRAINT, OUT
Value Heatmap
Ideas placed on agreed criteria such as business value and complexity
Which candidates to frame first
Next Steps Matrix
4 to 5 action items with owners and deadlines
Who measures the baseline, who signs
The Business AI Design Workshop goes one step further for a chosen use case. Its Capability Idea Napkin records input data, expected output and a verification step, and its to-be scenario names a trigger, a moment of success and the impact. Those map to OUTPUT, ACTION and GUARDRAIL.
What the workshops don't produce is a measured baseline, a ceiling check or a stop rule. That is the FDE's part.
A frame's ACTION line should name a real app. For the three running examples, SAP Learning and SAP's own teams describe:
Credit blocks (order-to-cash). An automatic credit check blocks sales orders that exceed the credit limit, and a credit case is assigned to an analyst. The analyst releases or rejects in Manage Documented Credit Decisions. If the block comes from a limit shortfall, a credit controller can approve a request in Manage Credit Limit Requests.
MRP exceptions (plan-to-produce). Planners review results in Monitor Stock/Requirements List (MD04), Manage Material Coverage (F02510) and Monitor Material Coverage - Net and Individual Segments. A post by SAP's S/4HANA RIG team shows situation handling for MRP exception messages, based on the template SAP_PP_MRP_MATERIAL_EXCEPTION, and stresses that it supplements, rather than replaces, daily exception monitoring.
Blocked supplier invoices (procure-to-pay). Invoices are released with Release Blocked Invoices (transaction MRBR), also available as a Fiori app. Invoices blocked due to variances can be released automatically when their blocking reasons no longer apply, also as a background job with program RM08RELEASE. The authorization object M_RECH_SPG controls which blocking reasons a user may delete.
The last point is why the invoice frame's benchmark is "schedule SAP's automatic release". It is a standard function that may clear part of the backlog with no new software. Check whether the customer already runs it before you frame an AI project around the backlog.
The SAP Business AI Feature Catalog in SAP Discovery Center lists embedded AI features with use cases, value and metrics, grouped by release stage. The Feature Estimator estimates the AI units a feature would need. Once a frame is written without technology, search the catalog for the process step. If an embedded feature targets the same step, the opportunity assessment should compare it with building, as Buy vs. build for SAP AI describes. SAP's value figures are a reason to look, not your baseline.
Frames are commitments. A signed frame sets expectations about money and people's time. Keep it in version control, and change it openly, with the owner, when evidence changes it.
SAP authorizations belong in the frame. A solution that reads or proposes on a user's behalf must stay within that user's authorizations. Write it as a constraint, so the design topic can't forget it. Agent permissions and SAP authorizations covers how to enforce it.
Human approval for changes. If any output would change SAP data or configuration, the frame requires a person's approval first. This is a design input, not a later control.
Personal data and automated decisions. Answer the ethical questions of the AppHaus brief early. A frame in a high-risk domain such as HR needs more constraints, and may need people outside the project to agree.
Baselines from system data. Pulling an extract to measure a baseline needs the data owner's approval and an authorized person. Ask only for the fields the metric needs.
Cost in the frame. A cost-per-case limit, written as a constraint, stops a design that works but costs more than the time it saves. Token economics shows how to estimate it.
Clean core. Framing changes nothing in SAP. A frame that lists "changing SAP code or configuration" under OUT keeps later designs side by side, as CAP and side-by-side extensions explains.
Check the last lines. The ceiling line now says best case is 54; the target needs 71% of the addressable part, and the verdict is FRAMED: 0 to fix, 2 to consider. The two warnings are the estimates. They stay until someone times real planner days.
It writes unit14/framing/mrp_exceptions_frame.md, with the two estimates listed under Open points.
Create a frame for your own problem. If my_frame.txt already exists from Use your own frames, skip this step.
python unit14/problem_framer.py new unit14/framing/my_frame.txt
Fill it in from unit14/discovery/problem_hypothesis.md, your discovery exercise. Copy the ask word for word into ASK. Use the baseline numbers and their source labels from the hypothesis. If you have no discovery notes, frame a problem from your own work, or use the delivery example: "predict which deliveries will be late".
Run lint on my_frame.txt until it shows no FAIL lines. Then run statement on it.
Save your work:
git add unit14/problem_framer.py unit14/framing/
git commit -m "Unit 14: problem framer and framed problems"
Done whenmrp_exceptions.txt shows FRAMED: 0 to fix, 2 to consider, my_frame.txt shows FRAMED, and my_frame_frame.md exists with your one-sentence problem. Keep them: the opportunity assessment, next in Unit 14, decides whether each framed problem needs AI, automation or neither.
Pick one answer for each question. The explanation appears after you choose.
1Which PROBLEM line is framed well enough for the checker to accept?
Answer: B. The framed line describes who does what and where the time goes, with no technology. The first and third name a solution, and the fourth is a wish, which lint flags as vague.
2A frame has baseline 180 minutes, addressable share 0.7 and target 30. What does the ceiling check report, and why?
Answer: C. The best case is baseline × (1 − share) = 180 × 0.3 = 54 minutes. A target of 30 is below what a perfect solution could reach, so the frame fails until the target, the scope or the measured share changes.
3Why does lint treat estimate baselines as a warning rather than a failure?
Answer: D. Early frames often start from estimates. A warning keeps the frame moving while making the gap visible; the one-page frame lists it under open points until someone measures it.
4The output of a proposed solution would release invoices in SAP. Which frame passes the approval check?
Answer: D. Any output that changes SAP data needs a person's approval written as a constraint. A guardrail measures harm after the fact; it doesn't stop an unapproved change.
5Why does the invoice frame's benchmark name SAP's automatic release of invoices whose blocking reasons no longer apply?
Answer: A. Google's framing guidance treats the simpler non-AI solution as the benchmark. If the scheduled automatic release clears most of the backlog, the stop rule ends the project before anything is built.
6An ACTION line says "Nobody, the agent does it". What is the problem?
Answer: D. The frame's action names who does what with the output, and where. A prediction or proposal only has value when it changes someone's next step; "nobody" also hides who approves changes.
7You run lint "unit14/framing/*.txt" in PowerShell and it works, but a colleague's own script fails with the same pattern. What is the likely reason?
Answer: B. macOS and Linux shells expand * before the script runs; PowerShell passes it through unchanged. cmd_lint() expands the glob itself, so the same command works on both.
8During the pilot, the owner asks to add four more equal "success metrics" to the frame. What do you do?
Answer: C. With several equal metrics, some improve by chance and get quoted. One primary metric with explicit guardrails keeps the decision clear; changes to a signed frame are made openly, with the owner, not silently.
Ask a question
Testing: only staff see this
Stuck on something in this layer? Ask it here. Questions are answered in the order they arrive, and the answer appears under My questions.
Sign in (free) to ask a question. You can ask anonymously.
Related topics
Picked from the terms, links and tags this topic shares with others.
Planning Using MRP Live (SAP Learning)— Monitor Stock/Requirements List (MD04), Manage Material Coverage (F02510), Monitor Material Coverage - Net and Individual Segments