Repository navigation
Fix #3992: no-JCL batch controller names an undefined <File>DTO - #3994
Merged
Merged
Conversation
A PC-dialect program ASSIGNs its files to literals (`ASSIGN "TEST-FILE"`, `ASSIGN TO "./input.txt"`). The intent reader's SELECT anchor read only a word operand, so files_requested came back empty, the program was classified transactional, and its controller bound `@RequestBody TestFileDTO` -- a class no generator writes -- so the Spring project did not compile. `ASSIGN TO "x"` also backtracked to read the TO keyword as the DD name (`toFile`). - cobol_jcl_forge: the SELECT anchor reads quoted literals and SELECT OPTIONAL, as the engine's own reader (mainframe_boundary._SELECT_ASSIGN) does, and never takes TO as the operand. - api_contract_forge: a non-CICS program with input files is batch even when no SELECT was read (its lineage inputs become the uploads); the transactional branch no longer names a per-file DTO class (it lists the files in a comment); a DD name from a literal is made a legal identifier. - Tests: intent forms, controller output, and an end-to-end no-JCL estate that asserts controllers name only generated classes and that mvn compiles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EC8FWfn3aPmsUPnRgKNVup
Contributor
This was referenced Sep 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3992
Root cause
JCL isn't actually involved.
base_intent.files_requestedcomes fromanalyze_cobol_intent's SELECT/ASSIGN anchor (cobol_jcl_forge._FILE_ASSIGN_ANCHOR), not from JCL. That anchor only read a word operand. So:ASSIGN "TEST-FILE"/ASSIGN "./TEST-FILE"(the form used by GnuCOBOL, opensourcecobol4j and Micro Focus) matched nothing.files_requestedcame back empty, the program was classified transactional, and the controller bound@RequestBody TestFileDTO. No generator ever writes that class, so compilation failed withcannot find symbol.ASSIGN TO "./TEST-FILE"backtracked past the optionalTOand read the keywordTOitself as the DD name. That compiled, but produced a wrong@RequestParam("toFile")and a//TO DDin the zero-trust JCL.The engine's own reader (
mainframe_boundary._SELECT_ASSIGN) already accepts literals andSELECT OPTIONAL, solineage.inputshadTEST-FILEwhilefiles_requestedwas empty.Approach: option (a) plus a general guard
cobol_jcl_forge: the SELECT anchor now reads a quoted literal (bounded to 1024 chars),SELECT OPTIONAL, and never takesTOas the operand. This matches the engine's reader. A non-CICS program doing file I/O is batch, so it gets theMultipartFileupload signature, the same way CardDemo batch programs do.api_contract_forge, as a guard for any SELECT form the intent reader still misses:files_requestedis empty. Its input files become the upload params.<File>DTO. No generator writes a per-file DTO (a CICS program's COMMAREA contract comes from its skeleton viaforges.cics.controller). The inputs are listed in a// Input files: ...comment for the porter. Two@RequestBodyon one method was never valid Spring anyway."01.DAT",KUNDE§NR) is made a legal Java identifier (java_legal_chars+fileprefix if it can't start one). Legal names are unchanged.Why not only option (b)? Keeping the program transactional and dropping the parameter would compile, but it would describe a file-processing batch program as a request/response endpoint and leave the JCL reading
TO. Option (a) is the semantically right classification. The guard means the controller can't name an ungenerated class again, even if the intent reader misses a SELECT.Output impact
java_target_matrix.py --same-as, default config, plain and--scanpaths). None of them uses literal ASSIGN orSELECT OPTIONAL.test_golden_forge.py's golden controller changed. Its mock IR was exactly the Generated REST controller references an undefined <File>DTO for a batch program without JCL: jp-compat still does not compile after #3957 #3992 shape (non-CICS, inputs, no SELECTs) and it codified the two undefined@RequestBody ...DTOparams. It is now the batch upload signature.Estate: opensourcecobol4j jp-compat (
mvn -o compile, JDK 17)cannot find symbol: class TestFileDTO@RequestBody TestFileDTO@RequestParam("toFile")(TO misread)toFile×15,sys01DaDkS*×4testFileFile×28,inputTxtFile×2,nowhereFile×2,sys01DaDkS*×4The zero-trust JCL for the literal-ASSIGN programs now declares
//TESTFILE DDwith the right DISP instead of//TO DD ... NO EXPLICIT OPEN INTENT. The analyze.py findings are unchanged.Tests
tests/cobol_mainframe/test_no_jcl_batch_controller.py:TOliteral, OPTIONAL and word forms, and never reads theTOkeyword as a name.mvn -o compilesucceeds (skipped without Maven + JDK 17 or an offline-resolvable repo).tests/cobol_mainframe+tests/tools_recorders: 1338 passed, 32 skipped.ruff_audit --ci,mypy_audit --ci,dead_key_audit --ci: no new findings.tool_regex_redos.py --ci: 0 offenders.ruff formatis clean on the touched files.Not addressed
cobol_dag_architect._SELECT(the forge lineage used without--scan) has the sameASSIGN TO "x"→TObacktrack. Itscode_viewblanks literal contents, so it can't read the literal name. The controller guard keeps that path compiling.🤖 Generated with Claude Code
https://claude.ai/code/session_01EC8FWfn3aPmsUPnRgKNVup