Skip to content

LINK / XCTL / CALL -> service-to-service calls; CSD decks are not program declarers (#3616) - #3640

Merged
squid-protocol merged 3 commits into
mainfrom
feat/calls-services-3616
Sep 25, 2026
Merged

squid-protocol merged 3 commits into
mainfrom
feat/calls-services-3616

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

Closes #3616 (epic #3625). It builds on #3615: every call becomes a call to the target's handleLink / handleCall.

What each call becomes

fact (skeleton) generated in the caller's @Service
resolved EXEC CICS LINK / XCTL (calls) link<T>(req) / xctl<T>(req) → tService.getObject().handleLink(req), typed by T's COMMAREA DTO
resolved CALL 'T' USING a b (calls + T's interface.parameters) call<T>(A a, B b) → handleCall(a, b). T gains handleCall, typed by its PROCEDURE DIVISION USING items: an elementary item maps to its Java type, a group to a DTO
data-driven XCTL PROGRAM(WS-X) / CALL WS-X (dynamic_call_targets) dispatch<WsX>L<line>(String program, ...): a switch over the candidates the engine found (VALUE, table, MOVEd literals). Any other name throws, naming the site
LINK the CSD routes to another region (remote_calls: REMOTESYSTEM / SYSID) with integration.remote_calls: http (new, default), a <Region>RemoteClient (RestTemplate, gitgalaxy.remote.<region>.url) posting to that program's /link; with local, the in-process bean
  • Cycle-safe injection. Targets are injected as ObjectProvider<TService>. CICS screens XCTL to each other in cycles (menu ↔ detail), which plain constructor injection cannot start.
  • Honest types. When a site passes a record other than the one the target was resolved to receive, the method or case carries // TODO: this site passes X; T receives Y (file) -- map one layout onto the other. The generator never casts silently.
  • Traceability. Every method names its call sites (file:line) and the field-testing status of the facts behind it.
  • DTOs. Program-contract DTOs move from dto.cics to dto.contract, since they now hold CALL USING records too. A program's own record is named after the program that declares it (MenuWsComm), whichever program receives it.

Example: CardDemo's menu option table:

    /** XCTL PROGRAM(CDEMO-MENU-OPT-PGMNAME) at app/cbl/COMEN01C.cbl:156: the target is data-driven. Candidates: COACTUPC (table), COACTVWC (table), ... */
    public Object dispatchCdemoMenuOptPgmnameL156(String program, Object request) {
        switch (program.trim().toUpperCase()) {
            case "COACTUPC":
                // TODO: this site passes CARDDEMO-COMMAREA; COACTUPC receives WS-COMMAREA (app/cbl/COACTUPC.cbl) -- map one layout onto the other
                return coactupcService.getObject().handleLink((CoactupcWsCommarea) request);

And GENAPP's DPL:

    /** EXEC CICS LINK PROGRAM(LGACVS01) at base/src/lgacdb01.cbl:174: the CSD routes it to region DOR1 (distributed program link). */
    public Lgacvs01Dfhcommarea remoteLgacvs01L174(Lgacvs01Dfhcommarea request) {
        return dor1RemoteClient.linkLgacvs01(request);
    }
corpus LINK XCTL CALL data-driven dispatch remote (clients)
CardDemo 0 2 3 32 0
CBSA 16 0 0 124 0
GENAPP 20 0 0 13 35 (DOR1, AOR1)
zECS 0 0 0 3 0
zOE 0 0 0 3 0
DSF 0 0 0 0 0 (its CALLs reach PL/I / assembler)

Engine defect found and fixed (field-testing log D022)

CSD, BMS, JCL and DDL files carry class_data names that are not programs: a CSD deck's DEFINE PROGRAM(...), a mapset, a job name, a table. Two lookups treated them as declarers:

  • dynamic_call_targets made the CSD deck the file of every program it DEFINEs: 88 of 89 CardDemo candidates resolved to CARDDEMO.CSD.
  • _program_file saw two declarers for each program and answered None, which quietly weakened the channel-handoff joins.

All program-ID indexes now consider executable declarers only. When a program is declared twice, the lookup takes the declarer nearest the caller (zOE: COBOL/SAM1 → COBOL/SAM2, not multiroot/sam/SAM2) and answers None on a tie.

Blast radius, diffing every IR join on the 6 corpora (main vs this PR):

  • dynamic_call_targets and navigation change on CardDemo, zECS (ZECS002 exists only as a CSD definition: now None, correctly) and zOE.
  • Nothing else changes.

The ledger is unchanged because the answer key compares candidate names, not their files. So this is logged as an attribute defect: it does not reset dynamic call targets.

Verified

  • Compile: all 6 corpora × 13 configs compile via java_target_matrix.py --scan, with JDK 17/21, Maven and Gradle; CI runs both paths.
  • Snapshot: refraction_snapshot.py check shows 0 differ on 6 corpora.
  • Suite: 11,578 passed, including the 521 mainframe tests run with the pinned corpora; the lint and dead-key audits are clean.
  • New tests (test_service_calls.py, a real scan): the CSD is no longer a declarer; the nearest-declarer rule and its tie; USING parameters; static LINK / CALL, data-driven dispatch with the mismatch TODO, and the remote client; local mode and plain constructors; config validation.

Not in this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g

squid-protocol and others added 2 commits September 25, 2026 13:27
…gram declarers (#3616)

Generator (cobol_to_java_call_forge.py). From the verified skeleton, each
program's @service gains:
- link<T> / xctl<T> for a resolved LINK / XCTL, calling T's handleLink
  (the #3615 contract);
- call<T>(...) for a resolved CALL, typed by T's PROCEDURE DIVISION USING
  items, calling T's new handleCall;
- dispatch<Operand>L<line>(String program, ...) for a data-driven site: a
  switch over the candidates the engine found; any other name throws;
- for a LINK the CSD routes to another region (REMOTESYSTEM / SYSID), a
  call through a <Region>RemoteClient (RestTemplate, the URL a property).
  New config `integration.remote_calls: http | local` (default http).

Targets are injected as ObjectProvider<...>: CICS screens XCTL to each
other in cycles, which plain constructor injection cannot start. When a
site passes a record other than the one the target receives, a TODO says
so. The program-contract DTOs move to dto.contract, named after the
declaring program. /link now also counts data-driven LINK / XCTL arriving
through navigation.

Engine (galaxy_ir). CSD, BMS, JCL and DDL files carry class_data names
that are not programs. dynamic_call_targets indexed them, so the CSD deck
became the file of every program it DEFINEs: 88 of 89 CardDemo candidates
resolved to CARDDEMO.CSD. And _program_file saw two declarers and answered
None. All program-ID indexes now use executable declarers only. A program
declared twice resolves to the declarer nearest the caller (zOE: COBOL/
SAM1 -> COBOL/SAM2), or None on a tie.

program_interfaces() also returns each program's USING parameters with
their layouts.

Verification:
- 6 corpora x 13 configs compile via --scan.
- The refraction snapshot shows 0 differ.
- 521 mainframe tests pass with the corpora (ledger unchanged: the key
  compares candidate names, not their files).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g
An engine attribute defect on CardDemo, found by the Java generator and
fixed in this PR. It does not reset `dynamic call targets`: the keyed
candidate names were right, the resolved file was not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g
@github-actions

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

_mismatch binds the target's COMMAREA once, and merge_extras keeps
its filtered parts in a list[dict] instead of reassigning the Optional
parameter tuple. No behavior change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ZsVaAkb86P5r5JXDC2Y9g
@squid-protocol
squid-protocol merged commit 84c36b9 into main Sep 25, 2026
36 checks passed
@squid-protocol
squid-protocol deleted the feat/calls-services-3616 branch September 25, 2026 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Java conversion: LINK / XCTL / CALL targets (incl. data-driven and remote SYSID) -> service-to-service calls

1 participant