Fit-to-standard and extension choices: where each requirement should live
Decide for each requirement whether it needs configuration, a process change, a standard feature, an extension or nothing, and defend the call with evidence.
Every SAP program collects hundreds of requirements. Each one has to land somewhere. There are only six places it can go:
Configuration. SAP already does it; someone sets it up.
A process change. SAP does it differently, and the business adopts SAP's way.
A standard feature not yet in scope. SAP has an app or product for it that nobody switched on.
A side-by-side extension. Something new is built next to SAP, on SAP's cloud platform.
An on-stack extension. Something new is built inside SAP, using the doors SAP keeps stable.
Nothing. The requirement isn't needed, and the program says no.
Fit-to-standard is SAP's method for sorting requirements into those places. Experts show the business how standard SAP runs a process, and the business says what truly doesn't fit. Only those gaps go on the list of things to build. The goal is a short list, because everything built has to be tested and paid for at every upgrade for as long as it lives.
This topic shows how a solution architect makes that call, using Calder Pumpworks, the fictional pump maker this unit follows. Ten real-looking Calder requests get one decision each.
The decision looks small, one request at a time. Added up, it decides what the system costs to run.
Every extension is a running cost. SAP's own training warns that each change to a standard process adds maintenance work at every release upgrade (SAP Learning). A program that builds 300 extensions has signed up to retest 300 things, every upgrade, for a decade.
The way it is built matters as much as whether it is built. SAP rates extensions from level A, built only on interfaces SAP keeps stable, to level D, such as changing SAP's own code or writing into SAP's tables (SAP Learning). Level D work can break at any upgrade and makes the next one slower and dearer.
Old habits hide in requirements. Many requests are "make it work like the old system". At Calder, the German company CP20 is moving from ECC into the US company's S/4HANA system. Augsburg's buyers ask to keep a program that writes delivery dates straight into purchase orders. It works today; in the new system, it is the riskiest kind of change.
Saying no saves the most money. A report nobody ran last year costs nothing to retire. Rebuilt, it costs a build plus every future upgrade.
A concrete case: in order-to-cash, Calder's sales director wants to release credit-blocked orders himself, by phone. Standard SAP already sends blocked orders to a credit analyst, who releases them in a standard app. The right answer is a process change, not a new approval screen, and it also keeps the person who sells apart from the person who approves credit.
As of October 2026, SAP supports this decision with a method, a few tools and a rating scale:
SAP Activate, SAP's implementation method, runs the fit-to-standard analysis in its Explore phase. Experts demonstrate standard processes, the team identifies the "delta" requirements that don't fit, and the product owner validates each one before it joins the backlog for the build phase (SAP Learning).
SAP Signavio Process Navigator supplies the standard process flows and test scripts used in the workshops, and SAP Cloud ALM records the requirements and tracks them through build and test (SAP Learning).
Three ways to extend when a gap is real: key user tools (apps that add fields, rules, forms and reports without programming), developer extensibility with ABAP Cloud (code inside S/4HANA that uses only released SAP objects), and side-by-side apps on SAP Business Technology Platform (BTP). Private edition and on-premise systems also allow classic extensibility, which can change any SAP object and is the least stable (SAP Learning).
Clean core levels A to D give leaders one scale for all of it. SAP calls the model "a shared vocabulary" for assessing a landscape, and its messaging recommends an "SAP BTP-first strategy" (SAP News, August 2025).
A Solution Standardization Board is SAP's suggested governance body: it reviews every proposed deviation from standard and records why it was accepted, so the extension can be removed when the standard catches up (SAP Learning).
The workshop technique itself (who attends, how to run the room) belongs to the solution architect's job and is covered in the solution architect on an SAP program. This topic is about the decision each workshop feeds.
#A decision guide: where each requirement should live
Ask the questions in this order. The first "yes" decides.
#
Question
If yes
Calder example
1
Is there evidence the business needs it: a law, a contract, a measured KPI, actual usage?
If no: decline it, and record why
Augsburg's open-PO aging report: zero runs in 14 months
2
Does standard SAP do it with configuration?
Configuration
Approval of purchase orders above 25,000 USD
3
Can the business adopt SAP's standard way instead?
Process change
Credit releases by the analyst, not by phone
4
Is there a standard SAP feature or product nobody has switched on?
Add it to scope
Capacity planning for the pump test bench
5
Do people outside S/4HANA use it, or must it change on its own schedule?
Side-by-side on SAP BTP
Order status for distributors
6
Is it a small last-mile change: a field, rule, form or report?
Key user extension
Test certificate number on orders
7
Otherwise
Developer extension (ABAP Cloud)
Monthly intercompany price calculation
Two rules sit across the table. First, every extension is rated A to D, and anything below level B needs the standardization board's written approval. Second, "the old system did it" is not evidence. Usage data, a regulation or a number the business is measured on is.
"Fit-to-standard means no customization." It means the gaps are real and justified. Some extensions are worth their cost; the point is to know which ones.
"Side-by-side is always cleaner." It is upgrade-stable, but it is a second application to run, secure and pay for. A key user field is cheaper than a BTP app for a last-mile change.
"Classic ABAP is forbidden in private edition." It is allowed, and SAP rates extensions on classic APIs as level B, low risk. What SAP calls not recommended is level D: modifications and writes into SAP tables.
"The partner decides what gets built." The business owns the requirements and their cost. The partner and the architect advise; a product owner or board decides.
"We can clean up later." Every upgrade before the clean-up costs extra testing, and later rarely comes.
Pick one answer for each question. The explanation appears after you choose.
1A department asks to rebuild a custom ECC report in S/4HANA. What is the first thing to establish?
Answer: D. The decision guide starts with evidence of need. A report with no recorded use is declined, which costs nothing; choosing how to build it only matters once the need is proven.
2Calder's sales director wants to release credit-blocked orders himself, by phone. Standard SAP routes them to a credit analyst. What is the right call?
Answer: A. Standard SAP already handles the need, and adopting it keeps selling and credit approval with different people. The need is real, so declining is wrong; building an app would add cost to undo a sound control.
3Why does SAP training warn against changing standard processes during fit-to-standard?
Answer: C. Each deviation has to be retested and maintained whenever SAP upgrades the system. That is why workshops keep only the requirements that are truly needed.
4Distributors want to check order status online, and they have no SAP users. Where should this requirement live?
Answer: D. The users are outside S/4HANA, which points to a side-by-side app that reads S/4HANA through stable APIs. A modification would be clean core level D, the riskiest kind of change.
5What does a clean core level tell an executive about an extension?
Answer: B. Levels A to D rate how an extension is built, from released, stable interfaces at A to modifications and table writes at D. The lower the level, the more each upgrade can break it.
6Who should own the final decision on whether a gap is built?
Answer: D. In SAP Activate the product owner validates deltas before they enter the backlog, and SAP suggests a standardization board that approves and records deviations. Partners and architects advise; the business owns the cost.
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.
Treat every requirement as a liability with a lifetime, not as a feature request. Configuration is a liability SAP shares with you: it runs on code SAP maintains through every upgrade, so you regression-test your processes but nothing of yours breaks underneath. An extension is a liability you carry alone: you build it once and retest it at every upgrade until you delete it. The fit-gap decision is therefore a cost decision with a long tail, and it has a strict order:
Is the requirement real? If not, the liability is zero.
Can SAP carry it (configuration, a process change, a standard feature)? Then SAP carries most of it.
Only if both fail, build, and build at the highest clean core level available, because the level sets the size of the tail.
Two numbers make the tail visible: how many upgrades the extension will live through, and how much each one costs to retest it. In this topic's cost model, a level A extension costs half a day of retesting per upgrade and a level D one costs eight days; those are course inputs, not SAP figures. The real difference is worse than any estimate: a program that writes into SAP tables can fail outright when SAP changes the table underneath it.
SAP Activate puts the fit-to-standard analysis in the Explore phase. As SAP Learning describes it (opened 28 October 2026):
Preparation. Scope comes from the earlier phases (for Public Edition, the Digital Discovery Assessment). The business answers the Business-Driven Configuration Questionnaire, which supplies configuration values. Experts download test scripts from SAP Signavio Process Navigator and run them in a starter system, a system preconfigured with SAP Best Practices (SAP Learning).
Workshops. Experts execute each in-scope process in the starter system, the business judges the fit, and requirements are recorded. The workshops are time-boxed so the whole scope is covered. In private cloud projects, the configuration step also covers WRICEF objects (workflows, reports, interfaces, conversions, enhancements and forms); in Public Edition they are less common because there is less to extend (SAP Learning).
Validation and backlog. The product owner validates the deltas, prioritizes the backlog, and only the top items go to design workshops; the rest wait for refinement (same source).
Tracking. In SAP Cloud ALM, a requirement is created from a solution process, approved, refined into user stories, and grouped into a feature that creates or is assigned transports; test cases attach to the requirement or its stories (SAP Learning).
The architect's job sits between the workshop and the backlog: turning "we need X" into a classified, rated, costed decision.
Before deciding, classify each gap along three axes. The register needs all three.
Axis
Values
Why it matters
Evidence
Law or regulation, contract, measured KPI, usage data, none
No evidence, no build. "The old system did it" isn't evidence
Object type
Field, rule, form, report, workflow, interface, conversion, new app
Points to the tool: fields and forms to key user apps, new apps to side-by-side or ABAP Cloud
Coupling
Who uses it (S/4HANA users or outsiders); must it change in the same transaction as SAP data?
Outsiders and loose coupling point side-by-side; same-transaction logic points on-stack
Interfaces and conversions are gaps too, but they have their own design homes: integration architecture in Unit 5B, and data migration later in this unit.
flowchart TD
R[Requirement] --> E{Evidence of need?}
E -- no --> N[Nothing: decline,<br/>record evidence]
E -- yes --> C{Configuration<br/>covers it?}
C -- yes --> CF[Configuration]
C -- no --> P{Can the business<br/>adopt standard?}
P -- yes --> PC[Process change]
P -- no --> F{Standard feature<br/>not yet in scope?}
F -- yes --> SF[Standard feature]
F -- no --> O{Users outside S/4HANA<br/>or own lifecycle?}
O -- yes --> SBS[Side-by-side<br/>on SAP BTP]
O -- no --> L{Last-mile:<br/>field, rule, form, query?}
L -- yes --> KU[Key user]
L -- no --> DEV[Developer:<br/>ABAP Cloud]
SBS --> LV[Rate A to D]
KU --> LV
DEV --> LV
LV --> SSB{Below level B?}
SSB -- yes --> B[Board approval<br/>or redesign]
SSB -- no --> BL[Backlog]
The order of questions 5 to 7 follows SAP's guidance. SAP's training says to exhaust key user options first and move to side-by-side for more complex extensions, and to check the SAP Store and the SAP Certified Solutions Directory for a partner solution before building anything fully custom (SAP Learning). SAP's older extensibility training adds the criteria that split on-stack from side-by-side: who the users are, how tightly the data must change together, the kind of scenario, and whose lifecycle the extension follows (SAP Learning). That training still lists ABAP custom development as on-premise only, which no longer matches private edition, so use its criteria, not its list of tools.
Web-based SAP Fiori apps: UI adaptation, Custom Fields, Custom Business Logic, Custom Business Objects, Custom CDS Views, Custom Analytical Queries, KPIs and Custom Forms
SAP's level model replaced the earlier three-tier model; SAP's training says the tier model is sunset (SAP Learning).
Level
Built on
Upgrade risk
A
Released APIs and extension points with stability contracts: key user, ABAP Cloud, side-by-side on BTP
Lowest; matches how Public Edition is extended
B
Classic APIs, such as BAPIs, documented and generally upgrade-stable
Low; the next option when no released API exists
C
SAP internal objects, such as reading tables not meant for customers
Can change without notice; manage with SAP's changelog
D
Modifications, writes to SAP tables, implicit enhancements
Highest; SAP recommends remediation
An extension takes the level of the lowest technique it uses. One direct table write makes an otherwise clean app level D.
Where the level comes from in practice. SAP publishes the state of its objects in the Cloudification Repository on GitHub. The ABAP test cockpit (ATC) reads those files to check custom code, and SAP's clean core check, available since August 2025, uses the ATC checks "Usage of APIs" and "Allowed Enhancement Technologies" (SAP on GitHub). In the private cloud file read for this topic, the purchase order tables EKKO and EKPO are notToBeReleased, with the released CDS views I_PurchaseOrderAPI01 and I_PurchaseOrderItemAPI01 as successors; BAPI_PO_CHANGE is listed as a classicAPI.
build + years × (run + upgrades per year × retest effort at its level)
The retest effort is the part programs underestimate. Public Edition upgrades twice a year; private edition customers apply feature packs and upgrades on their own plan within SAP's maintenance rules (Landscape and deployment). For code that already exists, SAP's guidance is to measure before deciding: run the ABAP Call Monitor (SCMON) or Usage and Procedure Logging (UPL) in production for 6 to 18 months including a year-end close, aggregate with SUSG, and let the Custom Code Migration app find unused code and generate a transport to delete it (SAP Learning).
You will build Calder's fit-gap register: ten requirements from order-to-cash, procure-to-pay and plan-to-produce, each run through the decision tree above. The script prints the register, explains the path any requirement took, compares five-year costs of extensions as decided and as first requested, and can re-check the clean core inputs against SAP's current Cloudification Repository files.
flowchart LR
Q[REQUIREMENTS<br/>workshop answers] --> S[fit_gap.py]
T[TREE<br/>decision order] --> S
A[API_STATES<br/>from SAP's repository] --> S
S --> M[calder_fit_gap.md<br/>register]
S --> X[--explain<br/>decision path]
S --> C[--cost<br/>five-year cost]
S -.->|--online| G[SAP files<br/>on GitHub]
In VS Code, create a new file, paste the script below, and save it as fit_gap.py inside the unit1b folder.
"""Build Calder Pumpworks' fit-gap register: ten requirements, one decision each.
Calder Pumpworks is a fictional company. Requirements, evidence, effort days,
day rate and upgrade counts are course labels and workshop inputs, not SAP
figures. The API states in API_STATES come from SAP's Cloudification
Repository on GitHub (files read on 28 October 2026); --online checks them
against the current files.
Run it from your course folder:
python unit1b/fit_gap.py the register, written to unit1b/calder_fit_gap.md
python unit1b/fit_gap.py --explain R07 the path one requirement takes through the decision tree
python unit1b/fit_gap.py --cost five-year cost of each extension, as decided and as requested
python unit1b/fit_gap.py --online re-check the API states against SAP's current files
The script needs no account and no key. Only --online uses the network.
"""
import argparse
import json
import sys
import urllib.request
from pathlib import Path
REGISTER = Path("unit1b") / "calder_fit_gap.md"
CR_BASE = "https://raw.githubusercontent.com/SAP/abap-atc-cr-cv-s4hc/main/src/"
CR_FILES = ["objectReleaseInfo_PCELatest.json", "objectClassifications_SAP.json"]
# ------------------------------------------------- SAP objects and their state
# State of each object in SAP's Cloudification Repository (private cloud file
# and classic API file, read 2026-10-28). "write" marks objects an extension
# would change rather than read.
API_STATES = {
"I_SALESORDER": "released",
"I_SALESORDERITEM": "released",
"I_PURCHASEORDERAPI01": "released",
"I_PURCHASEORDERITEMAPI01": "released",
"I_PURCHASEORDERTP_2": "released",
"I_PURCHASINGINFORECORDTP": "released",
"I_SLSPRCGCONDITIONRECORDTP_2": "released",
"BAPI_PO_CHANGE": "classicAPI",
"EKPO": "notToBeReleased",
"EKKO": "notToBeReleased",
}
# Clean core level for one use of one object (SAP's levels A to D).
def level_of(obj: str, mode: str) -> str:
state = API_STATES.get(obj, "unknown")
if state == "released":
return "A"
if state == "classicAPI":
return "B"
if state in ("notToBeReleased", "noAPI", "unknown"):
return "D" if mode == "write" else "C"
return "C"
# ------------------------------------------------------- the decision tree
# Each question is asked in order; the first "yes" decides.
TREE = [
("evidence", "Is there evidence the business needs it (law, contract, KPI, usage)?", "Nothing: decline", False),
("config", "Does standard SAP do it with configuration?", "Configuration", True),
("adopt", "Can the business adopt the standard process instead?", "Process change", True),
("standard_feature", "Is there a standard SAP feature or product not yet in scope?", "Standard feature", True),
("outside_users", "Do people outside S/4HANA use it, or must it run on its own lifecycle?", "Side-by-side (SAP BTP)", True),
("last_mile", "Is it a last-mile change: a field, rule, form or query?", "On-stack: key user", True),
]
FALLBACK = "On-stack: developer (ABAP Cloud)"
# ------------------------------------------------------- Calder's requirements
# Answers are workshop inputs. "objects" lists (object, read/write) for the
# design as decided; "requested" for the design the business first asked for.
REQUIREMENTS = [
{"id": "R01", "process": "O2C", "text": "Hold orders when a customer is over its credit limit",
"evidence": True, "config": True, "why": "SAP Credit Management blocks the order; analysts release it"},
{"id": "R02", "process": "O2C", "text": "Pump test certificate number on order item and delivery note",
"evidence": True, "config": False, "adopt": False, "standard_feature": False, "outside_users": False,
"last_mile": True, "objects": [("I_SALESORDERITEM", "read")], "build_days": 3,
"why": "A custom field plus a form change; key user apps, no code"},
{"id": "R03", "process": "O2C", "text": "Distributors see order status and dates without SAP users",
"evidence": True, "config": False, "adopt": False, "standard_feature": False, "outside_users": True,
"objects": [("I_SALESORDER", "read"), ("I_SALESORDERITEM", "read")], "build_days": 25,
"why": "Users outside S/4HANA; a small app on BTP reading released APIs"},
{"id": "R04", "process": "O2C", "text": "Sales director releases credit blocks by phone",
"evidence": True, "config": False, "adopt": True,
"why": "The analyst releases in the standard app; keeps duties separate"},
{"id": "R05", "process": "P2P", "text": "Plant manager approves POs above 25,000 USD",
"evidence": True, "config": True, "why": "Flexible workflow with a total net amount condition"},
{"id": "R06", "process": "P2P", "text": "Rebuild CP20's custom report ZMM_OPEN_PO_AGING",
"evidence": False, "why": "Zero runs in 14 months of usage data, a year-end included"},
{"id": "R07", "process": "P2P", "text": "Keep Augsburg's program that writes dates into PO items",
"evidence": True, "config": False, "adopt": True,
"requested": [("EKPO", "write")], "requested_days": 4,
"why": "Buyers change dates in standard PO apps; the old program is level D"},
{"id": "R08", "process": "P2P", "text": "Monthly intercompany price for CP-IMP200 at cost plus 8%",
"evidence": True, "config": False, "adopt": False, "standard_feature": False, "outside_users": False,
"last_mile": False,
"objects": [("I_SLSPRCGCONDITIONRECORDTP_2", "write"), ("I_PURCHASINGINFORECORDTP", "write")],
"requested": [("BAPI_PO_CHANGE", "write")], "requested_days": 10, "build_days": 12,
"why": "Logic on core data, run as a job; ABAP Cloud on released objects"},
{"id": "R09", "process": "Plan", "text": "Final inspection at goods receipt for ES-300 only",
"evidence": True, "config": True, "why": "Inspection type set in the ES-300 material master only"},
{"id": "R10", "process": "Plan", "text": "See TEST1 load against capacity and the maintenance downtime",
"evidence": True, "config": False, "adopt": False, "standard_feature": True,
"why": "Capacity evaluation and the Capacity Scheduling Board; add to scope"},
]
# Course inputs for the cost of ownership. Not SAP figures.
DAY_RATE = 900 # USD per person-day
UPGRADES_PER_YEAR = 1 # upgrade or feature pack events Calder applies per year
YEARS = 5
RUN_DAYS_PER_YEAR = {"Side-by-side (SAP BTP)": 6, "On-stack: key user": 1, FALLBACK: 2}
RETEST_DAYS_BY_LEVEL = {"A": 0.5, "B": 1.5, "C": 4, "D": 8} # per upgrade, per extension
def decide(req: dict) -> tuple:
"""Walk the tree; return (decision, path of (question, answer))."""
path = []
for key, question, outcome, yes_decides in TREE:
answer = req.get(key, False)
path.append((question, "yes" if answer else "no"))
if answer == yes_decides:
return outcome, path
return FALLBACK, path
def worst_level(objects: list) -> str:
"""An extension is rated by the lowest level any of its uses reaches."""
if not objects:
return "-"
return max(level_of(o, m) for o, m in objects) # "D" > "C" > "B" > "A"
def five_year_cost(decision: str, level: str, build_days: float) -> float:
run = RUN_DAYS_PER_YEAR.get(decision, 2)
retest = RETEST_DAYS_BY_LEVEL.get(level, 0) * UPGRADES_PER_YEAR
return (build_days + YEARS * (run + retest)) * DAY_RATE
def register() -> None:
rows, counts = [], {}
for r in REQUIREMENTS:
decision, _ = decide(r)
level = worst_level(r.get("objects", []))
counts[decision] = counts.get(decision, 0) + 1
rows.append((r["id"], r["process"], r["text"], decision, level, r["why"]))
print(f"{r['id']} {r['process']:<6} {decision:<33} {level} {r['text']}")
print()
for decision, n in sorted(counts.items(), key=lambda kv: -kv[1]):
print(f"{n:>2} {decision}")
built = sum(n for d, n in counts.items() if d.startswith(("Side", "On-stack")))
print(f"\n{built} of {len(REQUIREMENTS)} requirements need something built.")
lines = ["# Calder fit-gap register (fictional)", "",
"| ID | Process | Requirement | Decision | Level | Rationale |",
"| --- | --- | --- | --- | --- | --- |"]
lines += [f"| {' | '.join(row)} |" for row in rows]
REGISTER.write_text("\n".join(lines) + "\n", encoding="utf-8")
print(f"Wrote {REGISTER}.")
def explain(rid: str) -> None:
req = next((r for r in REQUIREMENTS if r["id"] == rid.upper()), None)
if req is None:
sys.exit(f"No requirement {rid!r}. Use one of {', '.join(r['id'] for r in REQUIREMENTS)}.")
decision, path = decide(req)
print(f"{req['id']}: {req['text']}")
for question, answer in path:
print(f" {answer:<3} {question}")
print(f" -> {decision}: {req['why']}")
for label, key in (("As decided", "objects"), ("As requested", "requested")):
for obj, mode in req.get(key, []):
state = API_STATES.get(obj, "unknown")
print(f" {label}: {mode} {obj} ({state}) -> level {level_of(obj, mode)}")
def cost() -> None:
print(f"Five-year cost at {DAY_RATE} USD/day, {UPGRADES_PER_YEAR} upgrade event(s) a year:\n")
for r in REQUIREMENTS:
decision, _ = decide(r)
if "objects" in r and decision.startswith(("Side", "On-stack")):
lvl = worst_level(r["objects"])
print(f"{r['id']} as decided level {lvl} {five_year_cost(decision, lvl, r['build_days']):>9,.0f} USD")
if "requested" in r:
lvl = worst_level(r["requested"])
print(f"{r['id']} as requested level {lvl} {five_year_cost(FALLBACK, lvl, r['requested_days']):>9,.0f} USD")
print("\nDay rate, effort and upgrade counts are course inputs, not SAP figures.")
def online() -> int:
"""Download SAP's current files and compare every state in API_STATES."""
current = {}
for name in CR_FILES:
try:
with urllib.request.urlopen(CR_BASE + name, timeout=60) as resp:
data = json.load(resp)
except OSError as err:
sys.exit(f"Could not download {name}: {err}. Check your network or proxy; the offline states still work.")
items = data.get("objectReleaseInfo") or data.get("objectClassifications") or []
for item in items:
key = item.get("objectKey", "").upper()
if key in API_STATES and item.get("state"):
current.setdefault(key, item["state"])
changed = 0
for obj, state in API_STATES.items():
now = current.get(obj, "not listed")
flag = "OK " if now == state else "CHANGED"
changed += now != state
print(f"{flag} {obj:<30} course: {state:<16} SAP now: {now}")
print(f"\n{changed} change(s) since 2026-10-28.")
return 1 if changed else 0
def main() -> None:
parser = argparse.ArgumentParser(description="Calder fit-gap register.")
parser.add_argument("--explain", metavar="ID", help="show the decision path for one requirement")
parser.add_argument("--cost", action="store_true", help="five-year cost of each extension")
parser.add_argument("--online", action="store_true", help="re-check API states against SAP's files")
args = parser.parse_args()
if args.explain:
explain(args.explain)
elif args.cost:
cost()
elif args.online:
sys.exit(online())
else:
if not Path("unit1b").is_dir():
sys.exit("Can't find the unit1b folder. Run this from your orchestrate-course folder.")
register()
if __name__ == "__main__":
main()
The script's Calder content sits in three blocks at the top. REQUIREMENTS holds the workshop answers for each request, TREE holds the decision order from this topic, and API_STATES holds the state of each SAP object an extension would touch, copied from SAP's Cloudification Repository on 28 October 2026. The day rate, effort days and upgrade count near the bottom of those blocks are course inputs for a fictional company.
R01 O2C Configuration - Hold orders when a customer is over its credit limit
R02 O2C On-stack: key user A Pump test certificate number on order item and delivery note
R03 O2C Side-by-side (SAP BTP) A Distributors see order status and dates without SAP users
R04 O2C Process change - Sales director releases credit blocks by phone
R05 P2P Configuration - Plant manager approves POs above 25,000 USD
R06 P2P Nothing: decline - Rebuild CP20's custom report ZMM_OPEN_PO_AGING
R07 P2P Process change - Keep Augsburg's program that writes dates into PO items
R08 P2P On-stack: developer (ABAP Cloud) A Monthly intercompany price for CP-IMP200 at cost plus 8%
R09 Plan Configuration - Final inspection at goods receipt for ES-300 only
R10 Plan Standard feature - See TEST1 load against capacity and the maintenance downtime
3 Configuration
2 Process change
1 On-stack: key user
1 Side-by-side (SAP BTP)
1 Nothing: decline
1 On-stack: developer (ABAP Cloud)
1 Standard feature
3 of 10 requirements need something built.
Wrote unit1b/calder_fit_gap.md.
Open unit1b/calder_fit_gap.md and preview it with Ctrl+Shift+V (Cmd+Shift+V on a Mac). You should see the register as a table with a rationale per line.
Read the summary before the details. Seven of ten requirements are solved without building anything, and the three that are built are all level A. That is what a healthy register looks like; on a real program, a register where most lines are extensions is a sign the workshops didn't challenge the requests.
Ask the script why R07, Augsburg's date-writing program, became a process change:
Windows (PowerShell):
python unit1b\fit_gap.py --explain R07
macOS / Linux:
python unit1b/fit_gap.py --explain R07
You should see:
R07: Keep Augsburg's program that writes dates into PO items
yes Is there evidence the business needs it (law, contract, KPI, usage)?
no Does standard SAP do it with configuration?
yes Can the business adopt the standard process instead?
-> Process change: Buyers change dates in standard PO apps; the old program is level D
As requested: write EKPO (notToBeReleased) -> level D
Now try --explain R08. It walks all six questions to the developer option, then shows the objects: as decided, the job writes through two released objects (level A); as first requested by Augsburg's team, it would update open purchase orders with the classic BAPI_PO_CHANGE (level B).
This is the evidence for a "no". The path shows which question decided, and the object line shows the clean core level of what was asked for, taken from SAP's own files rather than from opinion.
Five-year cost at 900 USD/day, 1 upgrade event(s) a year:
R02 as decided level A 9,450 USD
R03 as decided level A 51,750 USD
R07 as requested level D 48,600 USD
R08 as decided level A 22,050 USD
R08 as requested level B 24,750 USD
Day rate, effort and upgrade counts are course inputs, not SAP figures.
Read R07 against its decision: as requested, the level D program costs 48,600 USD over five years in this model; the process change costs no build at all. R03, the distributor app, is the most expensive line even at level A, because a side-by-side app has its own running cost. It is still the right call: its users have no SAP access, and the alternative is giving distributors SAP users.
#Step 6: Re-check the clean core inputs online (optional)
SAP updates the Cloudification Repository regularly. An object released today stays released, but objects can be deprecated and new successors added. This step checks the course's API_STATES against SAP's current files.
Run:
Windows (PowerShell):
python unit1b\fit_gap.py --online
macOS / Linux:
python unit1b/fit_gap.py --online
After a few seconds you should see (on 28 October 2026):
OK I_SALESORDER course: released SAP now: released
OK I_SALESORDERITEM course: released SAP now: released
OK I_PURCHASEORDERAPI01 course: released SAP now: released
OK I_PURCHASEORDERITEMAPI01 course: released SAP now: released
OK I_PURCHASEORDERTP_2 course: released SAP now: released
OK I_PURCHASINGINFORECORDTP course: released SAP now: released
OK I_SLSPRCGCONDITIONRECORDTP_2 course: released SAP now: released
OK BAPI_PO_CHANGE course: classicAPI SAP now: classicAPI
OK EKPO course: notToBeReleased SAP now: notToBeReleased
OK EKKO course: notToBeReleased SAP now: notToBeReleased
0 change(s) since 2026-10-28.
If a line says CHANGED, SAP's state for that object differs from the course's copy. Look the object up in the repository's CSV files and update API_STATES. The script ends with exit code 1 when anything changed, so a scheduled job could alert on it.
On a real program, each step of this topic has an SAP tool. As of October 2026:
Job
SAP tool
Edition
Note
Show the standard process
SAP Signavio Process Navigator; starter system
Public Edition workshops as described; private edition uses the same content
Process flows, test scripts and tutorials (SAP Learning)
Record and track requirements
SAP Cloud ALM requirements, user stories, features
All
Approval, refinement, transports and test cases (SAP Learning)
Configure
Customizing (IMG); SAP Central Business Configuration in Public Edition
All
Example: flexible workflow for purchase orders, configured in the app Manage Workflows for Purchase Orders with conditions such as total net amount (SAP Learning)
Find released APIs
SAP Business Accelerator Hub; Cloudification Repository
All S/4HANA
The hub lists APIs, events and CDS views per edition (SAP Learning)
Find patterns and samples
SAP Extensibility Explorer
All
Sample scenarios and use cases (same source)
Rate custom code
ABAP test cockpit with the Cloudification Repository checks
Private edition, on-premise; ECC for analysis
"Usage of APIs" and "Allowed Enhancement Technologies" (SAP on GitHub)
Licensing notes. Key user apps and ABAP Cloud are part of S/4HANA. Side-by-side apps need SAP BTP services; SAP's private edition training notes that SAP Business Application Studio needs an additional license, while it lists SAP Build as included with the GROW with SAP package (SAP Learning). Check your own contract.
The three standard answers in Calder's register come from SAP features verified for this topic: blocked orders go to a credit analyst who releases them in Manage Documented Credit Decisions (SAP Learning); an inspection type in a material's master data creates an inspection lot at goods receipt from production for that material only (SAP Learning); and capacity evaluation with Manage Work Center Capacity plus leveling in the Capacity Scheduling Board covers the test bench request (SAP Learning).
Where it sits. The register sits between fit-to-standard and the build. Each decision lands in one place in Calder's landscape:
flowchart LR
subgraph S4[CP10 S/4HANA private edition]
CFG[Configuration<br/>R01 R05 R09]
STD[Standard feature<br/>R10]
KU[Key user<br/>R02]
DEV[ABAP Cloud<br/>R08]
end
subgraph BTP[SAP BTP]
APP[Distributor app<br/>R03]
end
APP -->|released APIs| S4
D[Distributors] --> APP
X[Declined or process change<br/>R04 R06 R07] -.-> REG[Register and ADRs]
Non-functional requirements that decide the design
Requirement
Typical target
If missed
Upgrade stability
New extensions at level A; nothing below B without board approval
Upgrades slip or break production processes
Retest effort
Every extension has an automated or scripted test in Cloud ALM
Each upgrade becomes a manual project
Security
Side-by-side apps use the end user's identity or a narrowly scoped technical user
Outsiders see data beyond their own orders
Cost
Five-year cost recorded for each extension
Running costs surprise the budget after go-live
Traceability
Each register line links to evidence and a decision owner
Old debates reopen; audits can't see why
Integration and identity. On-stack extensions run inside S/4HANA under the user's own roles. The distributor app (R03) reads sales orders through released APIs; it should pass the distributor's identity, or, when a technical user is used, filter strictly by the customer number taken from the signed-in distributor's identity (never from a request parameter the caller can change), so Hallam sees only Hallam's orders. Role design for this is covered in Roles and authorization design.
Context: Augsburg's buyers ask to keep their ECC program that writes changed delivery dates straight into purchase order items (R07) after CP20 moves into CP10's system. The program writes to EKPO, which SAP lists as not to be released.
Options: (1) rebuild the program as it is; (2) rebuild it as an ABAP Cloud job through the released purchase order object I_PurchaseOrderTP_2; (3) adopt the standard: buyers change dates in the standard purchase order apps.
Decision: (3). The need behind the program is real, but standard apps meet it, and the requested design is level D.
Consequences: Augsburg's buyers need training on the standard apps before cutover. If the volume of date changes proves too high for manual work, option (2) is the fallback, at level A. The old program is not migrated.
What a design review will ask
What share of requirements became extensions, and what evidence backed the ones declined?
Which extensions are below level A, and who approved them?
Who runs and pays for each side-by-side app after go-live?
How is each extension retested at upgrade, and how long does that take?
Which Augsburg programs were retired on usage data, and was a year-end inside the window?
Security and SAP authorizations. Key user apps and ABAP Cloud work under SAP roles; restrict who may create custom fields and logic in development, and transport them like any change. Side-by-side apps need their own identity and authorization design; never give a portal a broad technical user (Agent permissions and SAP authorizations).
Evaluation. Treat the register as a living artifact: count extensions by level each quarter, and track how many standard features replaced an extension after an upgrade.
Cost. Record the five-year cost of each extension at decision time. Re-check it at each upgrade with the actual retest effort.
Operations. Every extension needs an owner, a test and a retirement trigger ("delete when SAP's standard covers X").
Clean core. Run ATC with the Cloudification Repository checks in the development system, and let a failed check block the transport of new level C or D code.
Extend Calder's register to two more processes and write the "no" memo for one requirement.
Run python unit1b/fit_gap.py and confirm the summary says 3 of 10 requirements need something built.
Open unit1b/fit_gap.py. Add R11 for maintain-to-settle: "Technicians record crane inspection results on a tablet in the plant, offline". Answer the tree questions honestly (evidence yes; configuration no; adopt standard no; standard feature: say no unless you find one in SAP's documentation; outside users or own lifecycle: decide and note why). Give it objects of your choice from API_STATES and build_days.
Add R12 for warehouse execution: "Show the Rockford dock team which trucks are late, from data already in S/4HANA". Decide whether it is a key user query or something larger, and set the answers to match.
Run the script again and --explain R11 and --explain R12. Check the paths match your reasoning.
Run --cost and note whether your two lines appear.
Open unit1b/calder_landscape_decision.md from Landscape and deployment (create the file if you skipped that exercise). Under a new heading Fit-gap decisions, paste the register table from unit1b/calder_fit_gap.md.
Below it, under The no for R07, write five lines for the Augsburg buyers' manager: the need you accept, the standard alternative, the clean core level of the requested design, the five-year cost comparison labeled as synthetic, and what happens if volumes prove too high.
Commit both files with Git.
Done when: the register shows 12 requirements with a decision and rationale each, --explain paths for R11 and R12 match what you wrote, and the R07 memo has all five lines, with the cost labeled synthetic. Keep the file: the roles topic designs access for the extensions in this register.
Pick one answer for each question. The explanation appears after you choose.
1In SAP Activate, what has to happen to a delta requirement from a fit-to-standard workshop before it enters the backlog for the Realize phase?
Answer: A. SAP's Explore guidance has the product owner validate deltas and configuration needs before they join the product backlog, which is then prioritized. ATC rates code, which doesn't exist yet at this point.
2An extension reads released CDS views, calls one classic BAPI and writes one field directly into EKPO. What is its clean core level?
Answer: B. An extension takes the level of the lowest technique it uses. Writing into an SAP table is level D, whatever the rest of the code does.
3In the script, why does R08 end at the developer option rather than key user?
Answer: D. The tree asks its questions in order, and the developer option is the fallback when all answers are no. Key user apps are available in all S/4HANA deployment options, so availability isn't the reason.
4Calder's distributor app reads sales orders from S/4HANA with a technical user. What must the design add?
Answer: B. A technical user sees everything its roles allow, so the app must limit each distributor to its own orders, or pass the distributor's identity. The other choices add cost or risk without closing the exposure.
5Augsburg insists its ECC report must be rebuilt. What evidence settles the question, by SAP's guidance?
Answer: A. SAP recommends usage data from production, over a window that includes a year-end close, aggregated with SUSG. Memories of usage are unreliable, and size or speed says nothing about need.
6A requirement is real, standard SAP doesn't cover it, and the users are S/4HANA buyers who need logic that changes core data in the same transaction. What do you choose?
Answer: C. Same-transaction logic for S/4HANA users points on-stack, and level A keeps it upgrade-stable. Side-by-side fits outsiders or loose coupling; classic code needs board approval; a process change only works when the business can adopt the standard.
7Why does the five-year cost of the requested R07 design exceed its build cost by so much?
Answer: D. In the course model, cost is build plus years times running and per-upgrade retest effort, and retest effort grows with the level. The model has no license fee per object and a flat day rate.
8What happens to an extension's place in the register after a later upgrade adds the same function to standard SAP?
Answer: B. SAP suggests recording why each deviation was accepted so it can be removed when the standard catches up. A retirement trigger per extension makes that review happen.
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.
The solution architect on an SAP programUnit 14 · The FDE operating system and capstoneLinked from this topic · Shares: Delta requirement, Solution Standardization Board
Exploring Clean Core Extensibility Best Practices (SAP Learning)— levels A (released APIs) to D (modifications, writes to SAP tables, implicit enhancements); the three-tier model is sunset; an extension takes the level of the lowest technique it uses; Cloudification Repository and changelog
Collecting Usage Data for Custom Code (SAP Learning)— SCMON or UPL in production for 6 to 18 months including a year-end close; SUSG aggregates; Custom Code Migration app finds unused code and can generate a deletion transport
Cloudification Repository: released and classic API list for ATC (SAP on GitHub)— files read 28 October 2026; private cloud file objectReleaseInfo_PCELatest.json (EKKO, EKPO, VBAK notToBeReleased with released successors; I_PurchaseOrderTP_2, I_SalesOrder, I_PurchasingInfoRecordTP, I_SlsPrcgConditionRecordTP_2 released); objectClassifications_SAP.json (BAPI_PO_CHANGE classicAPI); ATC checks "Usage of APIs" and "Allowed Enhancement Technologies" since August 2025