Repository navigation
Mainframe fact channel: CICS task control and the async task graph (#3449) - #3459
Merged
squid-protocol merged 2 commits intoSep 24, 2026
Merged
squid-protocol merged 2 commits into
squid-protocol merged 2 commits into
Conversation
…3449) Only RUN TRANSID reached call_site_data, as a routing verb whose target never resolved; the async API's join points, START/RETRIEVE data passing and DELAY/POST/WAIT/ENQ were not modelled, so CBSA's credit-agency fan-out/fan-in read as one unconnected child start. New channel cics_task_data: one row per CICS task-control command -- RUN, START, START ATTACH, FETCH CHILD / FETCH ANY, FREE CHILD, RETRIEVE, CANCEL, DELAY, POST, WAIT EVENT / WAIT EXTERNAL / WAITCICS, ENQ, DEQ -- with the TRANSID or RESOURCE target, the CHANNEL, the CHILD / ANY / REQID token, the FROM/INTO record, the timing and the remaining options. Target resolution adds one reading to literal / VALUE / MOVE: a transaction id BUILT by STRING becomes an fnmatch pattern, each source contributing its literal text or its PIC width (`[0-9]` per digit, `?` per character). CRECUST's `STRING 'OCR' ..., WS-CC-CNT (PIC 9) ... INTO WS-RUN-TRANSID` is `OCR[0-9]`: it reaches OCR1..OCR5 and deliberately not OCRA, another transaction in the same deck. A STRING also assigns the name, so it joins any MOVEd literals as candidates rather than losing to a sole MOVE. Spine per how_to_add_a_fact_channel.md: - core/cics_tasks.py: bounded extractor reusing cics_resources' block and option walker; STRING reader bounded by _STRING_LIMIT and the sentence end. - extract_boundary (cobol + pli), galaxyscope payload, record_keeper table + indexes, state_rehydrator byte-identical delta restore, audit block, LLM brief summary and per-file line. - galaxy_ir: EngineCicsTask, EngineFile.cics_tasks, and GalaxyIR.async_tasks(): each RUN/START joined to the CSD transactions and programs it can reach, the containers the parent PUTs on the passed channel, the FETCH ANY / FETCH CHILD / FREE CHILD that collect it (by token), and a START's child RETRIEVEs. CBSA: CRECUST RUN -> OCR1..OCR5 -> CRDTAGY1..5, containers CIPA..CIPI on CIPCREDCHANN, collected by FETCH ANY at line 639. Ground truth: an independent reader in cobol_answer_key.py (add-cics-tasks) with its own STRING/PIC reading and CSD expansion; two new scored fields, "CICS task control" and "async children" (TRUTH_FLAGS cics_tasks_validated, drafted). The engine matches the key exactly: CBSA 24/24 commands and 5/5 children, CardDemo 3/3 (its MQ-triggered RETRIEVEs), zopeneditor none. No START TRANSID exists in any pinned corpus; START is covered by unit tests. Golden masters re-blessed: the only change is a new cics_tasks.json in each fixture (CBSA + genapp COBOL files); no existing golden file moved. dead_key_audit: "CHANNEL" allowlisted -- it is a parsed EXEC CICS option word. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g
… into feat/cics-async-channel-3449
Contributor
This was referenced Sep 24, 2026
squid-protocol
merged commit Sep 24, 2026
2a03edd
into
feat/sql-statement-channel-3446
2 checks passed
squid-protocol
added a commit
that referenced
this pull request
Sep 24, 2026
* Mainframe fact channel: embedded SQL table access (#3446) sql_table_data (#3344) held DB2 table SHAPES; nothing said which programs use which table, or how. New channel sql_statement_data: every embedded SQL statement (EXEC SQL ... END-EXEC in COBOL, ... ; in PL/I), one row per (statement, table), with the verb, access (read / insert / update / delete / merge / lock), cursor and host variables. A statement naming no table (OPEN / FETCH / CLOSE, COMMIT, CALL) keeps one row, so the cursor lifecycle and unit-of-work points survive. INCLUDE, DECLARE ... TABLE and WHENEVER are not statements; dynamic SQL names no table. Spine per how_to_add_a_fact_channel.md: - core/db2_sql_statements.py: bounded extractor reusing db2_declare_table's sequence-field, literal and comment helpers. - Wired through extract_boundary, galaxyscope, record_keeper (+ indexes), state_rehydrator (byte-identical delta restore) and the audit block and LLM brief. - galaxy_ir: EngineSqlStatement, EngineFile.sql_statements, and the join GalaxyIR.sql_table_access(), a program x table matrix where OPEN / FETCH reach the cursor's DECLAREd SELECT. Ground truth: an independent token-walk reader in cobol_answer_key.py (add-sql-access), a new "DB2 table access" field (TRUTH_FLAGS sql_access_validated, drafted), and every key drafted. The engine matches the independent reader exactly: CardDemo 13/13, CBSA 24/24 (zopeneditor has no SQL). Every non-comment EXEC SQL in the corpora is accounted for. Golden masters re-blessed: 23 differences, all new `SQL Statements` blocks on COBOL files, no other movement. keyword-rosetta identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g * test_galaxy_ir: drop redundant local shutil/sqlite3 imports (CodeQL) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g * Mainframe fact channel: CICS task control and the async task graph (#3449) (#3459) Only RUN TRANSID reached call_site_data, as a routing verb whose target never resolved; the async API's join points, START/RETRIEVE data passing and DELAY/POST/WAIT/ENQ were not modelled, so CBSA's credit-agency fan-out/fan-in read as one unconnected child start. New channel cics_task_data: one row per CICS task-control command -- RUN, START, START ATTACH, FETCH CHILD / FETCH ANY, FREE CHILD, RETRIEVE, CANCEL, DELAY, POST, WAIT EVENT / WAIT EXTERNAL / WAITCICS, ENQ, DEQ -- with the TRANSID or RESOURCE target, the CHANNEL, the CHILD / ANY / REQID token, the FROM/INTO record, the timing and the remaining options. Target resolution adds one reading to literal / VALUE / MOVE: a transaction id BUILT by STRING becomes an fnmatch pattern, each source contributing its literal text or its PIC width (`[0-9]` per digit, `?` per character). CRECUST's `STRING 'OCR' ..., WS-CC-CNT (PIC 9) ... INTO WS-RUN-TRANSID` is `OCR[0-9]`: it reaches OCR1..OCR5 and deliberately not OCRA, another transaction in the same deck. A STRING also assigns the name, so it joins any MOVEd literals as candidates rather than losing to a sole MOVE. Spine per how_to_add_a_fact_channel.md: - core/cics_tasks.py: bounded extractor reusing cics_resources' block and option walker; STRING reader bounded by _STRING_LIMIT and the sentence end. - extract_boundary (cobol + pli), galaxyscope payload, record_keeper table + indexes, state_rehydrator byte-identical delta restore, audit block, LLM brief summary and per-file line. - galaxy_ir: EngineCicsTask, EngineFile.cics_tasks, and GalaxyIR.async_tasks(): each RUN/START joined to the CSD transactions and programs it can reach, the containers the parent PUTs on the passed channel, the FETCH ANY / FETCH CHILD / FREE CHILD that collect it (by token), and a START's child RETRIEVEs. CBSA: CRECUST RUN -> OCR1..OCR5 -> CRDTAGY1..5, containers CIPA..CIPI on CIPCREDCHANN, collected by FETCH ANY at line 639. Ground truth: an independent reader in cobol_answer_key.py (add-cics-tasks) with its own STRING/PIC reading and CSD expansion; two new scored fields, "CICS task control" and "async children" (TRUTH_FLAGS cics_tasks_validated, drafted). The engine matches the key exactly: CBSA 24/24 commands and 5/5 children, CardDemo 3/3 (its MQ-triggered RETRIEVEs), zopeneditor none. No START TRANSID exists in any pinned corpus; START is covered by unit tests. Golden masters re-blessed: the only change is a new cics_tasks.json in each fixture (CBSA + genapp COBOL files); no existing golden file moved. dead_key_audit: "CHANNEL" allowlisted -- it is a parsed EXEC CICS option word. Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * db2_sql_statements: build long regexes from named pieces (X-Ray entropy) The X-Ray entropy scan flagged three long regex literals. Build them from named parts (_S, _ALIAS_STOP, _FETCH_ORIENTATION, _HOST_NAME) instead; every compiled pattern is byte-identical to before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
squid-protocol
added a commit
that referenced
this pull request
Sep 24, 2026
…3448) (#3460) * Mainframe fact channel: embedded SQL table access (#3446) sql_table_data (#3344) held DB2 table SHAPES; nothing said which programs use which table, or how. New channel sql_statement_data: every embedded SQL statement (EXEC SQL ... END-EXEC in COBOL, ... ; in PL/I), one row per (statement, table), with the verb, access (read / insert / update / delete / merge / lock), cursor and host variables. A statement naming no table (OPEN / FETCH / CLOSE, COMMIT, CALL) keeps one row, so the cursor lifecycle and unit-of-work points survive. INCLUDE, DECLARE ... TABLE and WHENEVER are not statements; dynamic SQL names no table. Spine per how_to_add_a_fact_channel.md: - core/db2_sql_statements.py: bounded extractor reusing db2_declare_table's sequence-field, literal and comment helpers. - Wired through extract_boundary, galaxyscope, record_keeper (+ indexes), state_rehydrator (byte-identical delta restore) and the audit block and LLM brief. - galaxy_ir: EngineSqlStatement, EngineFile.sql_statements, and the join GalaxyIR.sql_table_access(), a program x table matrix where OPEN / FETCH reach the cursor's DECLAREd SELECT. Ground truth: an independent token-walk reader in cobol_answer_key.py (add-sql-access), a new "DB2 table access" field (TRUTH_FLAGS sql_access_validated, drafted), and every key drafted. The engine matches the independent reader exactly: CardDemo 13/13, CBSA 24/24 (zopeneditor has no SQL). Every non-comment EXEC SQL in the corpora is accounted for. Golden masters re-blessed: 23 differences, all new `SQL Statements` blocks on COBOL files, no other movement. keyword-rosetta identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g * test_galaxy_ir: drop redundant local shutil/sqlite3 imports (CodeQL) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g * Mainframe fact channel: CICS task control and the async task graph (#3449) Only RUN TRANSID reached call_site_data, as a routing verb whose target never resolved; the async API's join points, START/RETRIEVE data passing and DELAY/POST/WAIT/ENQ were not modelled, so CBSA's credit-agency fan-out/fan-in read as one unconnected child start. New channel cics_task_data: one row per CICS task-control command -- RUN, START, START ATTACH, FETCH CHILD / FETCH ANY, FREE CHILD, RETRIEVE, CANCEL, DELAY, POST, WAIT EVENT / WAIT EXTERNAL / WAITCICS, ENQ, DEQ -- with the TRANSID or RESOURCE target, the CHANNEL, the CHILD / ANY / REQID token, the FROM/INTO record, the timing and the remaining options. Target resolution adds one reading to literal / VALUE / MOVE: a transaction id BUILT by STRING becomes an fnmatch pattern, each source contributing its literal text or its PIC width (`[0-9]` per digit, `?` per character). CRECUST's `STRING 'OCR' ..., WS-CC-CNT (PIC 9) ... INTO WS-RUN-TRANSID` is `OCR[0-9]`: it reaches OCR1..OCR5 and deliberately not OCRA, another transaction in the same deck. A STRING also assigns the name, so it joins any MOVEd literals as candidates rather than losing to a sole MOVE. Spine per how_to_add_a_fact_channel.md: - core/cics_tasks.py: bounded extractor reusing cics_resources' block and option walker; STRING reader bounded by _STRING_LIMIT and the sentence end. - extract_boundary (cobol + pli), galaxyscope payload, record_keeper table + indexes, state_rehydrator byte-identical delta restore, audit block, LLM brief summary and per-file line. - galaxy_ir: EngineCicsTask, EngineFile.cics_tasks, and GalaxyIR.async_tasks(): each RUN/START joined to the CSD transactions and programs it can reach, the containers the parent PUTs on the passed channel, the FETCH ANY / FETCH CHILD / FREE CHILD that collect it (by token), and a START's child RETRIEVEs. CBSA: CRECUST RUN -> OCR1..OCR5 -> CRDTAGY1..5, containers CIPA..CIPI on CIPCREDCHANN, collected by FETCH ANY at line 639. Ground truth: an independent reader in cobol_answer_key.py (add-cics-tasks) with its own STRING/PIC reading and CSD expansion; two new scored fields, "CICS task control" and "async children" (TRUTH_FLAGS cics_tasks_validated, drafted). The engine matches the key exactly: CBSA 24/24 commands and 5/5 children, CardDemo 3/3 (its MQ-triggered RETRIEVEs), zopeneditor none. No START TRANSID exists in any pinned corpus; START is covered by unit tests. Golden masters re-blessed: the only change is a new cics_tasks.json in each fixture (CBSA + genapp COBOL files); no existing golden file moved. dead_key_audit: "CHANNEL" allowlisted -- it is a parsed EXEC CICS option word. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g * Mainframe fact channel: job submission through the internal reader (#3448) The engine recorded both halves of an online->batch submission -- the CICS WRITEQ TD (cics_resource_data) and the extrapartition TDQUEUE (csd_resource_data) -- but not the edge "transaction X submits job Y", and nothing of the batch case, a step whose DD is SYSOUT=(A,INTRDR). New channel job_submit_data (core/job_submits.py): - COBOL: the JCL cards a program holds as literals -- `//NAME JOB` (the job name) and `//STEP EXEC PROC=|PGM=|P` -- kept only when a JOB card is among them, so a DISPLAY '//...' is never JCL. One bounded literal regex, shielded. - JCL: every DD routed to the internal reader, with the step's SYSUT1 DSN (what IEBGENER copies there), read from the existing _jcl_statements parse. galaxy_ir: EngineJobSubmit, EngineFile.job_submits, and GalaxyIR.job_submissions(): - online (`tdq`): WRITEQ TD to an extrapartition TDQUEUE, when some JCL routes its DDNAME to SYSOUT=(x,INTRDR) (`region_jcl`) or the writer embeds a job card (`job_card`); with the transactions that enter the writer, the job names and each EXEC target resolved to its JCL member (a PROC prefers the procedure member: TRANREPT.prc over TRANREPT.jcl). - batch (`intrdr_dd`): the SYSUT1 library member resolved to its JCL file. CardDemo: CR00 -> CORPT00C -> TDQ JOBS (INREADER) -> job TRNRPT00 -> PROC TRANREPT = app/proc/TRANREPT.prc; INTRDRJ1 -> INTRDRJ2. Ground truth: an independent join in cobol_answer_key.py (add-job-submissions) with its own line-by-line JCL read, job-card scan and CSD / WRITEQ readers; new scored field "job submissions" (TRUTH_FLAGS submissions_validated, drafted). Engine matches the key exactly: CardDemo 3/3; CBSA and zopeneditor submit nothing. Golden masters re-blessed: one new Job Submission block (CORPT00C), nothing else moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g * Mainframe fact channel: CICS task control and the async task graph (#3449) (#3459) Only RUN TRANSID reached call_site_data, as a routing verb whose target never resolved; the async API's join points, START/RETRIEVE data passing and DELAY/POST/WAIT/ENQ were not modelled, so CBSA's credit-agency fan-out/fan-in read as one unconnected child start. New channel cics_task_data: one row per CICS task-control command -- RUN, START, START ATTACH, FETCH CHILD / FETCH ANY, FREE CHILD, RETRIEVE, CANCEL, DELAY, POST, WAIT EVENT / WAIT EXTERNAL / WAITCICS, ENQ, DEQ -- with the TRANSID or RESOURCE target, the CHANNEL, the CHILD / ANY / REQID token, the FROM/INTO record, the timing and the remaining options. Target resolution adds one reading to literal / VALUE / MOVE: a transaction id BUILT by STRING becomes an fnmatch pattern, each source contributing its literal text or its PIC width (`[0-9]` per digit, `?` per character). CRECUST's `STRING 'OCR' ..., WS-CC-CNT (PIC 9) ... INTO WS-RUN-TRANSID` is `OCR[0-9]`: it reaches OCR1..OCR5 and deliberately not OCRA, another transaction in the same deck. A STRING also assigns the name, so it joins any MOVEd literals as candidates rather than losing to a sole MOVE. Spine per how_to_add_a_fact_channel.md: - core/cics_tasks.py: bounded extractor reusing cics_resources' block and option walker; STRING reader bounded by _STRING_LIMIT and the sentence end. - extract_boundary (cobol + pli), galaxyscope payload, record_keeper table + indexes, state_rehydrator byte-identical delta restore, audit block, LLM brief summary and per-file line. - galaxy_ir: EngineCicsTask, EngineFile.cics_tasks, and GalaxyIR.async_tasks(): each RUN/START joined to the CSD transactions and programs it can reach, the containers the parent PUTs on the passed channel, the FETCH ANY / FETCH CHILD / FREE CHILD that collect it (by token), and a START's child RETRIEVEs. CBSA: CRECUST RUN -> OCR1..OCR5 -> CRDTAGY1..5, containers CIPA..CIPI on CIPCREDCHANN, collected by FETCH ANY at line 639. Ground truth: an independent reader in cobol_answer_key.py (add-cics-tasks) with its own STRING/PIC reading and CSD expansion; two new scored fields, "CICS task control" and "async children" (TRUTH_FLAGS cics_tasks_validated, drafted). The engine matches the key exactly: CBSA 24/24 commands and 5/5 children, CardDemo 3/3 (its MQ-triggered RETRIEVEs), zopeneditor none. No START TRANSID exists in any pinned corpus; START is covered by unit tests. Golden masters re-blessed: the only change is a new cics_tasks.json in each fixture (CBSA + genapp COBOL files); no existing golden file moved. dead_key_audit: "CHANNEL" allowlisted -- it is a parsed EXEC CICS option word. Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Mainframe fact channel: IBM MQ calls -- queues, direction, handles (#3447) (#3461) CALL 'MQOPEN' / 'MQPUT' / 'MQGET' reached call_site_data as external calls only; nothing said which program puts to or gets from which queue. New channel mq_call_data (core/mq_calls.py): one row per MQI call with the verb, direction (MQOO-* open options; PUT put, GET get), the queue, the handle and the option words in effect. - The queue of an MQOPEN / MQPUT1 is the operand last MOVEd to its descriptor's OBJECTNAME (qualified `OF <od>` or not), read as a literal / VALUE / MOVEd literals, following name-to-name MOVEs (depth 3). Two runtime sources are named, never guessed: `trigger` (MQTM-QNAME, the queue whose trigger started the transaction) and `reply_to` (MQMD-REPLYTOQ). - A PUT / GET / CLOSE is matched to its MQOPEN by handle: the one it passes, or the one MOVEd into its handle operand just before it, with the copies an open's handle gets before the next MQ call (`MOVE MQ-HOBJ TO INPUT-QUEUE-HANDLE`) -- so CardDemo's shared MQ-HOBJ still resolves. - Fixed-format sequence fields are blanked first: in numbered source the cols 73-80 tag used to end a CALL's operand list. The ground-truth ledger caught this on the real scan (COACCT01/CODATE01 4/22 -> 22/22). Spine per how_to_add_a_fact_channel.md: extract_boundary (cobol), payload, record_keeper table + indexes, byte-identical delta restore, audit block, LLM per-file queue line; galaxy_ir EngineMqCall / EngineFile.mq_calls, GalaxyIR.mq_queues (per-program endpoints, runtime queues named) and mq_flows (producer -> consumer through a named queue). Ground truth: an independent token-walk reader (add-mq) with its own MOVE, COMPUTE and handle tracking; new scored field "MQ calls" (mq_validated, drafted). Engine matches the key exactly: CardDemo 22/22; CBSA and zopeneditor make no MQ calls. CardDemo's MQ programs are request/reply services whose requesters are outside the repo, so no in-repo producer->consumer pair exists. Golden masters unchanged (no MQ program in the crucible corpus). Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * db2_sql_statements: build long regexes from named pieces (X-Ray entropy) The X-Ray entropy scan flagged three long regex literals. Build them from named parts (_S, _ALIAS_STOP, _FETCH_ORIENTATION, _HOST_NAME) instead; every compiled pattern is byte-identical to before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g * job_submits: build the JCL card regex from a named piece (X-Ray entropy) Same fix as db2_sql_statements in #3458: the compiled pattern is byte-identical; the literal no longer reads as a dense string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
5 tasks
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.
Closes #3449. Part of #3445. Stacked on #3458 (base is its branch; GitHub retargets to
mainwhen #3458 merges).What
New fact channel
cics_task_data: one row for each CICS task-control command.RUN,START,START ATTACH,FETCH CHILD,FETCH ANY,FREE CHILD,RETRIEVE,CANCEL,DELAY,POST,WAIT EVENT,WAIT EXTERNAL,WAITCICS,ENQandDEQ.A new join,
GalaxyIR.async_tasks(), connects each RUN or START to:The dynamic-transid part
CBSA's
CRECUSTbuilds its child transaction id at run time:Resolution adds one reading after literal, VALUE and MOVE: a STRING-built id becomes an fnmatch pattern.
[0-9]for each digit,?for each character.OCR[0-9]. It reaches OCR1..OCR5, and deliberately notOCRA, a different transaction in the same deck. A naiveOCR*pattern would have matched it.Result on CBSA:
CRECUSTRUNs OCR1..OCR5, which reach CRDTAGY1..5 (all resolved to files). It passes containers CIPA..CIPI onCIPCREDCHANN, andFETCH ANYat line 639 collects the children.Ground truth
cobol_answer_key.py add-cics-tasks, with its own STRING/PIC reading and its own CSD expansion.CICS task controlandasync children. Both are drafted, with sign-off flagcics_tasks_validated.The engine matches the key exactly:
RETRIEVE INTO(MQTM))No pinned corpus contains a
START TRANSID, so START / CANCEL / POST / WAIT are covered by unit tests only. A blind census of the new section is still owed beforecics_tasks_validatedcan be set.Checks
cics_tasks.jsonin each fixture (CBSA and genapp COBOL files); no existing golden file moved."CHANNEL"is allowlisted, because it's an EXEC CICS option word parsed from source.🤖 Generated with Claude Code
https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g