From sap-dev-core
Runs the SAP ABAP Test Cockpit (ATC) end-to-end as a quality gate: builds an SCI Object Set scoped to the target object(s), creates an ATC Run Series bound to that set, polls the ATC Run Monitor until the run completes, then reads the Priority 1 / Priority 2 / Priority 3 finding counts from the Manage Results screen and (best-effort) downloads the result text file. Applies the customer brief's MAX_PRIORITY threshold to decide pass / fail. Replaces the legacy SCI-results-tree implementation that lacked a Priority column. Per-stage VBS references are recorded against the S/4HANA 1909 ATC layout — re-record on first failure with /sap-gui-record if your release uses different tree node IDs / grid column IDs. Prerequisites: Active SAP GUI session (use /sap-login first).
How this skill is triggered — by the user, by Claude, or both
Slash command
/sap-dev-core:sap-atc <OBJECT_TYPE> <OBJECT_NAME> [--max-priority=<n>] [--object-set=<NAME>] [--run-series=<NAME>] [--poll-interval=<sec>] [--max-wait=<sec>] [--save-to=<PATH>] [--drill] [--no-drill]<OBJECT_TYPE> <OBJECT_NAME> [--max-priority=<n>] [--object-set=<NAME>] [--run-series=<NAME>] [--poll-interval=<sec>] [--max-wait=<sec>] [--save-to=<PATH>] [--drill] [--no-drill]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You drive the proper SAP ATC pipeline — Object Set → Run Series → Run
You drive the proper SAP ATC pipeline — Object Set → Run Series → Run Monitor → Manage Results — and apply a priority-based gate. The four stages each have their own VBS reference; SKILL.md orchestrates them with a polling loop in the middle.
Task: $ARGUMENTS
Stage 1: SCI /nSCI create / refresh Object Set "<SET>"
|
v
Stage 2: ATC /nATC tree node 12 → CREATE_SERIE bound to <SET>
| → EXECUTE_SERIE → run is async
v
Stage 3: ATC /nATC tree node 13 → poll Run Monitor for <RUN>
| until STATE=COMPLETED (or FAILED)
v
Stage 4: ATC /nATC tree node 14 → Manage Results: read
P1/P2/P3 counts; best-effort download
to <OUTPUT_PATH>
|
v
Gate logic in SKILL.md compares the counts to MAX_PRIORITY.
|
v
Stage 4b: ATC /nATC (optional) tree node 14 → drill into the
run-series row → export per-finding ALV
as TSV. Auto-triggered when gate FAILS;
always triggered by --drill. Outputs
<OUTPUT_PATH>.findings.tsv with one row
per finding: PRIO | CHECK_ID | CHECK_TITLE
| OBJECT | LINE | MSG_TEXT.
|
v
Final PASS / FAIL emitted with the findings.tsv path when available.
| File | Stage | Purpose |
|---|---|---|
<SKILL_DIR>/references/sap_sci_create_object_set.vbs | 1 | Define the scope — programs / classes / FMs / interfaces / FUGRs |
<SKILL_DIR>/references/sap_atc_create_run_series.vbs | 2 | Schedule + trigger the ATC run |
<SKILL_DIR>/references/sap_atc_check_run_status.vbs | 3 | Read run state from the Monitor (read-only; safe to call in a poll loop) |
<SKILL_DIR>/references/sap_atc_get_results.vbs | 4 | Pull P1/P2/P3 counts + try to save the result TXT (outer grid only — summary level) |
<SKILL_DIR>/references/sap_atc_drill_findings.vbs | 4b | (Optional) Drill into the run-series row → export per-finding ALV as TSV. Run when gate FAILS or --drill is passed. |
Settings reads/writes follow shared/rules/settings_lookup.md — merge settings.local.json over settings.json per-key on the .value field; writes always go to settings.local.json. Read work_dir. {WORK_TEMP} = work_dir\temp.
cmd /c if not exist "{WORK_TEMP}" mkdir "{WORK_TEMP}"
powershell -ExecutionPolicy Bypass -File "<SAP_DEV_CORE_SHARED_DIR>\scripts\sap_log_helper.ps1" -Action start -StateFile "{WORK_TEMP}\sap_atc_run.json" -Skill sap-atc -ParamsJson "{\"object_type\":\"<TYPE>\",\"object_name\":\"<NAME>\"}"
If the customer brief defines MAX_PRIORITY (typically 2 = block on
critical + high), use it as the default gate threshold. Allow override
via --max-priority=<n> on the skill argument list. Range: 1-4
(1=critical / 2=high / 3=medium / 4=low; lower = worse, fail-on-or-below).
If neither brief nor argument supplies a value, default to 2.
| Arg | Required | Default | Notes |
|---|---|---|---|
OBJECT_TYPE | yes | — | One of PROGRAM / CLASS / INTERFACE / FUGR / DDIC / TYPEGROUP / WDYN. SCI groups Class and Interface under one category, so both map to XSO_CLAS + SO_CLAS-LOW. FM is intentionally rejected — SCI Object Sets have no per-function-module category; pass FUGR <function-group-name> instead to scope at FG level. |
OBJECT_NAME | yes | — | UPPERCASE repository name. |
--max-priority=<n> | no | 2 (or brief) | Gate threshold — fail if any priority ≤ this value has count > 0. |
--object-set=<NAME> | no | auto | Reuse a named SCI Object Set. If omitted, generate ZGATE_<8-char-hash-of-objname> so re-runs on the same target reuse the same set. |
--run-series=<NAME> | no | auto | Run Series name. If omitted, generate RUN_<YYYYMMDD>_<HHMMSS> to avoid collisions. |
--poll-interval=<sec> | no | 15 | Stage 3 polling cadence. |
--max-wait=<sec> | no | 600 (10 min) | Stage 3 timeout. |
--save-to=<PATH> | no | {WORK_TEMP}\ATC_<series>.txt | Local path for the downloaded result TXT. |
--drill | no | (off by default; auto when gate FAILS) | Force Stage 4b — drill into the run-series row and export per-finding ALV as TSV to <save-to>.findings.tsv. Use to see WHICH findings exist even when the gate passes (e.g. inspecting P3 informational findings). |
--no-drill | no | (off) | Disable Stage 4b even when the gate FAILS. Useful for CI runs where the operator only needs PASS/FAIL counts and will drill manually if needed. |
Naming generation (when not supplied):
ZGATE_ + first 8 hex chars of an MD5 of
<OBJECT_TYPE>:<OBJECT_NAME>. Stable across runs of the same target.
Max length budget: SCI accepts up to 30 chars on SCI_DYNP-OBJS; we
use 14.R_ + Get-Date -Format "yyMMdd_HHmmss" →
R_260509_195347 (16 chars). The ATC popup field
ctxtSATC_CI_S_CFG_SERIE_UI_02-NAME has MaxLength = 16 on
S/4HANA 1909 — verified live; the older RUN_<YYYYMMDD>_<HHMMSS>
form (19 chars) fails with "method got an invalid argument". The
shorter form is unique to the second across 100 years.Run /sap-login first if no session is active.
Fill sap_sci_create_object_set.vbs and run it. Tokens:
%%OBJECT_SET_NAME%%, %%OBJECT_TYPE%%, %%OBJECT_NAME%%,
%%SESSION_LOCK_VBS%%.
# IMPORTANT: read with explicit UTF-8 and write with UTF-16 LE (BOM).
# The VBS templates contain Japanese/Chinese tooltip stems for
# locale-independent state decoding (see sap_atc_check_run_status.vbs).
# `Get-Content -Raw` reads via the Windows ANSI codepage and silently
# mangles those high-byte characters into garbage that VBScript then
# refuses to compile ("unterminated string literal"). Likewise
# `Set-Content -Encoding Unicode` was observed to double-encode in
# some PowerShell versions. Use System.IO.File directly.
$skillDir = '<SKILL_DIR>'
$shared = '<SAP_DEV_CORE_SHARED_DIR>'
$content = [System.IO.File]::ReadAllText("$skillDir\references\sap_sci_create_object_set.vbs", [System.Text.Encoding]::UTF8)
$content = $content.Replace('%%OBJECT_SET_NAME%%','THE_OBJECT_SET')
$content = $content.Replace('%%OBJECT_TYPE%%', 'THE_OBJECT_TYPE')
$content = $content.Replace('%%OBJECT_NAME%%', 'THE_OBJECT_NAME')
$content = $content.Replace('%%SESSION_LOCK_VBS%%',"$shared\scripts\sap_session_lock.vbs")
[System.IO.File]::WriteAllText('{WORK_TEMP}\sap_atc_stage1_run.vbs', $content, [System.Text.UnicodeEncoding]::new($false, $true))
Stages 2-4 use the same I/O pattern. Substitute the template name (
sap_atc_create_run_series.vbs,sap_atc_check_run_status.vbs,sap_atc_get_results.vbs) and the corresponding output file name. Always[System.IO.File]::ReadAllText(..., UTF8)+[System.IO.File]::WriteAllText(..., UnicodeEncoding). NeverGet-Content -Raw+Set-Content -Encoding Unicodefor these files — any localized string in the template will be silently corrupted.
Run via cscript. Expected last line:
SUCCESS: Object set <NAME> created/updated with <TYPE> <NAME>.
If it fails with "Object set already exists" or similar, that's
fine for our reuse model — proceed to Stage 2 with the same name. If
it fails with a missing-field-id error, the SCI screen layout shifted;
re-record via /sap-gui-record.
Fill sap_atc_create_run_series.vbs. Tokens: %%RUN_SERIES_NAME%%,
%%OBJECT_SET_NAME%%, %%SESSION_LOCK_VBS%%.
Same generator pattern; output {WORK_TEMP}\sap_atc_stage2_run.vbs,
run via cscript. Expected last line:
SUCCESS: Run series <NAME> scheduled (object set <SET>).
After this point the ATC run is async — SAP queues the work and executes it in the background. Stage 3 polls.
Loop:
{WORK_TEMP}\sap_atc_stage3_run.vbs from
sap_atc_check_run_status.vbs with token %%RUN_SERIES_NAME%%.STATE=COMPLETED → break, proceed to Stage 4.STATE=RUNNING → wait --poll-interval seconds, retry.STATE=FAILED → abort with ERROR: ATC run <NAME> failed.STATE=NOT_FOUND → wait one cycle (the Monitor may not have
picked up the freshly-scheduled run yet), then retry; if still
NOT_FOUND after 3 cycles, abort.STATE=UNKNOWN:<raw> → log and retry once; if it persists,
fall back to "treat as RUNNING" until --max-wait elapses.Hard cap at --max-wait seconds (default 600). On timeout, abort
with ERROR: ATC run <NAME> did not complete within <N>s.
Implementation hint for the orchestrator (PowerShell):
$pollInterval = 15
$maxWait = 600
$elapsed = 0
do {
$out = & cscript //NoLogo "{WORK_TEMP}\sap_atc_stage3_run.vbs"
$state = ($out -match '^STATE=(.+)$') | Out-Null; $Matches[1]
if ($state -eq 'COMPLETED') { break }
if ($state -eq 'FAILED') { throw "ATC run failed" }
Start-Sleep -Seconds $pollInterval
$elapsed += $pollInterval
} while ($elapsed -lt $maxWait)
Don't echo the polling output to chat each iteration — that's noisy. Suppress and only show on state-change or timeout.
Fill sap_atc_get_results.vbs. Tokens: %%RUN_SERIES_NAME%%,
%%OUTPUT_PATH%%, %%SESSION_LOCK_VBS%%. Run via cscript.
Parse the output for these lines:
PRIORITY_COUNTS: P1=<n> P2=<n> P3=<n>
FILE: <path> (<size> bytes) ← only on successful auto-download
SAVE_HINT: <diagnostic> ← only when auto-download skipped
SUCCESS: Read result for run series <NAME>.
Gate logic:
| MAX_PRIORITY | Pass condition |
|---|---|
1 | P1 == 0 (any critical finding fails) |
2 (default) | P1 == 0 AND P2 == 0 |
3 | P1 == 0 AND P2 == 0 AND P3 == 0 |
4 | report findings but never fail (informational) |
Emit a final verdict line in your reply:
GATE_VERDICT: PASS P1=0 P2=0 P3=18 (threshold=2 → P3 doesn't block)
GATE_VERDICT: FAIL P1=3 P2=2 P3=14 (threshold=2 → P1+P2 sum 5 blocks)
The aggregated P1/P2/P3 counts from Stage 4 tell the operator THAT the gate failed but not WHY. The findings ALV (check ID, source line, message text — one row per finding) lives one screen deeper, behind a doubleClick on the run-series row. Stage 4b drills there and exports the grid as TSV.
Trigger conditions (run Stage 4b when ANY is true):
--drill was passed on the command line.--no-drill was NOT passed.Otherwise skip Stage 4b.
Compute output path:
DRILL_PATH = <save-to>.findings.tsv
(i.e. same dir + filename as --save-to but with .findings.tsv suffix)
Token-replace and run the same way as Stage 4 (UTF-8 read + UTF-16 LE write):
$skillDir = '<SKILL_DIR>'
$shared = '<SAP_DEV_CORE_SHARED_DIR>'
$content = [System.IO.File]::ReadAllText("$skillDir\references\sap_atc_drill_findings.vbs", [System.Text.Encoding]::UTF8)
$content = $content.Replace('%%RUN_SERIES_NAME%%', 'THE_RUN_SERIES')
$content = $content.Replace('%%OUTPUT_PATH%%', 'THE_DRILL_PATH')
$content = $content.Replace('%%SESSION_LOCK_VBS%%',"$shared\scripts\sap_session_lock.vbs")
[System.IO.File]::WriteAllText('{WORK_TEMP}\sap_atc_stage4b_run.vbs', $content, [System.Text.UnicodeEncoding]::new($false, $true))
Run via cscript. Expected output lines:
INFO: Outer row <N> for series <NAME> — drilling in.
INFO: Findings grid located at <path>
FINDING_COUNT: <n>
FILE: <DRILL_PATH> (<size> bytes)
SUCCESS: Drilled findings for run series <NAME>.
The findings TSV has the header row:
PRIO CHECK_ID CHECK_TITLE OBJECT LINE MSG_TEXT
When the gate FAILED, parse this TSV and surface the offending findings
(PRIO <= MAX_PRIORITY) in the final reply — one bullet per row with
file:line and message text. Don't dump the whole TSV inline if it's
long; quote the top 5 by priority and point the operator at the TSV
path for the rest.
When the gate PASSED but --drill forced Stage 4b, mention the file
path so the operator can review informational findings if interested.
If Stage 4b errors out (e.g. drill couldn't locate the findings grid because the screen 201 layout shifted on a newer SAP_BASIS release):
WARN: Stage 4b drill failed — operator must inspect findings manually via /nATC > Manage Results > <series>./sap-gui-record against the result-display
screen, then updating the findingPaths fallback list in
sap_atc_drill_findings.vbs.For the operator's final reply, summarise:
Priority 1 (critical) : 3
Priority 2 (high) : 2
Priority 3 (medium) : 14
<save-to>.findings.tsv) when Stage 4b ran,
with a 1-line preview: Findings: N (top: P<n> <check> @<obj>:<line>)PRIO <= MAX_PRIORITY)
inline — quote the top 5 by priority, point at the TSV for the restIf the operator wants the full finding list, point them at the saved TXT, the findings TSV (when Stage 4b ran), or the still-open ATC > Manage Results > screen.
cmd /c del {WORK_TEMP}\sap_atc_stage1_run.vbs & del {WORK_TEMP}\sap_atc_stage2_run.vbs & del {WORK_TEMP}\sap_atc_stage3_run.vbs & del {WORK_TEMP}\sap_atc_stage4_run.vbs & del {WORK_TEMP}\sap_atc_stage4b_run.vbs
Keep the downloaded result TXT (--save-to) and, when Stage 4b ran, the
findings TSV (<save-to>.findings.tsv) — both are operator artefacts.
powershell -ExecutionPolicy Bypass -File "<SAP_DEV_CORE_SHARED_DIR>\scripts\sap_log_helper.ps1" -Action end -StateFile "{WORK_TEMP}\sap_atc_run.json" -Status SUCCESS -ExitCode 0
For gate FAIL, set -Status FAILED -ExitCode 1 -ErrorClass ATC_GATE_FAIL
and put the P1/P2/P3 counts in -ErrorMsg.
For other failure modes:
-ErrorClass ATC_OBJ_SET_FAILED (Stage 1 broke)-ErrorClass ATC_RUN_SCHEDULE_FAILED (Stage 2 broke)-ErrorClass ATC_RUN_TIMEOUT (Stage 3 ran out of wait time)-ErrorClass ATC_RESULT_PARSE_FAILED (Stage 4 couldn't read counts)ATC tree nodes (left pane of /nATC):
| Node ID | Function |
|---|---|
12 | Schedule / Manage Run Series (Stage 2 entry) |
13 | Run Monitor (Stage 3 entry) |
14 | Manage Results (Stage 4 entry) |
The string format " 12" (10 leading spaces + node ID) is how
SAP GUI scripting addresses ATC tree nodes. Different ATC roles /
versions may renumber these — re-record if Stage 2/3/4 fails to
navigate.
Run Monitor grid (Stage 3, tree node 13) — column IDs verified live on S/4HANA 1909:
| Column ID | What it shows |
|---|---|
APP_CONFIG_NAME | Run Series name (the value Stage 2 supplied) |
STATE_ICON | Icon-encoded state, e.g. @DF\QState: Finished@ |
TITLE, RESTARTS, DURATION, STARTED_ON_DATE, STARTED_ON_TIME, VALID_TO_DATE, STARTED_BY, COUNT_PLNERR | Other monitor columns |
Manage Results grid (Stage 4, tree node 14) — column IDs verified live:
| Column ID | What it shows |
|---|---|
RUN_SERIES_NAME | Run Series name |
COUNT_PRIO1 / COUNT_PRIO2 / COUNT_PRIO3 | Finding counts per priority bucket |
COUNT_PLNERR | Planning errors |
IS_ACTIVE, IS_CENTRAL_RUN, IS_IN_BASELINE, TITLE, SCHEDULED_BY, SCHEDULED_ON_DATE, SCHEDULED_SYS, VALID_TO_DATE, DATA_SOURCE_ID, ANNOTATION | Other admin columns |
The Stage 3 / Stage 4 VBS files put these IDs first in their column-
candidate lists, with older release names (RUN_SERIES_NAME, PRIO_<n>,
STATUS_ICON, etc.) as portability fallbacks.
Each stage's VBS header points to its source recording:
| Stage VBS | Recording |
|---|---|
sap_sci_create_object_set.vbs | C:\Temp\Record_SCI_CreateObjectSet_01.vbs |
sap_atc_create_run_series.vbs | C:\Temp\Record_ATC_CreateRunSeries_01.vbs |
sap_atc_check_run_status.vbs | C:\Temp\Record_ATC_CheckRunStatus_01.vbs |
sap_atc_get_results.vbs | C:\Temp\Record_ATC_CheckResult_01.vbs |
When something breaks on a different SAP release, re-record on the target system and patch the affected VBS.
/sap-sp02The Stage 4 download is best-effort — if the ATC Manage Results detail
screen doesn't expose a Save list to local file shortcut on your
release, Stage 4 emits SAVE_HINT: and leaves the screen open. The
operator can then run /sap-sp02 against any spool produced via *List
Print > Print* (the same idiom as
/sap-where-used-list --to-spool) to capture a TXT copy.
/sap-gui-record and patch the four VBS files.PROGRAM → XSO_REPO + SO_REPO-LOW ✓CLASS / INTERFACE → XSO_CLAS + SO_CLAS-LOW ✓
(SCI groups them as one category)FUGR → XSO_FUGR + SO_FUGR-LOW ✓DDIC → XSO_DDIC + SO_DDIC-LOW (untested but field ID dumped)TYPEGROUP → XSO_DDTY + SO_DDTY-LOW (untested)WDYN → XSO_WDYN + ctxtSO_WDYN-LOW (untested; uses ctxt
instead of txt)FM is intentionally rejected — there is no per-FM category in
SCI Object Sets. The Stage 1 VBS produces a clear redirect
message pointing at FUGR <function-group-name> instead.Ctrl+Shift+F9 followed by a
format-radio + DY_PATH/DY_FILENAME dialog (the SP02 idiom). If the
Manage Results detail screen on your release uses a different save
path, the VBS emits SAVE_HINT: and leaves the screen open for
manual export.--baseline=<NAME>
flag that compares against a saved baseline rather than absolute zero.The previous sap-atc shipped a single sap_atc_run.vbs that drove
SCI's results-tree screen (Error / Warnings / Information columns, no
Priority). That implementation is retired — the four-stage flow above
captures findings via ATC's native Priority columns and supports
async runs, Object Set reuse, and downloadable result files.
Operator-visible API changes:
<OBJECT_TYPE> <OBJECT_NAME>.[CHECK_VARIANT] argument is gone — the run series uses
ATC's default behaviour flags (GENERATED_CODE-ANALYZE,
QUICKFIXES-GENERATE_QUICKFIXES); customisation will arrive when
the skill grows a --variant=<NAME> flag.MAX_PRIORITY is still honoured but now applies to ATC's actual
priority columns instead of a heuristic mapping.npx claudepluginhub sapdev-ai/sap-dev --plugin sap-dev-coreGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.