关于 sap-unused-code
sap-unused-code 是用于 SAP 自定义代码退役审查的技能,结合 SCMON/SUSG 运行数据与静态引用分析,对限定范围内的对象分类。它要求先提供包、命名空间、对象清单或意图,且不会删除代码。
主要功能
- 01结合运行时数据与静态引用
- 02按四类结果分类对象
- 03支持 SCMON 与 SUSG 数据
- 04要求明确审计范围
- 05提供对象级使用计数
适用场景
- 01评估特定包中的自定义代码是否可退役
- 02筛查指定命名空间内未运行的对象
- 03结合静态调用关系审查删除候选项
MCP 相关
此技能通过 ARC-1 访问 SAP 系统,使用 SAP 查询、搜索、读取和引用导航能力执行分析。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ arc-mcp/ arc-1 --skill sap-unused-code安装后在 Claude Code 中输入/sap-unused-code确认已加载。
详细介绍
SAP 未使用代码发现
查找在运行时从未被调用的 Z/Y 自定义对象——这是任何可信的自定义代码退役项目的前提。结合 SAP 调用监控器(SCMON)的运行时使用数据与静态使用位置分析,将每个对象分类为 UNUSED / LIKELY_UNUSED / USED / INDETERMINATE。
⚠ 必填:范围和意图
此技能没有筛选条件就会拒绝运行。 在 ECC 系统中生成“列出所有未使用代码”的报告,会返回数万行,毫无用处。用户必须至少提供以下一项:
- 包(例如,
Z_FI_CUSTOM)——仅分析此包中的对象 - 命名空间前缀(例如,
Z_SALES_*、/ACME/*)——仅分析匹配此模式的对象 - 对象列表——以逗号分隔的待检查名称
- 意图说明——例如,“查找 90 天内未运行过的 FI-GL 中的 Z 报表”——按目的缩小范围
如果用户未提供任何一项,请先询问。例如:
你要审计哪个包或命名空间?例如:“Z_REPORTING 包”、“所有以 Z_FI_ 开头的 Z* 对象”,或“我准备删除的这 15 个报表”。
这比看起来更复杂的原因(提出方案前请先阅读)
SAP 有两个相关的监控系统。请先确认你要使用哪一个:
| 系统 | 说明 | 数据存放位置 | 延迟 | 数据保留期限 |
|---|---|---|---|---|
| SCMON(ABAP 调用监控器) | 每次调用的原始计数器 | SCMON_DATA + SCMON_PROG + SCMON_SUB + SCMON_RDATA 表 | 激活期间实时 | 滚动保留约 7 天 |
| SUSG(使用统计生成器) | 基于 SCMON 的每日汇总 | SUSG_DATA + SUSG_PROG + SUSG_RDATA + SUSG_SUB + SUSG_ADMIN 表(或 CDS 视图 SUSG_I_DATA、SUSG_I_RDATA、SUSG_I_ODATA) | 取决于批处理计划(默认每天约 02:30) | 数月/数年 |
关键限制: 达到记录阈值时,SCMON 会自动停用(SCMON_CONF_SET_MAX_NUM_SLICES)。如果 SCMON 在统计时间段内处于非活动状态,SUSG 会拒绝汇总。在开发/测试系统中,这会导致数据管道频繁中断。
三种选项(根据系统状态选择)
选项 A(首选)——通过 ARC-1 直接联接 SCMON 表
只要 SCMON 曾在系统上激活过,此选项即可立即使用,无论是否运行过 SUSG 汇总。
-- "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
-- "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
列名注意事项(SAP 的命名正好相反):
SCMON_DATA.TRIGID→SCMON_PROG.PROGID(实际执行的程序,尽管名称容易让人误解)SCMON_DATA.SUBID→SCMON_SUB.SUBID(触发根,即发起调用的事务/报表)
优点: 无需等待批处理,无需轮换切片,可立即运行。 缺点: 保留时间有限(约 7 天);无法回答“过去 6 个月内是否运行过”这类问题。
选项 B——通过 CDS 视图使用汇总后的 SUSG 数据
客户已正确安排 SUSG(生产系统通常如此)时使用。
-- 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
预联接的 CDS 视图:SUSG_I_DATA、SUSG_I_RDATA、SUSG_I_ODATA。这些视图都设置了 @AccessControl.authorizationCheck: #NOT_REQUIRED。
优点: 历史数据更长(数月)、已预先联接(SQL 更简单)、数据受官方支持。 缺点: 必须已运行 SUSG 批处理(运行前 SUSG 中有 0 行);如果 SCMON 在统计时间段内被停用,则无法使用。
选项 C——手动导出 SUSG XML(仅作后备方案)
如果客户已运行 SUSG 事务并导出了 5 个 XML 文件(ADMIN0001.xml、PROG0001.xml、DATA*.xml、RDATA*.xml、SUB0001.xml),此技能可以在本地解析这些文件。这是 Kiro 的处理方式,应作为最后手段——需要人工在 SAP GUI 中操作,并离线传递文件。
此技能不附带 XML 解析器。如果用户坚持选择选项 C,请告知其使用 Kiro 的 parse-susg.py 或编写本地 Python 脚本;ARC-1 无法处理。
智能默认设置(静默应用,不要询问)
| 设置 | 默认值 | 理由 |
|---|---|---|
| 选项选择 | 先探测 SCMON 活动;如果有实时数据,则使用 A,否则使用 B | 大多数系统两者之一可用 |
| 输出分类 | UNUSED / LIKELY_UNUSED / USED / INDETERMINATE | Kiro 的四类分类;便于确定优先级 |
| 使用位置检查 | 是,针对未在运行时观察到的对象 | 静态引用是有效信号 |
| 报告粒度 | 按对象列出计数;前 20 项 + 摘要 | 可按需提供完整列表 |
前提条件
请预先检查以下事项。如果有任何一项缺失,请停止并告知用户。
- ARC-1 服务器上已设置
SAP_ALLOW_FREE_SQL=true(否则SAPQuery会被阻止——它会运行 FreeSQL)。如有需要,请咨询管理员。 - 用户拥有
SCMON_DATA、SCMON_PROG、SCMON_SUB、SCMON_RDATA的S_TABU_NAM授权(选项 B 则为对应的 SUSG 表)。 - SCMON 曾经处于活动状态(选项 A),或者 SUSG 聚合已运行(选项 B)。使用以下方式探测:
SAPQuery(sql="SELECT COUNT(*) AS CNT FROM SCMON_DATA")
SAPQuery(sql="SELECT COUNT(*) AS CNT FROM SUSG_I_DATA")
如果两者都没有返回数据,则尚未进行数据收集。请引导用户查看下一节,然后停止。
如果客户还没有 SCMON/SUSG 数据
告知他们:
- SAP GUI:事务码
SCMON→ 激活监控器 → 让它运行 N 天(7 天是常见的最低时长) - 事务码
SCMONL显示时间片状态;SCMOND显示原始数据 - 如需永久保存数据:将
SCMON_COLLECT设为每日作业,然后运行SUSG_COLLECT_FROM_SCMON - 数据开始流入后,重新运行此技能
第 1 步:探测要使用的选项
运行上述两个 COUNT 查询。决策表:
| SCMON_DATA 计数 | SUSG_I_DATA 计数 | 使用 |
|---|---|---|
| > 0 | > 0 | A(数据更新,实时)——但要提及 B 也可用于更长的历史记录 |
| > 0 | 0 | A(SUSG 尚未聚合) |
| 0 | > 0 | B(SCMON 已过期;SUSG 保留了历史记录) |
| 0 | 0 | 停止。 告知用户激活 SCMON;不要猜测。 |
第 2 步:枚举范围
根据用户的筛选输入:
2a. 包
SAPRead(type="DEVC", name="<package>")
仅保留运行时类型(PROG、CLAS、FUGR、FUNC)且带有 Z/Y 前缀的对象。(SCMON/SUSG 无法直接捕获表、CDS 视图和接口以“在运行时被调用”的方式使用。)
2b. 命名空间 / 前缀
SAPSearch 只接受单个 objectType 筛选条件——对每种运行时类型分别调用一次,然后合并结果:
SAPSearch(query="<prefix>*", objectType="PROG")
SAPSearch(query="<prefix>*", objectType="CLAS")
SAPSearch(query="<prefix>*", objectType="FUGR")
2c. 对象列表
使用给定的名称。
将其称为集合 S(候选列表)。
第 3 步:查询运行时用量
选项 A(直接联接 SCMON)
根据集合 S 构建 WHERE 子句。SAP FreeSQL 有查询长度限制,因此当 |S| > 100 时应分块处理。
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
还要检查触发端(某些 Z 对象只作为事务/RFC 运行,从不作为内部被调用程序运行):
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 ( ... )
合并结果。构建集合 U(运行时已使用对象及其计数)。
选项 B(SUSG)
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
构建集合 U,并附加 LAST_SEEN 时间戳。
第 4 步:对不在 U 中的对象进行静态使用位置检查
对 S 中但不在 U 中的每个对象:
SAPNavigate(action="references", type="<type>", name="<name>")
(references 是 ARC-1 的使用位置操作——它会在底层调用 SAP 的使用位置 API。)
构建集合 W(静态引用对象——源代码中有程序调用它们,即使在观察窗口内没有运行过)。
第 5 步:分类
按从上到下优先匹配:
| 对象位于…… | 分类 | 含义 |
|---|---|---|
| U(运行时执行次数 ≥ 1) | USED | 在生产环境中运行;保留 |
| W(在源代码中被引用,但不在 U 中) | LIKELY_UNUSED | 存在静态调用方,但在观察窗口内没有实际运行 |
| U 和 W 中都没有 | UNUSED | 可以优先考虑删除 |
对象在 S 中,但系统上不存在(例如,SAPSearch 无法解析该对象) | INDETERMINATE | 需人工审核 |
第 6 步:生成报告
6a. 标题
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 表(删除候选项)
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)
...
“最后更改”来自 SAPRead(type="VERSIONS")。长期未更改且未使用的对象最适合安全删除。
6c. 带调用方提示的 LIKELY_UNUSED 表
对于每个 LIKELY_UNUSED 对象,显示引用它的对象:
ZCL_OLD_SALES_UTILS (CLAS)
Called by: ZR_SALES_JOB (PROG — also UNUSED — cascade delete)
ZCL_ACTIVE_HANDLER (CLAS — USED at runtime) ← blocks deletion
如果 LIKELY_UNUSED 对象的所有调用方都是 UNUSED,则可传递删除该对象。只要有一个活跃调用方,就不能删除。
6d. 后续选项
- “想以树形结构查看静态引用图吗?”(→ 链式调用
SAPNavigate where-used) - “想先对 USED 对象进行 clean-core 检查,再考虑未使用的对象吗?”(→ sap-clean-core-atc)
- “想查看 USED 对象的文档吗?”(→ sap-object-documenter)
- “想将其整理成经过审核的 S/4HANA 迁移档案,并生成 HTML/CSV/图表输出吗?”(→ sap-migration-dossier)
- “想开始删除 UNUSED 对象吗?” → 手动操作:此技能不会删除任何内容;用户需通过
SAPWrite或传输请求自行操作
错误处理
| 症状 | 根本原因 | 修复方法 |
|---|---|---|
SCMON_DATA 计数 = 0,SUSG_I_DATA 计数 = 0 | 从未启用监控 | 停止;指导用户启用 SCMON(见上方步骤) |
SCMON 有数据,但所有记录的 SLICEID=1 且 SUSG 为 0 | 切片尚未轮换;SUSG 无法汇总未关闭的切片 | 使用选项 A(直接读取),跳过 SUSG;或通过 SA38 运行 SCMON_COLLECT_ALL,然后运行 SUSG_COLLECT_FROM_SCMON |
SUSG_LOG 显示“SCMON not active” | SCMON 自动停用(达到记录阈值) | 通过 SCMON_CONF_SET_MAX_NUM_SLICES 提高阈值,重新启用 SCMON,并接受会损失一个汇总周期 |
SAP_ALLOW_FREE_SQL=false | 管理员策略 | 要么申请放宽限制,要么退回到 SAPRead(type="TABLE_CONTENTS", name="SCMON_DATA", maxRows=…)(也会被 SAP_ALLOW_DATA_PREVIEW=false 阻止;无论如何都不能进行联接)——报告质量会大幅下降 |
访问 SCMON_* / SUSG_* 表时返回 403 | 缺少 S_TABU_NAM 授权 | 用户需要获得授权;在申请中列出相关表 |
| 范围返回超过 500 个候选对象 | 用户的筛选条件过于宽泛 | 拒绝;请用户缩小范围(500 个对象的删除清单无法实际执行) |
注意事项
运行时数据无法告诉你的内容
- 覆盖缺口:每年年末运行一次的报告不会出现在一周的 SCMON 数据中。务必结合观察窗口与对象的预期使用频率进行判断。
- 死代码检测 ≠ 代码消除:UNUSED 对象可能是应急/灾难恢复代码、仅在考试期间使用的代码,或由观察窗口期间未运行的计划作业调用。删除前请与业务负责人核实。
- 动态调用:
CALL FUNCTION IN BACKGROUND、使用动态程序名的SUBMIT,或通过 RTTI 调用的 CALL METHOD,可能无法在 SCMON 中归因到正确的 PROGNAME。无法避免出现一些误判为 UNUSED 的对象。
此技能不会执行的操作
- 不删除。 仅生成报告。删除必须由人工决定,最好通过传输请求和 CTS 完成。
- 不合并跨系统数据(DEV + QAS + PRD 的使用情况)。这需要导出每个系统的数据;此技能一次只读取一个系统。
- 不提供已弃用但仍在使用的代码的替代建议。 如需此功能,请使用 sap-clean-core-atc。
- 不导入 XML(选项 C)。如果客户只有 SUSG XML 转储文件,则需要使用离线解析器。
何时使用此技能
- 为自定义代码退役项目确定范围
- 迁移前——不要迁移未使用的内容
- 项目结束后的清理——移除为已回滚功能编写的代码
- 需要死代码清单的许可证/合规性审查
- **与 sap-clean-core-atc 结合使用:**迁移 USED Level-A 代码,审计 USED Level-C/D 代码,彻底删除 UNUSED 代码