sap-transport-review — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sap-transport-review (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Answer "what actually changed?" for a transport or for your in-flight (unactivated) work, as a reviewable report: a per-object unified diff plus risk flags — not a wall of full source.
It leans on two token-cheap ARC-1 primitives so a review of a 30-object transport costs a handful of small diffs instead of 60 full-source reads:
SAPTransport(action="list", summary=true) — scan many open transports cheaply (objects omitted, objectCount kept), then drill into one.SAPRead(action="diff", from=…, to=…) — server-side unified diff per object; the response is just the hunks.Complements explain-abap-code (deep single-object understanding) and sap-object-documenter (written docs for a package). This skill is about delta — what moved between two points in time — for code review, hand-off, or a pre-release gate.
| You are… | Scope | What the skill does |
|---|---|---|
| Reviewing a transport (senior dev / approver) | one transport id | Diff every safely resolved source object, label the version coverage, and add impact/quality checks only when requested or risk-triggered. The chat / whole-transport twin of Eclipse ADT 3.6's "Object Changes" tab (same source-diff coverage boundary). |
| Checking your own recent work (dev) | your modifiable transports | "What have I changed since my last release?" — diff each object's last-released version → current. Light: skip impact/ATC unless asked. |
For a system-wide inventory of every open transport (basis: who has what open, how big, conflicts — no diffs) that's a different job → sap-transport-overview.
| Setting | Default | Rationale |
|---|---|---|
| Transport scope | current user, modifiable (status="D") | The work in progress, not released history |
| Overview first | summary=true when listing | Cheap scan before pulling any object list in full |
| Diff direction (in-flight) | from="active", to="inactive" | Exact for pending, unactivated source only; it does not reconstruct changes already activated in an open request |
| Diffable types | PROG, CLAS, INTF, FUNC, FUGR, INCL, DDLS, DCLS, BDEF, SRVD, DDLX, TABL | The plain-text source types action="diff" supports |
| Object-diff cap | ~40 | Above that, summarize counts and ask which to expand |
| Impact | On for changed CDS/RAP objects in a risk-focused review; otherwise opt-in | Focus the extra reads where dependency risk exists |
| ATC | Opt-in (+atc) or clearly risk-triggered; bounded to changed objects | ATC is workload-producing and must not fan out silently across a large request |
The user provides one of:
A4HK900123) — review everything in that request.Optional: +impact (who consumes the changed CDS/RAP), +atc (new quality findings), output path for a Markdown file.
Scope guard: if the selected set exceeds ~40 diffable objects, show the object table with +/- counts only and ask which objects (or which task) to expand into full diffs. A review nobody reads is worse than no review.
SAPTransport(action="get", id="<id>") → the tasks[].objects[] list.SAPTransport(action="list", summary=true) → a cheap table(id, description, owner, status, objectCount). Present it, let the user pick, then get that one.
or the objects in the named package). No transport id needed for the diff itself.
SAPTransport get returns CTS identities, not guaranteed SAPRead inputs. Each entry has pgmid, CTS type, name, and wbtype; real transports may also contain subobjects such as LIMU/METH, LIMU/REPS, language entries, and package/metadata entries.
Before diffing:
tasks[].objects[], but keep the task id and original CTS key for the report.R3TR entries (R3TR/CLAS, R3TR/DDLS, …) as direct repository objects anddeduplicate exact repeats.
pgmid (LIMU, LANG), a CTS subtype (METH, REPS), or wbtype (CLAS/OM,PROG/I, …) to SAPRead(type=…).
exposes only the subobject, report it as parent resolution unavailable rather than guessing a class/include name. This is a coverage limitation, not evidence that nothing changed.
a unique-object count.
Then split the resolved repository objects into:
action="diff" returns "not supported" (their read is parsed metadata/XML, not plain-text source). This is exactly the boundary SAP's own Eclipse ADT 3.6 "Object Changes" has — it prints "Feature not supported for object …" for these same types (e.g. SRVB). Don't try to diff them. For a thorough review, still read the object's metadata (e.g. SAPRead(type="SRVB", name=…)) so the report names what the object is and that it's in the change set — just without a source diff.
from/to by intentRun these in parallel (each returns only hunks):
SAPRead(type="<type>", name="<name>", action="diff", from="<from>", to="<to>")Choose the sides by what the user is reviewing:
| Intent | from → to | Notes | |||
|---|---|---|---|---|---|
| Pending draft ("what I'm about to activate") | active → inactive | Exact pending-source diff. No draft means "no pending source", not "the open transport made no changes". | |||
| Since the latest released snapshot | <latest released revision id> → active (or inactive if still draft) | Captures all changes since that release; it may combine multiple open requests and must be labelled that way. Confirm revision ordering/timestamps rather than assuming feed order. | |||
| Released transport ("what did this TR change") | <revision immediately before TR> → <revision tagged with TR> | Compare the transport's own released snapshot, not today's active source. If the matching snapshot/predecessor is ambiguous or absent, report the baseline gap. | |||
| Specific revisions | `<id\ | uri> → <id\ | uri\ | active>` | From a VERSIONS response. |
Snapshot-sparsity reality (important): ABAP cuts a version snapshot only when a transport is released. So for an open/unreleased transport, objects usually have just the active version (+ maybe an inactive draft) — there is no "before" revision to diff against. Handle it honestly:
SAPRead(type="VERSIONS", name=…, objectType=…) where supported.If either cannot be established, do not substitute current active source for an old transport.
active → inactive only for the pending portion. A prior releasedrevision → active comparison is useful, but label it "since released snapshot" because it can include other open requests.
baseline unavailable.Do not call it an add unless independent object metadata proves creation in this request.
The report must state its coverage: pending draft, released snapshot, since released snapshot (may span requests), or baseline unavailable.
DDLS/BDEF/SRVD can break consumers): SAPContext(action="impact", type="DDLS", name="<view>") → projection views, BDEFs, service defs/bindings, ABAP consumers that depend on it.+atc, or risk justifies it, run SAPDiagnose(action="atc", ...)only for the bounded changed set. Use SAPLint(action="lint", name=…) for a cheaper local pass.
SAPDiagnose action="syntax" check for unactivated work.SAPActivate mutates system state; run it only when the user explicitly asks to activate.
# Change review — <transport id or "pending drafts"> on <SID>
_<owner> · <status> · <description>_
_Coverage: <pending draft | released snapshot | since released snapshot | baseline unavailable>_
## Summary
| Object | Type | Change | +/− | Flags |
|---|---|---|---|---|
| ZCL_ORDER | CLAS | changed | +12 −3 | |
| ZI_ORDER | DDLS | changed | +4 −0 | impacts 3 consumers |
| ZNEW_REPORT | PROG | unknown | — | baseline unavailable |
| ZSTATUS | DOMA | changed | — | metadata — no source diff |
| <CTS subobject> | LIMU/METH | unresolved | — | parent resolution unavailable |
## Diffs
### ZCL_ORDER (CLAS) active → inactive (+12 −3)<the unified-diff hunks from SAPRead action="diff">
…one block per diffable object…
## Risk flags
- ⚠ ZI_ORDER (DDLS) has 3 downstream consumers — re-activation order matters (see impact).
- ⚠ ZCL_BP appears in two explicitly expanded request manifests; current lock holder is A4HK900123.
- ⚠ A4HK900123 has no target — this is a local request and cannot be imported onward.
## Verdict
<2–3 lines: what this change set does, what to review first, what's risky / not yet activated.>Write to disk (default docs/reviews/transport-<id>-<date>.md) only if asked; otherwise return inline.
| Error | Cause | Fix |
|---|---|---|
action="diff" → "not supported for type X" | Metadata type (DOMA/DTEL/MSAG/SRVB/VIEW/…) | Expected — list it as "metadata — no source diff", don't diff |
| "No differences between active and inactive" | No unactivated draft for that object | Report "no pending source"; do not infer that the open request made no activated changes |
| "Revision-id diff is not available for type X" | FUGR/DDLX have no revisions feed | Use active/inactive or a full /sap/bc/adt/ URI instead of a bare id |
| VERSIONS returns 1 revision | Snapshot only cut on release (sparsity) | Use active→inactive only for a real pending draft; otherwise report baseline unavailable |
Transport entry is LIMU/*, LANG/*, or only has a slash wbtype | CTS identity is not a SAPRead type | Fold into an unambiguous parent entry or report parent resolution unavailable; never guess |
Transport get 404 | Wrong id / already deleted | Re-list with summary=true and confirm the id |
| >40 objects in scope | Review too large to read | Show the +/- table, ask which task/objects to expand |
per instance. Do a cross-system review by running the ARC-1 CLI against each system (arc1-cli call SAPRead … --url <sys>) and diffing the two outputs — a separate orchestration, not this skill.
SAPActivate, then SAPTransport(action="release").SAPContext(action="impact") (or re-run with +impact).~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.