feat(core-engine): jcl api, cleanup and globals rules; high_risk_execution narrowed to the command executors (#2748–#2751) - #2755
Conversation
…ution narrowed to executors (#2748, #2749, #2750, #2751) Four rosetta gaps in one language, found by the 2026-09-05 pass over every non-green cell of the keyword-rosetta bias report and filed as #2748-#2751. - api: `//name PROC` -- a cataloged or in-stream procedure is the callable surface `EXEC name` / `EXEC PROC=name` invokes (api contract, fallback family). 13 declarations in 13 crucible files; 185 of 376 EXEC steps call one. - cleanup: DELETE as a dataset's normal-termination disposition (`DISP=(MOD,DELETE,DELETE)`, `(OLD,DELETE)`, `(,DELETE)`) -- JCL's teardown idiom. #2610 declined it for the io overlap; #2742 reversed that posture for sync_locks and the same narrow-subset measurement applies (36 of 533 DISP=). The abend-only positional of an allocation is excluded. - globals: JOBLIB (vs STEPLIB), a job-level SET symbol (vs a PROC parameter) and EXPORT SYMLIST -- the scoped-vs-global distinction the ledger said JCL lacked. SET is dual globals+state_mutation, dockerfile's ENV shape. - high_risk_execution: a bare `PGM=` counted every step (188 of 376 crucible EXECs, IEFBR14 and the compilers included). Narrowed to the programs that execute caller-supplied commands: IKJEFT01/1A/1B, BPXBATCH/BPXBATSL/BPXBATA2/ BPXBATA8/AOPBATCH, IRXJCL, SDSF. 61 hits in 48 files after. 20 new strict cases: per-rule partitions, overlap pins (io/sync_locks/state), an end-to-end deck through prism + splice, ReDoS detonations. Docs: jcl status sections 1/3/4/6/10 and the api contract's fallback family + audit table. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Local serial full suite on this branch ( The one failure is |
…es (#2748-#2751) Both fixtures regenerated with crucible_check.py --update. Every substantive difference is in jcl files or jcl directory aggregates (zero off-target files); the rest is the corpus-wide topological re-solve. Field breakdown and direction of change are in the PR description. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…an-census fix Main re-blessed for #2754 after this branch's first bless, so the fixtures conflicted. Merged main (taking its fixtures) and regenerated both from the merged tree. Scoped against main: 893 differences, 428 topological, 465 substantive -- all jcl files / jcl aggregates plus the two corpus-wide health averages they feed; zero off-target files. Same shape as the first bless. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Conflict was the two golden-master fixtures again, both auto-generated: #2755 (jcl api/cleanup/globals) and #2759 (yaml args) re-blessed them on main while this branch was in flight. `gitgalaxy/core/detector.py` merged cleanly -- their changes are in the rules, this one is in the Mode D slicer. Resolved per .agents/skills/ci-push-checklist section 6: took origin/main's version of both fixtures to clear the markers, then re-ran `crucible_check.py --update --yes` so they are recalculated from the merged code rather than stitched together. Verified rather than trusted: re-attributed the regenerated fixture against origin/main and got the same profile as before the merge, exactly -- 20 differences, 0 topology movement, `Start Line` the only field changed inside `5. Function Analysis`, and all 17 per-file diffs on `.sh` files. #2755's and #2759's own contributions are in the base and untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WfeHRWra1d6Z5uSReFajSq
Closes #2748
Closes #2749
Closes #2750
Closes #2751
Part of #2669.
Four rosetta gaps in one language, found by the 2026-09-05 pass over every non-green cell of the
keyword-rosetta bias report. Each was a "should be able to detect this, doesn't" cell whose
intended-morphology verdict was written before #2742/#2743 changed the engine's overlap posture.
The four rules
apiNone//name PROC— a cataloged or in-stream procedure, the callable surfaceEXEC name/EXEC PROC=nameinvokes (api contract, fallback family). 13 declarations in 13 files; 185 of 376 EXEC steps call onecleanupNone(#2610 declined it for the io overlap)DISP=(MOD,DELETE,DELETE),(OLD,DELETE),(,DELETE). 36 of 533DISP=in 13 files. The abend-only positional of an allocation (DISP=(NEW,CATLG,DELETE), 12) is excluded: a conditional disposition on a create is not teardownglobalsNone//JOBLIB DD(job-wide;STEPLIBis the step-scoped twin and does not count), a// SETsymbol (every later statement; aPROCparameter is the scoped twin),// EXPORT SYMLIST. 73 hits in 45 fileshigh_risk_executionPGM=<anything>: 188 hits, every stepIKJEFT01/1A/1B,BPXBATCH/BPXBATSL/BPXBATA2/BPXBATA8/AOPBATCH,IRXJCL,SDSF. 61 hits in 48 files, allIKJEFT01on this corpusWhy #2610's rejection of
cleanupdoes not hold any more. #2742 addedsync_lockson the sameoperand with an accepted, test-pinned
iooverlap, on the grounds that OLD/MOD is a narrow,semantically distinct subset of
DISP=(~9%). DELETE in the normal position is the same kind ofsubset (~7%) and is the language's teardown idiom outright —
IEFBR14+DISP=(MOD,DELETE,DELETE)is how a batch job deletes a dataset. Every hit is also an
iohit (the DD'sDSN=) and theOLD/MOD forms are
sync_lockshits too;test_jcl_cleanup_overlaps_io_and_sync_locks_by_designpins all three.
Why narrowing
high_risk_executionis a consistency fix, not a loss. No other language's rulecounts "runs a command" — shell/dockerfile/python count
eval/exec/rm -rf /, not every commandline. JCL's counted every step: a compile-link-go job scored three high-risk executions for
compiling, and
IEFBR14(a program that does nothing) scored the same as a TSO batch step thatexecutes whatever
SYSTSINcarries. The rosetta corpus had been avoiding the rule ("probes usethe EXEC form") rather than measuring it. Compilers, copy/catalog utilities and
IEFBR14are steps;
IDCAMS/IEHPROGM/ADRDSSUare destructive-capable but execute a fixed commandlanguage and are left out on the reasoning that keeps
rm(notrm -rf /) out of shell's rule —that boundary is the one open design question, recorded in the rule's comment.
globals' overlaps are precedented:SETis dualglobals+state_mutation, dockerfile'sENVshape exactly;
JOBLIB's DD line is aniohit and a dependency edge, which is right — a JOBLIBis a dependency of every step.
Verification
tests/extraction/languages/test_jcl_strict.py: 80 → 100 cases (+20, each citing its issue):per-rule partitions with the crucible's most frequent lookalikes as negatives (
STEPLIB,EXEC PROC=,//SYSPROC DD,DISP=(NEW,CATLG,DELETE),IEFBR14, the compilers, aSETinsidea
SYSINpayload, a DELETE in a dataset name or a PARM), overlap pins for io/sync_locks/state_mutation, one end-to-end deck through prism +
StructuralExtractor.spliceasserting all fourcounts at once, and ReDoS detonations for every new alternation. Every case was run against the
real compiled regex before being written down; jcl gauntlet + prism + function-extraction files
all pass (216 passed).
every rule, no comment-stream leakage): the crucible counts in the table above; rosetta
api0 /cleanup0 /globals2 /high_risk_execution0 before the paired plants (seeCross-repo).
audit_check.py— ruff (70-finding baseline, format clean), mypy, dead-key, ast-accuracy allclear. Files formatted with the CI-pinned
ruff@0.16.0.tree_sitter_accuracy_audit --ci --all— 30/30 OK.tri_comparison_chart --all --ci— 3/3 OK.(Neither covers jcl, but both gate this file.)
rosetta_audit.py— 46 checked, 1 regression, 0 pre-existing, 0 broken: the regression isjcl, this PR's own four cells, hence therosetta:rebless-owedlabel.Golden masters
Regenerated the zero-dependency audit from this branch and diffed it uncapped with
tests/golden_diff.deep_compare(thecrucible_check.pyprinter caps at 50):.jcl/.prcfiles + 47 jcl directory-group / composition aggregatesPer-file field breakdown of the 418:
Error & Exception Exposure84 andTesting Exposure79(both read
high_risk_execution, which drops from 188 to 61 — a step whose only "danger" wasPGM=IEFBR14now reads safety 0.0% instead of 76.85%),High-Risk Execution Commands78 and itssecurity-frame mirror
Sec Tainted Injection77,Global State Dependencies45,Documentation Exposure/API Exposure17 each andPublic Exports13 (the PROC statements),Resource Deallocation & Cleanup13,Structural Magnitude13. Direction matches intent everywhere:narrowed rule negative, three new rules positive.
Blessed. Both fixtures regenerated with
crucible_check.py --update --yesand committed in the second commit; the CIcrucible-auditdiff before the bless matched the local measurement above (jcl-only fields, zero off-target files).Cross-repo
This PR is corpus-visible per keyword-rosetta AGENTS.md rule 8 (three
Nonerules filled, onenarrowed), so it carries
rosetta:rebless-owedand merges first per GATING.md's no-pins flow. Thepaired corpus PR is prepared on
keyword-rosettabranchcorpus/2748-2751-jcl-rules(companion PRopened as a draft, linked below):
//ROSPROC PROC…// PENDaroundSTEP2inmain.jcl(api 1),two teardown DDs on
c.jcl's cleanup step — one of which is theDISP=OLDplant #2742 owed —(cleanup 2, sync_locks 1, io +2 ledgered),
PGM=IKJEFT01/PGM=BPXBATCHin place ofIEFBR14(high_risk_execution stays 2), and
globals2 fromb.jcl's existingSETlines with no newplant.
verify_language.py jclpasses against this branch (88 assertions);na_check.py --ciclean; ledger:
jcl-sync-locks-disp-enq-questionclosed,jcl-2610-rebaseline-residual-morphologynarrowed,
api-no-rule-definednarrowed to markdown. Tracking: keyword-rosetta#59.🤖 Generated with Claude Code