arc-mcp/arc-1

sap-unused-code

Find Z/Y custom objects never called at runtime by combining SAP call-monitor (SCMON) usage data with static where-used analysis — classifies each as UNUSED/LIKELYUNUSED/USED/INDETERMINATE.

查看源码

使用方法

  1. 复制安装命令,在自己的智能体环境安装前先检查源码包。
  2. 从原始文档核对所需工具、凭据和支持的宿主。
  3. 说明输入材料与期望交付物,并对照来源检查输出。
npx skills add https://github.com/arc-mcp/arc-1 --skill sap-unused-code

开始前需了解

  • 安装不包含模型订阅、API 额度或访问文件的权限。
  • 仓库星数和安装量反映活跃情况,不等于独立质量或安全测试。
仓库原始内容

按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。

SAP Unused Code Discovery

Find Z/Y custom objects that are never called at runtime — the prerequisite for any credible custom-code retirement project. Combines runtime usage data from SAP's call monitor (SCMON) with static where-used analysis to classify each object as UNUSED / LIKELY_UNUSED / USED / INDETERMINATE.

⚠ Required: scope and intent

This skill refuses to run without a filter. A "list all unused code" report across an ECC system returns tens of thousands of rows and is useless. The user must provide at least one of:

  • Package (e.g., Z_FI_CUSTOM) — analyze only objects in this package
  • Namespace prefix (e.g., Z_SALES_*, /ACME/*) — only objects matching the pattern
  • Object list — comma-separated names to check
  • Intent statement — e.g., "find Z reports in FI-GL that haven't run in 90 days" — narrow by purpose

If none is given, ask. Example clarifying questions:

Which package or namespace do you want to audit? E.g., "the ZREPORTING package", "all Z* starting with ZFI_", or "these 15 reports I'm planning to delete".

Why this is harder than it looks (read before proposing a plan)

SAP has two relevant monitoring systems. Understand which you're working with:

SystemWhat it isWhere data livesLatencyData lifetime
SCMON (ABAP Call Monitor)Raw per-call countersSCMON_DATA + SCMON_PROG + SCMON_SUB + SCMON_RDATA tablesReal-time while active~7 days rolling
SUSG (Usage Statistics Generator)Daily aggregation over SCMONSUSG_DATA + SUSG_PROG + SUSG_RDATA + SUSG_SUB + SUSG_ADMIN tables (or CDS views SUSG_I_DATA, SUSG_I_RDATA, SUSG_I_ODATA)Depends on batch schedule (default ~02:30 daily)Months/years

Key constraint: SCMON auto-deactivates when record threshold is hit (SCMON_CONF_SET_MAX_NUM_SLICES). SUSG refuses to aggregate if SCMON was inactive during the window. On dev/test systems this breaks the pipeline constantly.

Three Options (pick based on system state)

Option A (preferred) — Direct SCMON table join via ARC-1

Works immediately on any system where SCMON has ever been active, regardless of whether SUSG aggregation ran.

sql
-- "Which programs actually ran?"
SELECT p~PROGNAME, p~OBJECT, p~OBJ_NAME, SUM( d~COUNTER ) AS EXECS
FROM SCMON_DATA AS d INNER JOIN SCMON_PROG AS p ON d~TRIGID = p~PROGID
WHERE <filter>
GROUP BY p~PROGNAME, p~OBJECT, p~OBJ_NAME
ORDER BY EXECS DESCENDING
sql
-- "Which transactions/reports triggered anything?"
SELECT s~ROOTNAME, s~ROOTTYPE, SUM( d~COUNTER ) AS EXECS
FROM SCMON_DATA AS d INNER JOIN SCMON_SUB AS s ON d~SUBID = s~SUBID
GROUP BY s~ROOTNAME, s~ROOTTYPE

Column caveat (SAP naming is inverted):

  • SCMON_DATA.TRIGID → SCMON_PROG.PROGID (the executed program, despite the name)
  • SCMON_DATA.SUBID → SCMON_SUB.SUBID (the trigger root, transaction/report that initiated)

Pros: No batch wait, no slice rotation dance, runs today. Cons: Limited retention window (~7 days); useless for "has this run in the last 6 months" questions.

Option B — Aggregated SUSG via CDS views

Use when the customer has SUSG properly scheduled (production systems usually do).

sql
-- Same question, longer window
SELECT PROGNAME, OBJ_TYPE, OBJ_NAME, SUM( COUNTER ) AS EXECS, MAX( LAST_USED ) AS LAST_SEEN
FROM SUSG_I_DATA
WHERE <filter>
GROUP BY PROGNAME, OBJ_TYPE, OBJ_NAME

Pre-joined CDS view: SUSG_I_DATA, SUSG_I_RDATA, SUSG_I_ODATA. All have @AccessControl.authorizationCheck: #NOT_REQUIRED.

Pros: Longer history (months), pre-joined (simpler SQL), officially supported data. Cons: Requires SUSG batch to have run (0 rows in SUSG until it does); nothing works if SCMON was deactivated during the window.

Option C — Manual SUSG XML export (fallback only)

If the customer has already run transaction SUSG and exported the 5 XML files (ADMIN0001.xml, PROG0001.xml, DATA*.xml, RDATA*.xml, SUB0001.xml), the skill can parse those locally. This is the Kiro path and should be the last resort — it requires human action in SAP GUI and offline file handoff.

This skill does not bundle an XML parser. If the user insists on Option C, tell them to use Kiro's parse-susg.py or write a local Python script; ARC-1 won't do it.

Smart Defaults (apply silently, do NOT ask)

SettingDefaultRationale
Option selectionProbe SCMON activity first; use A if live data exists, else BMost systems have one or the other
Output classificationUNUSED / LIKELY_UNUSED / USED / INDETERMINATEKiro's 4-way classification; useful for prioritization
Where-used checkYes, for non-runtime-seen objectsStatic references are a real signal
Reporting granularityPer-object with counts; top-20 + summaryFull list available on request

Prerequisites

Check these up front. If missing, stop and tell the user.

  1. `SAP_ALLOW_FREE_SQL=true` on the ARC-1 server (otherwise SAPQuery is blocked — it runs FreeSQL). Ask admin if needed.
  2. User has `S_TABU_NAM` authorization on SCMON_DATA, SCMON_PROG, SCMON_SUB, SCMON_RDATA (or the SUSG equivalents for Option B).
  3. SCMON has been active at some point (Option A) OR SUSG aggregation has run (Option B). Probe with:
SAPQuery(sql="SELECT COUNT(*) AS CNT FROM SCMON_DATA")
SAPQuery(sql="SELECT COUNT(*) AS CNT FROM SUSG_I_DATA")

Zero rows in both → data collection hasn't happened. Point the user to the next section and stop.

If the customer has no SCMON/SUSG data yet

Tell them:

  1. SAP GUI: transaction SCMON → activate the monitor → let it run for N days (7 is a common minimum)
  2. Transaction SCMONL shows slice state; SCMOND shows raw data
  3. For permanent data: schedule SCMON_COLLECT as a daily job, then SUSG_COLLECT_FROM_SCMON after it
  4. Re-run this skill once data is flowing

Step 1: Probe which option to use

Run the two COUNT queries above. Decision table:

SCMON_DATA countSUSGIDATA countUse
> 0> 0A (fresher data, real-time) — but mention B is also available for longer history
> 00A (SUSG hasn't aggregated yet)
0> 0B (SCMON expired; SUSG has history)
00Stop. Tell user to activate SCMON; don't guess.

Step 2: Enumerate the scope

Based on user's filter input:

2a. Package

SAPRead(type="DEVC", name="<package>")

Keep only objects of runtime types (PROG, CLAS, FUGR, FUNC) with Z/Y prefix. (Tables, CDS views, interfaces aren't "called at runtime" in a way SCMON/SUSG captures directly.)

2b. Namespace / prefix

SAPSearch takes a single objectType filter — call it once per runtime type and union the results:

SAPSearch(query="<prefix>*", objectType="PROG")
SAPSearch(query="<prefix>*", objectType="CLAS")
SAPSearch(query="<prefix>*", objectType="FUGR")

2c. Object list

Use names as given.

Call this set S (the candidate list).

Step 3: Query runtime usage

Option A (SCMON direct join)

Build a WHERE clause from set S. SAP FreeSQL has query length limits, so chunk if |S| > 100.

sql
SELECT p~PROGNAME, p~OBJECT, p~OBJ_NAME, SUM( d~COUNTER ) AS EXECS
FROM SCMON_DATA AS d INNER JOIN SCMON_PROG AS p ON d~TRIGID = p~PROGID
WHERE p~OBJ_NAME IN ( 'ZCL_FOO', 'ZR_BAR', ... )   -- or  p~OBJ_NAME LIKE 'Z_FI_%'
GROUP BY p~PROGNAME, p~OBJECT, p~OBJ_NAME

Also check trigger-side (some Z-objects run only as transactions/RFCs, never as inner callees):

sql
SELECT s~ROOTNAME, s~ROOTTYPE, SUM( d~COUNTER ) AS EXECS
FROM SCMON_DATA AS d INNER JOIN SCMON_SUB AS s ON d~SUBID = s~SUBID
WHERE s~ROOTNAME IN ( ... )

Union the results. Build set U (runtime-used objects with counts).

Option B (SUSG)

sql
SELECT PROGNAME, OBJ_TYPE, OBJ_NAME, SUM( COUNTER ) AS EXECS, MAX( LAST_USED ) AS LAST_SEEN
FROM SUSG_I_DATA
WHERE <scope filter>
GROUP BY PROGNAME, OBJ_TYPE, OBJ_NAME

Build set U with additional LAST_SEEN timestamp.

Step 4: Static where-used for objects not in U

For each object in S but not in U:

SAPNavigate(action="references", type="<type>", name="<name>")

(references is ARC-1's where-used action — it calls SAP's where-used scope API under the hood.)

Build set W (statically referenced objects — someone calls them in source, even if no one ran them in the observed window).

Step 5: Classify

Apply first-match-wins:

Object in …ClassificationMeaning
U (runtime executed ≥ 1 time)USEDRuns in production; keep
W (referenced in source, not in U)LIKELY_UNUSEDStatic callers exist but nothing exercised it in the observed window
Neither U nor WUNUSEDStrong deletion candidate
S but object doesn't exist on system (e.g., SAPSearch couldn't resolve it)INDETERMINATEManual review

Step 6: Emit the report

6a. Headline

Unused Code Audit — <scope>
Data source: SCMON (2,843 rows, window: 2026-04-12 → 2026-04-19)   ← Option A
  — or —
Data source: SUSG (Aggregated 2026-01-01 → 2026-04-19, 128 days)    ← Option B

Scope:         42 objects
  USED:          18  (43%)  — safe to keep
  LIKELY_UNUSED: 12  (29%)  — still has static callers; investigate
  UNUSED:        10  (24%)  — deletion candidates
  INDETERMINATE:  2   (5%)  — manual review

6b. UNUSED table (the deletion candidates)

Object                  Type  Package           Last change (TR)
ZR_OLD_FI_POSTING       PROG  Z_FI_CUSTOM       2024-02-15 (MARIAN / A4HK900042)
ZCL_LEGACY_HELPER       CLAS  Z_FI_CUSTOM       2023-11-03 (MARIAN / A4HK900031)
...

"Last change" comes from SAPRead(type="VERSIONS"). Old + unused = safest to delete.

6c. LIKELY_UNUSED table with caller hints

For each LIKELY_UNUSED object, show who references it:

ZCL_OLD_SALES_UTILS  (CLAS)
  Called by:  ZR_SALES_JOB (PROG — also UNUSED — cascade delete)
              ZCL_ACTIVE_HANDLER (CLAS — USED at runtime) ← blocks deletion

A LIKELY_UNUSED object whose callers are all UNUSED is transitively deletable. One active caller blocks deletion.

6d. Follow-up options

  • "Want to see the static reference graph as a tree?" (→ chained SAPNavigate where-used)
  • "Want to clean-core-check the USED objects before worrying about unused ones?" (→ sap-clean-core-atc)
  • "Want documentation for the USED objects?" (→ sap-object-documenter)
  • "Want to turn this into a reviewed S/4HANA migration dossier with HTML/CSV/graph outputs?" (→ sap-migration-dossier)
  • "Want to start deleting UNUSED objects?" → Manual: this skill does not delete anything; the user does it via SAPWrite or a transport

Error Handling

SymptomRoot causeFix
SCMON_DATA count = 0, SUSG_I_DATA count = 0Monitoring never activatedStop; instruct user to activate SCMON (Step above)
SCMON has data but all SLICEID=1 and SUSG is 0Slice hasn't rotated; SUSG can't aggregate open slicesUse Option A (direct), skip SUSG; or run SCMON_COLLECT_ALL via SA38 then SUSG_COLLECT_FROM_SCMON
SUSG_LOG shows "SCMON not active"SCMON auto-deactivated (record threshold hit)Raise threshold via SCMON_CONF_SET_MAX_NUM_SLICES, reactivate SCMON, accept you lost one aggregation cycle
SAP_ALLOW_FREE_SQL=falseAdmin policyEither get it relaxed, or fall back to SAPRead(type="TABLE_CONTENTS", name="SCMON_DATA", maxRows=…) (also blocked by SAP_ALLOW_DATA_PREVIEW=false; no joins either way) — badly degrades the report
403 on SCMON_* / SUSG_* tablesMissing S_TABU_NAM authUser needs auth assignment; document tables in request
Scope returns > 500 candidatesUser's filter too broadRefuse; ask user to narrow (a 500-object deletion list is not actionable)

Caveats

What runtime data does NOT tell you

  • Coverage gap: a report that runs every year-end won't appear in a week's worth of SCMON data. Always consider the observation window vs. the object's expected frequency.
  • Dead-code-detection ≠ code elimination: an UNUSED object may be emergency/DR code, exam-period-only, or called by a scheduled job not active during the window. Cross-check with business owners before deletion.
  • Dynamic calls: CALL FUNCTION IN BACKGROUND, SUBMIT with dynamic program names, or CALL METHOD via RTTI may not attribute to the right PROGNAME in SCMON. Some false UNUSEDs are unavoidable.

What this skill does NOT do

  • No deletion. Report only. Deletion must be a human decision, ideally via transport and CTS.
  • No cross-system consolidation (DEV + QAS + PRD usage). That requires exports from each system; this skill reads one system at a time.
  • No replacement suggestions for deprecated-but-used code. For that, use sap-clean-core-atc.
  • No XML import (Option C). If the customer has SUSG XML dumps and nothing else, they need an offline parser.

When to Use This Skill

  • Scoping a custom-code retirement project
  • Before a migration — don't migrate what you don't use
  • Post-project cleanup — removing code written for a feature that was rolled back
  • License/compliance reviews requiring a dead-code inventory
  • Combine with [sap-clean-core-atc](../sap-clean-core-atc/SKILL.md): migrate USED Level-A code, audit USED Level-C/D code, delete UNUSED code entirely

按任务相关推荐

来自同一仓库

更多 Skills

全部 Skills
arc-mcp
社区

analyze-chat-session

Analyze the current conversation's tool calls, responses, errors, and approach to produce a structured feedback report for improving MCP tool usage with ARC-1. Use when the user asks to "analyze this session", "review my chat", "give feedback on tool usage", "how did I do", or wants a retrospective on a debugging session.

安装量
1
GitHub Stars
201
最近更新
9月24日
arc-mcp
社区

debug-slow-sql

Find the root cause of a slow ABAP SQL or Fiori-Elements OData request and propose the cheapest fix — GUI-free via ARC-1 (odataperf sap-statistics timing split, cdssql "Show SQL", SAPQuery execution metrics, ST05 SQL-trace control, ABAP profiler traces), escalating to SAP GUI / HANA only for trace records and execution plans. Use when a report, transaction, Fiori list, CDS view, or OData entity is slow, a query times out under load, or someone asks "why is this SQL/OData so slow" or "where is th

安装量
1
GitHub Stars
201
最近更新
9月24日
arc-mcp
社区

generate-analytics-star-schema

Generate a CDS analytical model (star schema — cube + dimension + text views) on top of a RAP business object or a DDIC table. Use when asked to "create a star schema", "generate an analytical cube and dimensions", "make a RAP BO analytical", "build a CDS cube from a table", or "create an analytical model".

安装量
1
GitHub Stars
201
最近更新
9月24日
arc-mcp
社区

generate-cds-analytical-query

Generate an analytical CDS query (transient projection view with PROVIDER CONTRACT ANALYTICALQUERY) on top of an existing analytical cube. Use when asked to "create an analytical query", "build a KPI query on a cube", "generate an ANALYTICALQUERY view", or "expose a cube for analytics/embedded analytics".

安装量
1
GitHub Stars
201
最近更新
9月24日