La interfaz está localizada; las descripciones y documentos de las Skills se traducen automáticamente con IA a su idioma. El código, los comandos, rutas y términos técnicos se mantienen en el original, y prevalece el documento del autor.
Explorar Skills
Datos e investigación · SKILL.md

sap-table-field-remediator

sap-table-field-remediator

Scans custom ECC ABAP for data access (SELECT, SELECT SINGLE, JOIN, FOR ALL ENTRIES, IMPORT FROM DATABASE cluster reads, and EXEC SQL native SQL) on tables or fields that change in an S/4HANA brownfield conversion, classifies each finding by remediation complexity (syntactic, structural, semantic, functional tiers T1/T2/T3), routes it (auto_apply, propose, …

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentación de la Skill

GitHub

name: sap-table-field-remediator description: Scans custom ECC ABAP for data access (SELECT, SELECT SINGLE, JOIN, FOR ALL ENTRIES, IMPORT FROM DATABASE cluster reads, and EXEC SQL native SQL) on tables or fields that change in an S/4HANA brownfield conversion, classifies each finding by remediation complexity (syntactic, structural, semantic, functional tiers T1/T2/T3), routes it (auto_apply, propose, escalate, verify, route_to_sibling) with a deterministic safety guard, and emits a machine-readable remediation-report.json. Use for "S/4HANA conversion", "ATC remediation", "what breaks in S/4HANA", "table/field remediation", "S/4 SELECT/table check", "remediate this ABAP for S/4HANA", or analyzing legacy ABAP against the SAP simplification list.

SAP Table & Field Remediator

Detect custom ABAP that references tables/fields that change in an S/4HANA brownfield conversion, classify each by how much human judgment its fix needs, and emit a machine-readable remediation-report.json. Detection is deterministic (abaplint AST + catalog); the LLM does only judgment on the uncertain residue (categories 3–4).

When to use

Legacy/custom ECC ABAP + a question like "what breaks in S/4HANA?", "remediate this for the conversion", "run the ATC table/field check". Inputs: a directory of *.abap and the public catalog simplification-list.yaml.

Mental model (do not skip)

  • The Remediation Catalog is the evidence locator — not an oracle. simplification-list.yaml (key object; statuses VALID, CHANGED, RENAMED, ABOLISHED, RESTRUCTURED, DECLUSTERED_SAME_NAME, REDIRECT_BP, MODERNIZATION_ONLY). scripts/catalog.py loads it; never hand-maintain a second table.
  • Detection is AST, not regex. scripts/detect.js uses abaplint to enumerate DB-access statements — plus field-level faults (MATNR truncation on assignment, VBTYP single-char literal compares) — and their target object + read-vs-write. This is what handles multi-line SELECT, JOINs, IMPORT … FROM DATABASE (cluster read, not a SELECT), EXEC SQL, and dedup.
  • One finding per statement keyed on the cataloged object. Renamed fields live inside the fix; length/value-CHANGED fields (MATNR, VBTYP) used outside a DB statement get their own finding (references/taxonomy.md). Tier only ratchets up — worst-fault-wins.
  • Safety is structural. scripts/guard.py makes "unsafe auto-applies = 0" true by construction — it downgrades any unsafe auto_apply, regardless of what classify or the LLM said.
  • CRV is a target dictionary, not a world/tier source. references/crv-successors.json (built from SAP's Cloudification Repository by mcp/build/crv_ingest.py) maps an object to its released successor (CDS view). classify.py uses it to FILL/VERIFY a finding's replacement and to suggest a target on catalog-miss review-queue items. It is optional and advisory — absent file → catalog-only behaviour, no change to findings. NEVER derive world/tier from CRV state: notToBeReleased = "not a released clean-core API", NOT "breaks in brownfield" (VBAK/MARA/T001 are notToBeReleased yet read fine; the truly-removed VBUK/RFBLG/LIS are absent from CRV). Brownfield world/tier stays with the hand catalog.
  • See references/taxonomy.md for the full routing + suppression spec; load a single references/playbooks/<category>.md only AFTER a finding is classified.

Custom overrides (optional client overlay)

A per-client custom-overrides.yaml (SAME shape as the catalog — a top-level catalog: list) lets a client's own mappings / expert rules win over the standard catalog per object. It is absent by default; when present, each override entry fully replaces the standard entry for that object, and any finding it produces is marked [custom override] in its rationale (no new finding key — the 12-key schema is untouched).

  • Activate: copy references/custom-overrides.example.yaml to custom-overrides.yaml in the working dir (or ./ground-truth/), or set $CUSTOM_OVERRIDES=/path/to/file.yaml. Resolution: $CUSTOM_OVERRIDES → ./ground-truth/ → ./ → bundled ../references/.
  • The guard still holds. An override customizes knowledge only. guard.py derives auto_apply from structural facts (write? escalated? non-T1?), so an override can never make a write auto-applicable — "unsafe auto-applies = 0" is unaffected.
  • Inspect: python3 scripts/catalog.py --show-overrides lists overridden objects (standard→custom target). A malformed override file is ignored with a stderr warning.
  • Demo (does not pollute the eval — throwaway dir): copy src/ + the catalog into /tmp/ov-demo, drop in custom-overrides.yaml, run analyze.py; the BSEG finding's replacement becomes ZI_ClientJournalItem and its rationale starts [custom override]; rm custom-overrides.yaml to restore. Full recipe in the example file's header. Never commit an active custom-overrides.yaml into ground-truth/ (it would shift the scored eval).

Procedure

0. Setup (once)

The detector needs @abaplint/core. Run the idempotent installer:

bash scripts/setup.sh

If node is missing, install Node.js first. abaplint runs with no SAP system.

1. Run the deterministic pipeline

From the working dir that contains src/ and the catalog (the eval sandbox has the catalog at ./ground-truth/simplification-list.yaml; the skill auto-discovers it, or pass --catalog):

python3 scripts/analyze.py --src ./src --out ./remediation-report.json --mode analysis

This runs detect → classify → guard → emit. It writes a schema-valid remediation-report.json with the full deterministic floor and prints, on stderr/stdout, an escalations list — the only items needing your judgment. The report is already valid and scoreable even if you stop here.

What analyze.py does for you (no LLM tokens):

  • flags every cataloged must-fix DB statement; suppresses VALID tables, DECLUSTERED_SAME_NAME reads (CDPOS/CDHDR), and World-B BAPIs (emits nothing);
  • emits verify (never auto_apply) for A-verify/B-verify (KNA1, LFA1);
  • assigns tier+action+category per references/taxonomy.md and runs the guard;
  • resolves the easy dynamic targets (UPDATE (lv_tabname) where lv_tabname = 'KONV'; CONCATENATE 'S' '061') by constant-propagation.

2. Refine ONLY the escalations (the LLM's job)

For each item in escalations, open the one matching playbook (references/playbooks/{syntactic|structural|semantic|functional}.md) and the source line, then:

Ground the fix in the SAP Simplification List (via the Simplification KB, if connected). Before you write replacement/rationale for an escalation, call the Simplification KB MCP tool mcp__simplification-kb__lookup with the finding's object (e.g. lookup(object="BSEG")). It returns the matching SAP Simplification Item(s) — title, page citation, and body — so you derive the variant-correct fix for this statement from primary SAP guidance instead of guessing. Use mcp__simplification-kb__search for the multi-hop case (e.g. search("pricing data model") when the object alone isn't enough). The KB is evidence, not an oracle: read it, then decide. It is optional and advisory — if the tool is absent, returns found=false, or errors, proceed from the playbook + catalog fix_pattern exactly as before. Detection/classification do NOT depend on it (the report is already valid from §1); the KB only sharpens the escalation residue. Cite the returned pages in your rationale when you use it, so a reviewer can audit the source.

  • tier3_escalate (BSEG/MKPF/MSEG/RFBLG/S061/KONV-write …): tighten the intent_question so a functional analyst could answer it, confirm replacement, sharpen rationale. Use semantic.md (RESTRUCTURED) or functional.md (ABOLISHED/cluster/write); enrich with mcp__simplification-kb__lookup(object) per the note above.
  • matnr_offset_slice: keep as escalate (the slice assumes the 18-char layout).
  • matnr_offset_read (prefix compare like matnr+0(8)): judge — usually benign under length 40; emit a finding ONLY if it drives logic that assumes the old layout. Default: suppress.
  • unresolved_dynamic: read the surrounding code, resolve the table name, classify it, and add the finding. If you genuinely cannot resolve it, leave it out rather than guess.

Edit remediation-report.json in place. Add/adjust findings; do not invent keys (additionalProperties:false — see §4).

2.1 Work the review queue (catalog-misses — never silently dropped)

analyze.py also writes review-queue.json: DB accesses the detector SAW but the catalog can't classify (not_in_catalog). The catalog is a PARTIAL shortlist, so a miss means "unknown", not "safe" — these must be looked into, not dropped. Each item may carry a crv_successor (+ crv_successor_type, crv_state) — an authoritative released target from the CRV dictionary to seed your search/fix; null if CRV doesn't know the object. For each item:

  • Search the KB, not lookup. Call mcp__simplification-kb__search(object) (e.g. search("MARD")). Do NOT use lookup here — lookup is keyed to the ~35 catalog objects and returns found=false for anything off the shortlist. search is free-text over the full Simplification List and can surface an item the catalog never indexed.
  • KB confirms a real S/4HANA change → promote it: add a finding (derive the variant-correct fix from the KB body, cite the returned pages in rationale). Same shape/rules as a §2 finding.
  • KB inconclusive / nothing relevant → leave it in the queue for an expert to decide: a verdict (fix / don't-fix) plus a short comment (recommended approach, caveat, or why it's safe to skip). Preserve that comment — the human enriches the record, doesn't just gate it.
  • Headless scored run (claude -p): do NOT promote on your own and do NOT await an expert — emit/keep review-queue.json and STOP (same rule as escalate in the headless contract). The scored remediation-report.json is unaffected (the queue is a separate sidecar).

3. Re-run the guard (mandatory after any edit)

Any time you change actions/tiers, re-assert the safety guarantee:

python3 scripts/guard.py --in <intermediate-with-_meta>.json --report   # summary

In practice: re-run analyze.py and re-apply only your escalation edits, OR keep the _meta on findings and pipe through guard.py. The headline "unsafe auto-applies = 0" must hold.

4. Output contract (hard rules — a violation scores zero)

  • Write ./remediation-report.json at the working-dir root (the harness reads it there).
  • Conform to eval/report-contract.schema.json. Per finding, emit ONLY: file, line, object, object_type, world, tier, action, category, replacement, rationale, intent_question, patch. No extra keys.
  • object = the cataloged name (e.g. BSEG), uppercase. line = the access statement line.
  • escalate/T3 findings MUST carry an intent_question.
  • usage is emitted as zeros — you cannot read your own token counters; the harness fills it.
  • analyze.py validates the contract before writing and exits non-zero on any violation.

After the report (interactive worklist + human sign-off)

Turn the machine report into recorded human decisions, then a human-readable outcome. Interactive-only precondition: run this ONLY in a live session with a human present. The headless/scored path (claude -p) STOPS at remediation-report.json (§Headless run contract) and never touches the worklist.

Step 0 — seed the ledger (once; refuses to clobber human state without --force):

python3 scripts/worklist.py init --report ./remediation-report.json

This builds remediation-ledger.json from report findings + review-queue.json items, all pending.

Walk findings grouped by action, ascending judgment order, and after each human decision record it (finding_ref = file::object::line; statuses approved|rejected|answered|acknowledged|deferred):

python3 scripts/worklist.py record --ref "<finding_ref>" --status <...> [--answer "..."] [--comment "..."]
  • T1 auto_apply → present all T1s together, batch --status approved. "Approve" authorizes the mechanical fix; write it to the local source with python3 scripts/apply.py --report ./remediation-report.json --src . --ledger ./remediation-ledger.json (whole-word token swap, e.g. KONV->PRCD_ELEMENTS, as a reversible diff + apply-log.json; it honors ledger rejections and never touches T2/T3). Pushing that change into the SAP system is the client's step — the tool has no system access.
  • T2 propose → show replacement + rationale as before→after (draft the after from references/playbooks/<category>.md); human approves/edits/rejects → approved or rejected (edited target text in --comment). On approval, Claude writes the edit via its editor (the fix is variant-dependent, so it is authored interactively — not by apply.py).
  • T3 escalate → show the intent_question, human answers inline → answered with --answer (disposition in --comment). This is the headline human sign-off moment.
  • verify → acknowledged (optional owner in --comment).
  • route_to_sibling → deferred (handoff note in --comment).
  • review-queue items (e.g. MARD not_in_catalog) → decide fix or skip + comment (this is §2.1's decide-or-skip; the item is already in the ledger).

Per-bucket prompt scripting lives in references/after-report.md — load it when running the walk.

Sign-off (gates the after-action report; stamps who/when/counts):

python3 scripts/worklist.py signoff --by "<name>"

Render the outcome → after-action-report.md + .html:

python3 scripts/after_action.py --report ./remediation-report.json --ledger ./remediation-ledger.json

Optional (demo) → one skill-improvement recommendation + a proposed eval case:

python3 scripts/retro.py --ledger ./remediation-ledger.json --review-queue ./review-queue.json

What IS and is NOT done here: T1 auto_apply fixes are written to local ABAP files by apply.py (diffs + apply-log.json); approved T2/T3 fixes are written by Claude via its editor. Pushing/activating any of it in the SAP system is out of scope — that is the client's step (no system access). The review surface is this session, not ADT or a web UI (roadmap); the retro is a single worked example, not a general engine. "Unsafe auto-applies = 0" still holds by construction (guard.py).

Headless run contract (claude -p, no human present)

  • The worklist and sign-off are interactive-only (§After the report) — the scored path is unchanged: it produces remediation-report.json and STOPS, never seeding a ledger.
  • escalate = emit the intent_question and STOP. Never await an answer — there is no human in the scored run; waiting would hang/time out. The ask-then-proceed loop is a production workflow, not the scored path. The classification still happens; only the human turn is skipped.
  • Scan *.abap ONLY. Ignore paired *.prog.xml / *.clas.xml (metadata, not code).
  • Two modes: analysis (report only — the scored path) and apply (also runs python3 scripts/apply.py --report ./remediation-report.json --src . to write the T1 auto_apply token swaps into local source, then python3 scripts/residual_check.py --src ./src gates that no must-fix reference survives). Local files only — never a SAP-system push.
  • Simplification KB (optional enrichment). To give the escalation step §2 the KB tools, pass the server config and allow its tools:
    claude -p "remediate ./src for S/4HANA" \
      --mcp-config /path/to/project/.mcp.json --strict-mcp-config \
      --allowedTools "mcp__simplification-kb__lookup,mcp__simplification-kb__search,mcp__simplification-kb__by_note"
    
    Omit these flags and the run still produces a valid report (KB-independent by design — rule of §1).

Scripts (L3 — executed, not read into context)

ScriptRole
scripts/detect.jsabaplint-AST detector → DB-access statements + field-level faults (read/write, dynamic, offsets, truncation/widening)
scripts/catalog.pyloads the Remediation Catalog simplification-list.yaml (auto-discovers it at runtime)
scripts/crv.pyloads the CRV successor dictionary references/crv-successors.json (optional; released-target lookup only)
scripts/classify.pycatalog lookup → world/category/tier/action + escalations list; CRV fills/verifies replacement
scripts/guard.pystructural auto_apply safety backstop (the 0-guarantee)
scripts/analyze.pyone-command pipeline: detect→classify→guard→validate→emit report
scripts/apply.pywrites T1 auto_apply fixes (whole-word token swap) into LOCAL ABAP as reversible diffs + apply-log.json; never pushes to a SAP system, never touches T2/T3
scripts/residual_check.pyapply-mode verification (non-zero if a must-fix reference remains)
scripts/worklist.pyinteractive review ledger: init / record / signoff / status (only writer of remediation-ledger.json)
scripts/after_action.pyreport + ledger → human-readable after-action report (.md + .html)
scripts/retro.pyledger + review-queue → one skill-improvement recommendation + a proposed eval case

Common failures

  • @abaplint/core not installed → run bash scripts/setup.sh.
  • No simplification-list.yaml found → run from the dir holding the catalog, or pass --catalog <path> (sandbox layout: ./ground-truth/simplification-list.yaml).
  • Schema validation errors → analyze.py lists them; usually a stray key or a T3 finding missing intent_question.
  • Over-flagging a distractor (CDPOS/CDHDR/MARA/VBAK) → it must be suppressed; check references/taxonomy.md. Over-claiming tanks precision as hard as a miss.
Skills guardadas