Program Logic Manual — CBTRN03C

Gold Standard PLM (v3 hybrid: L0 spine + unified-STB grounded). Archetype: batch_report. Program kind: batch.


s01 — Program Narrative

Purpose

CBTRN03C is a batch COBOL program whose stated function is to "Print the transaction detail report" (per the source header comment block, L2–L5). It reads a date-filtered, card-sorted daily transaction file, enriches each transaction with descriptive lookups (card-account cross-reference, transaction type, transaction category), and writes a paginated Daily Transaction Report (REPT-LONG-NAME VALUE 'Daily Transaction Report', L178–L179) to a sequential report dataset. The report carries page headers, per-transaction detail lines, per-card account subtotals, per-page subtotals, and a grand total (per STB data_division.working_storage.fields[]; report line records REPORT-NAME-HEADER, TRANSACTION-DETAIL-REPORT, REPORT-PAGE-TOTALS, REPORT-ACCOUNT-TOTALS, REPORT-GRAND-TOTALS, L175–L237).

The program is classified batch_report and its lineage tier is arithmetic (per STB metrics / spine header), reflecting that its principal computed logic is the additive roll-up of transaction amounts into page, account, and grand totals.

Invocation / Run Cadence

CBTRN03C runs as a batch job step under JCL job TRANREPT, step STEP10R (per STB jcl_facts.tier1_core.invocation; the JCL deck is jcl/TRANREPT.jcl, per spine INVOCATION_CONTEXT). It is the terminal (third) step of a three-step pipeline (per jcl_facts.tier2_enhanced.step_sequence):

  1. STEP05R.PRC001 — IDCAMS (transaction VSAM → sequential backup)
  2. STEP05R — SORT (backup → date-filtered, card-sorted daily file)
  3. STEP10RCBTRN03C (this program)

A key operational fact: the upstream SORT step (STEP05R) applies a DFSORT INCLUDE COND that pre-filters the transaction file to records whose processing date lies between the start and end parameter dates, and sorts ascending by card number. The raw SORT control statement (from jcl_facts.tier1_core.sort_specifications.raw) is:

      SORT FIELDS=(TRAN-CARD-NUM,A)
 INCLUDE COND=(TRAN-PROC-DT,GE,PARM-START-DATE,AND,
         TRAN-PROC-DT,LE,PARM-END-DATE)

    

The sort key is the card-number field and the filter bounds the processing-date field to the parameter date window (these are DFSORT symbolic field names, not COBOL entities). This means the input reaching CBTRN03C is already date-bounded and card-ordered — context that matters for the in-program date check and control-break logic discussed in s05 and s11.

I/O Summary

CBTRN03C touches 6 files — 5 read (INPUT) and 1 written (OUTPUT) (per spine DATA_FLOW FILE ROLE COUNTS, counted by data direction):

File (FD) Assign / DD Organization Direction Record area
TRANSACT-FILE TRANFILE SEQUENTIAL input (primary driver) TRAN-RECORD
XREF-FILE CARDXREF INDEXED, RANDOM input (lookup) CARD-XREF-RECORD
TRANTYPE-FILE TRANTYPE INDEXED, RANDOM input (lookup) TRAN-TYPE-RECORD
TRANCATG-FILE TRANCATG INDEXED, RANDOM input (lookup) TRAN-CAT-RECORD
DATE-PARMS-FILE DATEPARM SEQUENTIAL input (parameter) WS-DATEPARM-RECORD
REPORT-FILE TRANREPT SEQUENTIAL output (report) FD-REPTFILE-REC

The SELECT/FILE-CONTROL declarations are at L29–L57; the FD record areas at L61–L88 (per STB environment_division / data_division.file_descriptions). The primary input TRANSACT-FILE is read sequentially in the main loop; the three VSAM KSDS files (XREF-FILE, TRANTYPE-FILE, TRANCATG-FILE) are read RANDOM by key for per-transaction enrichment; DATE-PARMS-FILE is read once for the reporting date window; REPORT-FILE receives every report line via WRITE FD-REPTFILE-REC (L477).


s02 — System-Level Context

JCL Context

CBTRN03C is invoked by job TRANREPT, step STEP10R, executing PGM=CBTRN03C (per jcl_facts.tier1_core.invocation). Job-level attributes: MSGCLASS=0, NOTIFY=&SYSUID, JCLLIB ORDER=(AWS.M2.CARDDEMO.PROC). No step PARM is passed (invocation.parm = null) — the reporting date window is supplied through the DATEPARM dataset rather than a PARM string.

DD statements for STEP10R (per jcl_facts.tier1_core.dd_mappings):

DD Dataset DISP Type Notes
STEPLIB AWS.M2.CARDDEMO.LOADLIB SHR Sequential load library
TRANFILE AWS.M2.CARDDEMO.TRANSACT.DALY(+1) SHR Sequential (GDG) primary input, fed by STEP05R SORTOUT
CARDXREF AWS.M2.CARDDEMO.CARDXREF.VSAM.KSDS SHR VSAM card cross-reference lookup
TRANTYPE AWS.M2.CARDDEMO.TRANTYPE.VSAM.KSDS SHR VSAM transaction-type lookup
TRANCATG AWS.M2.CARDDEMO.TRANCATG.VSAM.KSDS SHR VSAM transaction-category lookup
DATEPARM AWS.M2.CARDDEMO.DATEPARM SHR Sequential reporting date parameters
TRANREPT AWS.M2.CARDDEMO.TRANREPT(+1) NEW,CATLG,DELETE Sequential (GDG) report output; LRECL=133, RECFM=FB, SPACE=(CYL,(1,1),RLSE), UNIT=SYSDA
SYSOUT / SYSPRINT (SYSOUT=*) system output

The report output TRANREPT(+1) is a new generation-data-group dataset catalogued on normal completion and deleted on abnormal completion (DISP=(NEW,CATLG,DELETE)), with fixed-block 133-byte records — consistent with the 133-byte report record FD-REPTFILE-REC (L85).


s03 — Data Dictionary

File Section Records (byte-precise layouts)

The following record layouts are transcribed verbatim from the deterministic spine RECORD_BYTE_LAYOUT block (OCCURS already expanded, USAGE packing already applied; offsets are 0-based within the 01-record). These are the authoritative byte layouts for the persisted / read-into records.

TRAN-RECORD (350 bytes) — copybook CVTRA05Y, read area for TRANSACT-FILE

Field PIC Offset Bytes Dir
TRAN-RECORD 0 350 unused
TRAN-ID X(16) 0 16 in
TRAN-TYPE-CD X(02) 16 2 in
TRAN-CAT-CD 9(04) 18 4 in
TRAN-SOURCE X(10) 22 10 in
TRAN-DESC X(100) 32 100 unused
TRAN-AMT S9(09)V99 132 11 in
TRAN-MERCHANT-ID 9(09) 143 9 unused
TRAN-MERCHANT-NAME X(50) 152 50 unused
TRAN-MERCHANT-CITY X(50) 202 50 unused
TRAN-MERCHANT-ZIP X(10) 252 10 unused
TRAN-CARD-NUM X(16) 262 16 in
TRAN-ORIG-TS X(26) 278 26 unused
TRAN-PROC-TS X(26) 304 26 in
FILLER X(20) 330 20 unused

CARD-XREF-RECORD (50 bytes) — copybook CVACT03Y, read area for XREF-FILE

Field PIC Offset Bytes Dir
CARD-XREF-RECORD 0 50 unused
XREF-CARD-NUM X(16) 0 16 unused
XREF-CUST-ID 9(09) 16 9 unused
XREF-ACCT-ID 9(11) 25 11 in
FILLER X(14) 36 14 unused

TRAN-TYPE-RECORD (60 bytes) — copybook CVTRA03Y, read area for TRANTYPE-FILE

Field PIC Offset Bytes Dir
TRAN-TYPE-RECORD 0 60 unused
TRAN-TYPE X(02) 0 2 unused
TRAN-TYPE-DESC X(50) 2 50 in
FILLER X(08) 52 8 unused

TRAN-CAT-RECORD (60 bytes) — copybook CVTRA04Y, read area for TRANCATG-FILE

Field PIC Offset Bytes Dir
TRAN-CAT-RECORD 0 60 unused
TRAN-CAT-KEY 0 6 unused
TRAN-TYPE-CD X(02) 0 2 in
TRAN-CAT-CD 9(04) 2 4 in
TRAN-CAT-TYPE-DESC X(50) 6 50 in
FILLER X(04) 56 4 unused

WS-DATEPARM-RECORD (21 bytes) — read area for DATE-PARMS-FILE

Field PIC Offset Bytes Dir
WS-DATEPARM-RECORD 0 21 unused
WS-START-DATE X(10) 0 10 in
FILLER X(01) 10 1 unused
WS-END-DATE X(10) 11 10 in

The remaining FD record areas are fixed byte strings: FD-REPTFILE-REC PIC X(133) (L85, the report line) and FD-DATEPARM-REC PIC X(80) (L88). The VSAM key fields declared in FILE-CONTROL are FD-XREF-CARD-NUM (L36), FD-TRAN-TYPE (L42), and FD-TRAN-CAT-KEY (L48).

Working-Storage Key Areas

01-level group Role Notable fields (L)
WS-DATEPARM-RECORD Reporting date window WS-START-DATE, WS-END-DATE (L254–L257)
WS-REPORT-VARS Report state + accumulators WS-FIRST-TIME VALUE 'Y', WS-LINE-COUNTER COMP-3 VALUE 0, WS-PAGE-SIZE COMP-3 VALUE 20, WS-PAGE-TOTAL / WS-ACCOUNT-TOTAL / WS-GRAND-TOTAL S9(09)V99 VALUE 0, WS-CURR-CARD-NUM VALUE SPACES (L259–L269)
APPL-RESULT I/O result code (S9(9) COMP) 88 APPL-AOK VALUE 0; 88 APPL-EOF VALUE 16 (L282–L284)
END-OF-FILE Loop sentinel (X(01) VALUE 'N') drives PERFORM UNTIL (L286)
IO-STATUS, IO-STATUS-04, TWO-BYTES-BINARY File-status display formatting used by 9910-DISPLAY-IO-STATUS (L271–L280)
ABCODE, TIMING Abend parameters (S9(9) BINARY) passed to CEE3ABD (L287–L288)
Report line records Report images REPORT-NAME-HEADER, TRANSACTION-DETAIL-REPORT, TRANSACTION-HEADER-1, TRANSACTION-HEADER-2, REPORT-PAGE-TOTALS, REPORT-ACCOUNT-TOTALS, REPORT-GRAND-TOTALS (L175–L237)

Six file-status two-byte groups back the six files: TRANFILE-STATUS, CARDXREF-STATUS, TRANTYPE-STATUS, TRANCATG-STATUS, TRANREPT-STATUS, DATEPARM-STATUS (per FILE-CONTROL FILE STATUS IS clauses, L31–L57; group definitions L116–L252).

Business Limits (numeric / VALUE-defaulted fields)

Parameter Record (batch PARM)

No JCL PARM string is supplied to STEP10R (jcl_facts.tier1_core.invocation.parm = null). Runtime parameterization is instead by dataset: DATE-PARMS-FILE (DD DATEPARM) is read into WS-DATEPARM-RECORD, populating WS-START-DATE and WS-END-DATE (the 10-byte start date, a 1-byte filler, and the 10-byte end date; L254–L257, read at L353).


s04 — Hierarchical Structure Map

Paragraph Inventory (26 paragraphs)

Total: 26 paragraphs (per STB procedure_division.paragraphs.length). Lines are expanded-source coordinates; end lines are source-derived (source-derived — STB extraction gap: paragraph end line; not in unified STB is not the case here — end_line IS carried at procedure_division.paragraphs[].end_line).

Paragraph Lines Role
(unnamed PROCEDURE DIVISION driver) L291–L349 Main sequence: opens, date read, PERFORM UNTIL loop, closes, GOBACK
0000-TRANFILE-OPEN L508–L525 OPEN INPUT TRANSACT-FILE
0100-REPTFILE-OPEN L526–L543 OPEN OUTPUT REPORT-FILE
0200-CARDXREF-OPEN L544–L561 OPEN INPUT XREF-FILE
0300-TRANTYPE-OPEN L562–L579 OPEN INPUT TRANTYPE-FILE
0400-TRANCATG-OPEN L580–L597 OPEN INPUT TRANCATG-FILE
0500-DATEPARM-OPEN L598–L615 OPEN INPUT DATE-PARMS-FILE
0550-DATEPARM-READ L352–L379 READ date parameters; set EOF or abend
1000-TRANFILE-GET-NEXT L380–L405 READ next transaction; classify status
1100-WRITE-TRANSACTION-REPORT L406–L424 First-time headers, page break, add to totals, write detail
1110-WRITE-PAGE-TOTALS L425–L437 Emit page subtotal; roll page→grand; reset page total
1120-WRITE-ACCOUNT-TOTALS L438–L449 Emit per-card account subtotal; reset account total
1110-WRITE-GRAND-TOTALS L450–L455 Emit grand total
1120-WRITE-HEADERS L456–L474 Emit report name, blank, column headers, rule line
1111-WRITE-REPORT-REC L475–L492 WRITE one report record; check status; abend on error
1120-WRITE-DETAIL L493–L507 Build and write one transaction detail line
1500-A-LOOKUP-XREF L616–L625 RANDOM read XREF-FILE by card number
1500-B-LOOKUP-TRANTYPE L626–L635 RANDOM read TRANTYPE-FILE by type code
1500-C-LOOKUP-TRANCATG L636–L645 RANDOM read TRANCATG-FILE by type+category key
9000-TRANFILE-CLOSE L646–L663 CLOSE TRANSACT-FILE
9100-REPTFILE-CLOSE L664–L682 CLOSE REPORT-FILE
9200-CARDXREF-CLOSE L683–L700 CLOSE XREF-FILE
9300-TRANTYPE-CLOSE L701–L718 CLOSE TRANTYPE-FILE
9400-TRANCATG-CLOSE L719–L736 CLOSE TRANCATG-FILE
9500-DATEPARM-CLOSE L737–L757 CLOSE DATE-PARMS-FILE
9999-ABEND-PROGRAM L758–L764 DISPLAY, set abend code, CALL CEE3ABD
9910-DISPLAY-IO-STATUS L765–L781 Format and DISPLAY file status

Structure Chart (PERFORM hierarchy)

      PROCEDURE DIVISION (L291-L349)
├── 0000-TRANFILE-OPEN
├── 0100-REPTFILE-OPEN
├── 0200-CARDXREF-OPEN
├── 0300-TRANTYPE-OPEN
├── 0400-TRANCATG-OPEN
├── 0500-DATEPARM-OPEN
├── 0550-DATEPARM-READ
│   └── 9910-DISPLAY-IO-STATUS ──► 9999-ABEND-PROGRAM ──► CALL CEE3ABD
├── PERFORM UNTIL END-OF-FILE = 'Y' (L302-L338)
│   ├── 1000-TRANFILE-GET-NEXT
│   ├── 1120-WRITE-ACCOUNT-TOTALS  (on card control break, WS-FIRST-TIME='N')
│   │   └── 1111-WRITE-REPORT-REC
│   ├── 1500-A-LOOKUP-XREF
│   ├── 1500-B-LOOKUP-TRANTYPE
│   ├── 1500-C-LOOKUP-TRANCATG
│   ├── 1100-WRITE-TRANSACTION-REPORT      (per-record path)
│   │   ├── 1120-WRITE-HEADERS ──► 1111-WRITE-REPORT-REC
│   │   ├── 1110-WRITE-PAGE-TOTALS ──► 1111-WRITE-REPORT-REC
│   │   └── 1120-WRITE-DETAIL ──► 1111-WRITE-REPORT-REC
│   ├── 1110-WRITE-PAGE-TOTALS             (EOF close-out path)
│   └── 1110-WRITE-GRAND-TOTALS            (EOF close-out path)
├── 9000-TRANFILE-CLOSE
├── 9100-REPTFILE-CLOSE
├── 9200-CARDXREF-CLOSE
├── 9300-TRANTYPE-CLOSE
├── 9400-TRANCATG-CLOSE
└── 9500-DATEPARM-CLOSE

    

Every I/O and write routine reaches 9910-DISPLAY-IO-STATUS and 9999-ABEND-PROGRAM on an error branch; those two edges are elided from the tree above for readability and detailed in s08.


s05 — Control Flow Logic

Main Logic Walkthrough

The driver (L291–L349) runs a fixed open sequence, reads the date parameters once, then enters the single read loop and finally closes all files:

  1. Six OPEN paragraphs run in order (0000-TRANFILE-OPEN0500-DATEPARM-OPEN, L293–L298), each validating its file status and abending on failure.
  2. 0550-DATEPARM-READ (L300) reads DATE-PARMS-FILE into WS-DATEPARM-RECORD, sets APPL-RESULT from the status via an EVALUATE, and either displays the reporting window (APPL-AOK), sets END-OF-FILE='Y' (APPL-EOF, empty parameter file), or abends (other status).
  3. The primary read loopPERFORM UNTIL END-OF-FILE = 'Y' (L302–L338) is the one loop construct in the program (per spine CONTROL_STRUCTURE_COUNTS: PERFORM UNTIL loops: 1 at L302). Per iteration, guarded by IF END-OF-FILE = 'N' (L303):
  4. The six CLOSE paragraphs run (L340–L345) and the program GOBACKs (L349).

Per the deterministic CLOSEOUT_BRANCH_PERFORMS resolution of the L311 branch: the then (per-record) branch performs 1120-WRITE-ACCOUNT-TOTALS, 1500-A-LOOKUP-XREF, 1500-B-LOOKUP-TRANTYPE, 1500-C-LOOKUP-TRANCATG, and 1100-WRITE-TRANSACTION-REPORT; the else (EOF close-out) branch performs only1110-WRITE-PAGE-TOTALS and 1110-WRITE-GRAND-TOTALS. The account-total emitter is not on the close-out path — see the final-group omission defect below.

NEXT SENTENCE control flow (L309 — effect_class=exit_loop, danger_level=high)

NEXT SENTENCE (L309) exits the surrounding PERFORM UNTIL loop. Per STB procedure_division.control_flow.next_sentence_jumps[], this occurrence is classified effect_class=exit_loop, danger_level=high, with target_line=338. NEXT SENTENCE transfers control to the statement following the next period, which is the period on END-PERFORM. at L338 — so it jumps past the entire read loop, not to the next statement inside it. It is not equivalent to CONTINUE: maintainers refactoring this code must not substitute CONTINUE, which would fall through to the L311 IF inside the loop body instead.

Boundary and Edge-Case Coverage

Data Operations

Per-record data movement is dominated by MOVE (per STB statements.by_verb.MOVE = 97), assembling the detail line in 1120-WRITE-DETAIL (L494–L503): INITIALIZE TRANSACTION-DETAIL-REPORT, then MOVEs of TRAN-ID, XREF-ACCT-ID, TRAN-TYPE-CD, TRAN-TYPE-DESC, TRAN-CAT-CD, TRAN-CAT-TYPE-DESC, TRAN-SOURCE, and TRAN-AMT into the corresponding TRAN-REPORT-* fields. Arithmetic is additive only (statements.by_verb.ADD = 16, SUBTRACT = 2; no COMPUTE per absence_factsno_compute): amount roll-ups (ADD TRAN-AMT TO WS-PAGE-TOTAL WS-ACCOUNT-TOTAL, L332/L419; ADD WS-PAGE-TOTAL TO WS-GRAND-TOTAL, L429) and line-counter increments (ADD 1 TO WS-LINE-COUNTER). The two SUBTRACTs are the close-routine result-code resets (SUBTRACT APPL-RESULT FROM APPL-RESULT, L650/L668). No STRING, UNSTRING, or INSPECT operations are present (absence_factsno_string_inspect).

Loop Termination

The lone PERFORM UNTIL END-OF-FILE = 'Y' (L302) is the primary and only loop (per procedure_division.control_flow.loop_constructs[]). Its exit is driven solely by the END-OF-FILE sentinel as described under Termination signal above; there is no counter-bounded or PERFORM VARYING loop in the program.

Control Breaks

The program performs a single-level control break on card number. The break field is TRAN-CARD-NUM compared against the retained WS-CURR-CARD-NUM (L313). On a change of card (and once past the first record, WS-FIRST-TIME='N'), 1120-WRITE-ACCOUNT-TOTALS emits the prior card's account subtotal (REPT-ACCOUNT-TOTAL) and resets WS-ACCOUNT-TOTAL to zero (L439–L442). The input arriving card-sorted (upstream SORT on TRAN-CARD-NUM,A) is what makes this single-pass control break correct.

Operational Behavior (semantic summary)

CBTRN03C is a straightforward sequential report writer with random-access enrichment: one input driver loop, three keyed lookups per transaction, and a three-tier total roll-up (page → account → grand). All error handling is by explicit file-status checks that funnel to a hard abend (s08). Cyclomatic complexity is 44 (McCabe, per STB metrics.cyclomatic_complexity), concentrated in the repetitive per-file status-check/abend blocks rather than in the report logic. Perform nesting depth is 2 (metrics.perform_nesting_depth).


s06 — Integrated Diagrams

File I/O Data Flow (transcribed verbatim from spine DATA_FLOW)

FILE ROLE COUNTS (by data direction): 6 files — 5 INPUT (read), 1 OUTPUT (written).

File (FD) Ops Paragraph(s) Record Direction
DATE-PARMS-FILE OPEN READ CLOSE 0500-DATEPARM-OPEN, 0550-DATEPARM-READ, 9500-DATEPARM-CLOSE WS-DATEPARM-RECORD input
TRANSACT-FILE OPEN READ CLOSE 0000-TRANFILE-OPEN, 1000-TRANFILE-GET-NEXT, 9000-TRANFILE-CLOSE TRAN-RECORD input
XREF-FILE OPEN READ CLOSE 0200-CARDXREF-OPEN, 1500-A-LOOKUP-XREF, 9200-CARDXREF-CLOSE CARD-XREF-RECORD input
TRANTYPE-FILE OPEN READ CLOSE 0300-TRANTYPE-OPEN, 1500-B-LOOKUP-TRANTYPE, 9300-TRANTYPE-CLOSE TRAN-TYPE-RECORD input
TRANCATG-FILE OPEN READ CLOSE 0400-TRANCATG-OPEN, 1500-C-LOOKUP-TRANCATG, 9400-TRANCATG-CLOSE TRAN-CAT-RECORD input
REPORT-FILE OPEN WRITE CLOSE 0100-REPTFILE-OPEN, 1111-WRITE-REPORT-REC, 9100-REPTFILE-CLOSE FD-REPTFILE-REC output

Supplementary ASCII view (agrees with the table above; paragraph nodes shown in brackets):

      DATE-PARMS-FILE ─► [0550-DATEPARM-READ] ─► WS-DATEPARM-RECORD ─┐
TRANSACT-FILE ──► [1000-TRANFILE-GET-NEXT] ─► TRAN-RECORD ─────┤
XREF-FILE ──────► [1500-A-LOOKUP-XREF] ─► CARD-XREF-RECORD ────┤
TRANTYPE-FILE ──► [1500-B-LOOKUP-TRANTYPE] ─► TRAN-TYPE-RECORD ┼─► [1100/1120 report build] ─► FD-REPTFILE-REC ─► REPORT-FILE
TRANCATG-FILE ──► [1500-C-LOOKUP-TRANCATG] ─► TRAN-CAT-RECORD ─┘

    

(Per project diagram rules, no Mermaid/PlantUML markup is used; text-based diagrams render in all output media.)


s07 — External Dependencies

External Calls

The program issues exactly one CALL (per statements.by_verb.CALL = 1): CALL 'CEE3ABD' USING ABCODE, TIMING in 9999-ABEND-PROGRAM (L762, per spine XCORP_call_sites and metrics.static_vs_dynamic — static). CEE3ABD is the Language Environment callable service that forces an abnormal task termination; ABCODE is set to 999 and TIMING to 0 before the call (L760–L761). There are no calls to application subprograms (absence_factsno_app_calls) and no ON EXCEPTION/ON OVERFLOW handling on the CALL (absence_factsno_on_exception).

Copybook References

The program inlines 5 copybooks (per data_division.copybooks.length):

Copybook Provides Consumers (blast radius)
CVTRA05Y TRAN-RECORD (350-byte transaction) 9 consumers
CVACT03Y CARD-XREF-RECORD (50-byte card xref) 12 consumers
CVTRA03Y TRAN-TYPE-RECORD (60-byte tran type) 1 consumer
CVTRA04Y TRAN-CAT-RECORD (60-byte tran category) 1 consumer
CVTRA07Y Report line records (name header, detail, totals) 1 consumer

Consumer counts are the exact values from spine COPYBOOK_CONSUMERS / cross_corpus.copybook_consumers. CVACT03Y (12 consumers) and CVTRA05Y (9 consumers) are the widely-shared shared-record copybooks; the remaining three are used only by CBTRN03C in this corpus.


s08 — Error and Exception Handling

File-Status Checks

Every file operation is followed by an explicit status check against '00', mapping the result into APPL-RESULT and then testing the 88-condition APPL-AOK. The pattern (open example, 0000-TRANFILE-OPEN, L511–L523): IF TRANFILE-STATUS = '00'MOVE 0 TO APPL-RESULTELSEMOVE 12 TO APPL-RESULT; then IF APPL-AOK CONTINUE ELSE display an error, move the status to IO-STATUS, PERFORM 9910-DISPLAY-IO-STATUS, and PERFORM 9999-ABEND-PROGRAM. The two reads that can legitimately hit end-of-file (0550-DATEPARM-READ L354–L361 and 1000-TRANFILE-GET-NEXT L383–L390) use an EVALUATE on the status instead: WHEN '00' → 0, WHEN '10' → 16 (APPL-EOF, sets END-OF-FILE='Y' rather than abending), WHEN OTHER → 12 (abend). The three keyed lookups (1500-A/B/C) use READ ... INVALID KEY clauses that display the offending key, set IO-STATUS=23, and abend (L618–L642).

Per spine COND_SET_SITES, the two checked 88-conditions are activated by MOVEs into APPL-RESULT: APPL-AOK via MOVE 0 TO APPL-RESULT, APPL-EOF via MOVE 16 TO APPL-RESULT. Error disposition here is not uniform: most I/O errors route to 9999-ABEND-PROGRAM, but the end-of-file status ('10') on the two sequential reads is handled by setting the loop sentinel and continuing, not by abending.

Abend Codes

9999-ABEND-PROGRAM (L758–L764) is the single hard-failure path: DISPLAY 'ABENDING PROGRAM', MOVE 0 TO TIMING, MOVE 999 TO ABCODE, CALL 'CEE3ABD' USING ABCODE, TIMING. It is invoked via PERFORM from 18 call sites (cite verbatim, per spine ABEND_CALL_SITES): the six OPENs, the six CLOSEs, the two sequential-read WHEN OTHER branches, the report-write error branch (1111-WRITE-REPORT-REC), and the three lookup INVALID KEY branches. On abend, the report GDG (TRANREPT(+1)) is deleted per its DISP=(...,DELETE).

9910-DISPLAY-IO-STATUS (L765–L781) formats the two-byte file status for display, handling both the non-numeric/'9'-prefixed VSAM-return case (via TWO-BYTES-BINARY/IO-STATUS-04) and the ordinary numeric case, emitting 'FILE STATUS IS: NNNN'.

The specific DISPLAY diagnostic strings preceding each abend (e.g. 'ERROR OPENING TRANFILE' at L519, 'ERROR READING TRANSACTION FILE' at L398, 'ERROR WRITING REPTFILE' at L486, 'INVALID CARD NUMBER : ' at L619) are present in source but are not carried in the unified STB's error_messages[] array (which is empty for this program) (source-derived — STB extraction gap: DISPLAY diagnostic text; not in unified STB).

I/O Steps (source/harvest order — NOT execution order)

The following I/O events are listed in source/harvest order (each at its verb's paragraph-definition line), not execution order — the I/O paragraphs are PERFORMed out of physical position (the OPENs run first at runtime though they sit physically late). Per spine IO_EVENTS (18 events):

READ DATE-PARMS-FILE INTO WS-DATEPARM-RECORD (L353) · READ TRANSACT-FILE INTO TRAN-RECORD (L381) · WRITE FD-REPTFILE-REC (L477) · OPEN TRANSACT-FILE (L510) · OPEN REPORT-FILE (L528) · OPEN XREF-FILE (L546) · OPEN TRANTYPE-FILE (L564) · OPEN TRANCATG-FILE (L582) · OPEN DATE-PARMS-FILE (L600) · READ XREF-FILE INTO CARD-XREF-RECORD (L617) · READ TRANTYPE-FILE INTO TRAN-TYPE-RECORD (L627) · READ TRANCATG-FILE INTO TRAN-CAT-RECORD (L637) · CLOSE TRANSACT-FILE (L648) · CLOSE REPORT-FILE (L666) · CLOSE XREF-FILE (L685) · CLOSE TRANTYPE-FILE (L703) · CLOSE TRANCATG-FILE (L721) · CLOSE DATE-PARMS-FILE (L739).

File Closure

All six files are explicitly closed before GOBACK (per statements.by_verb.CLOSE = 6):

File Close paragraph Status var checked
TRANSACT-FILE 9000-TRANFILE-CLOSE (L648) TRANFILE-STATUS
REPORT-FILE 9100-REPTFILE-CLOSE (L666) TRANREPT-STATUS
XREF-FILE 9200-CARDXREF-CLOSE (L685) CARDXREF-STATUS
TRANTYPE-FILE 9300-TRANTYPE-CLOSE (L703) TRANTYPE-STATUS
TRANCATG-FILE 9400-TRANCATG-CLOSE (L721) TRANCATG-STATUS
DATE-PARMS-FILE 9500-DATEPARM-CLOSE (L739) DATEPARM-STATUS

Each close checks its status and abends on failure. The two sequential-file closes (9000, 9100) reset the result code via ADD 8 TO ZERO GIVING APPL-RESULT then SUBTRACT APPL-RESULT FROM APPL-RESULT on success (L647–L650, L665–L668); the four VSAM closes use plain MOVE.


s10 — PLM Metadata

Field Value
Program ID CBTRN03C (per identification_division.program_id, L23)
Source file CBTRN03C.CBL (per identification_division.header_comments.program)
Author AWS (L24)
Program kind / archetype batch / batch_report (per program_kind, archetype)
Application CardDemo (per header comment, L3)
Stated function "Print the transaction detail report" (L5)
Program version banner * Ver: CardDemo_v2.0-25-gdb72e6b-235 Date: 2025-04-29 11:01:29 CDT (the program's own version stamp, L780, per spine VERSION_INFO)
Cyclomatic complexity 44 (McCabe, per metrics.cyclomatic_complexity)
Perform nesting depth 2 (per metrics.perform_nesting_depth)
Copybook-expanded source length 781 lines (source-derived — STB extraction gap: source-counted line total of the copybook-expanded listing; not in unified STB)
Source computer / object computer Not asserted — the program has no CONFIGURATION SECTION (per environment_division)
Generator gold_plm_generation (v3 hybrid: L0 spine + unified STB)

No SOURCE-COMPUTER / OBJECT-COMPUTER paragraphs are present in the program.


s11 — Business Rules and Validation

CBTRN03C is a reporting program; its "validation" is limited to date-window filtering and referential lookups, not field-level edit rules.

There are no field-level edit/validation routines, no 88-level validation-flag families beyond the two I/O result conditions (APPL-AOK='0', APPL-EOF='16'), and no embedded SQL validation (absence_factsno_sql).


s12 — Key Algorithms

Three-tier total roll-up

Amounts accumulate through three cross-record accumulators (per spine FIELD_ROLES — cross-record accumulators: WS-PAGE-TOTAL, WS-ACCOUNT-TOTAL, WS-GRAND-TOTAL, WS-LINE-COUNTER, APPL-RESULT):

Pagination

1100-WRITE-TRANSACTION-REPORT triggers a page break when FUNCTION MOD(WS-LINE-COUNTER, WS-PAGE-SIZE) = 0 (L414), where WS-PAGE-SIZE is 20 (L263–L264). On a page break it emits the page total and re-emits the column headers (1120-WRITE-HEADERS). WS-LINE-COUNTER is incremented on every report write (ADD 1 TO WS-LINE-COUNTER).

Detected latent defects (deterministic L1 detectors + spine warnings)

Two independent deterministic findings identify real defects in the total logic:

  1. Confirmed accumulator double-write (L1_DETECTORS accumulator_double_writes, status CONFIRMED). TRAN-AMT is added to WS-PAGE-TOTAL and WS-ACCOUNT-TOTAL at two sites: the per-record path (L419) and the EOF close-out path (L332). The source operand TRAN-AMT lives in TRAN-RECORD, whose only writer is a READ ... INTO (L381); because a READ INTO does not modify the receiving area on AT END, TRAN-AMT retains the final record's value at close-out, so the last transaction's amount is added a second time to the page and account totals (and thus into the grand total via the page roll-up). This is a genuine defect — the final page total, account total, and grand total are inflated by the last record's amount. It is not zeroed and not mutually exclusive with the per-record add.

  2. Final-group (account) subtotal omission (CLOSEOUT_BRANCH_PERFORMS ⚠ FINAL-GROUP OMISSION). 1120-WRITE-ACCOUNT-TOTALS emits a card subtotal only on a control break (IF WS-CURR-CARD-NUM NOT= TRAN-CARD-NUM → performed at L315) and is absent from the EOF close-out branch (the else at L329 performs only 1110-WRITE-PAGE-TOTALS and 1110-WRITE-GRAND-TOTALS). Consequently the last card's account subtotal is never written — a dropped final subtotal, a latent defect. There is no last-card-break path and no EOF path that emits it; the omission should be documented as such rather than assumed handled.

Both findings are deterministic pipeline results (L1 detector + spine close-out resolution), presented here as verified rather than inferred.


s13 — Screen and Report Layouts

CBTRN03C writes a 133-byte fixed report record (FD-REPTFILE-REC PIC X(133), L85). The report line images are defined in copybook CVTRA07Y (L175–L237):

Report element Record Key fields / VALUEs
Report title / name header REPORT-NAME-HEADER REPT-SHORT-NAME VALUE 'DALYREPT'; REPT-LONG-NAME VALUE 'Daily Transaction Report'; REPT-DATE-HEADER VALUE 'Date Range: '; REPT-START-DATE / REPT-END-DATE (populated from WS-START-DATE/WS-END-DATE at L409–L410) with ' to ' filler (L175–L184)
Column heading line TRANSACTION-HEADER-1 fixed captions: 'Transaction ID', 'Account ID', 'Transaction Type', 'Tran Category', 'Tran Source', 'Amount' (L204–L217)
Rule / separator line TRANSACTION-HEADER-2 PIC X(133) VALUE ALL '-' (L219)
Detail line TRANSACTION-DETAIL-REPORT TRAN-REPORT-TRANS-ID, TRAN-REPORT-ACCOUNT-ID, TRAN-REPORT-TYPE-CD, TRAN-REPORT-TYPE-DESC, TRAN-REPORT-CAT-CD, TRAN-REPORT-CAT-DESC, TRAN-REPORT-SOURCE, TRAN-REPORT-AMT (PIC -ZZZ,ZZZ,ZZZ.ZZ) (L186–L202)
Page total REPORT-PAGE-TOTALS caption 'Page Total' + dot leader; REPT-PAGE-TOTAL PIC +ZZZ,ZZZ,ZZZ.ZZ (L221–L225)
Account total REPORT-ACCOUNT-TOTALS caption 'Account Total' + dot leader; REPT-ACCOUNT-TOTAL PIC +ZZZ,ZZZ,ZZZ.ZZ (L227–L231)
Grand total REPORT-GRAND-TOTALS caption 'Grand Total' + dot leader; REPT-GRAND-TOTAL PIC +ZZZ,ZZZ,ZZZ.ZZ (L233–L237)

s14 — Data Store Interaction

Not applicable — the program performs no DB2/SQL access (absence_factsno_sql; sql empty) and no IMS DL/I calls (absence_factsno_ims_dli; ims_dli empty). All data access is VSAM/QSAM file I/O documented in s08.


s15 — State Machine Documentation

Not applicable — batch program; no pseudo-conversational state machine (state_machines carries no kind: "state_machine" entry for this program).

s16 — COMMAREA Structure

Not applicable — batch program; no CICS COMMAREA (absence_facts: no CICS; program kind is batch).

s17 — PF Key Dispatch

Not applicable — batch program; no terminal interaction (pfkey_dispatch empty).


s18 — Copybook Inventory

All copybooks are inlined in the DATA DIVISION (WORKING-STORAGE / FILE SECTION). Per data_division.copybooks:

Copybook Division / area Provides Consumers
CVTRA05Y WORKING-STORAGE TRAN-RECORD (350-byte transaction layout) 9
CVACT03Y WORKING-STORAGE CARD-XREF-RECORD (50-byte card xref) 12
CVTRA03Y WORKING-STORAGE TRAN-TYPE-RECORD (60-byte type record) 1
CVTRA04Y WORKING-STORAGE TRAN-CAT-RECORD (60-byte category record) 1
CVTRA07Y WORKING-STORAGE Report line images 1

Change-impact. CVACT03Y has the largest blast radius at 12 consumers and CVTRA05Y at 9 consumers (exact counts per cross_corpus.copybook_consumers) — a change to either the card-xref or transaction record layout ripples across many CardDemo programs, so any modification must be coordinated corpus-wide. CVTRA03Y, CVTRA04Y, and CVTRA07Y are each used by only this program (1 consumer) in the corpus, so their blast radius is local.


s19 — Cross-Program Data Flow

Transcribed verbatim from spine JOB_FLOW (job TRANREPT, per jcl_facts):

Job-Step Sequence (3 steps harvested)

# Step Program
1 STEP05R.PRC001 IDCAMS
2 STEP05R SORT
3 STEP10R CBTRN03C (this program)

Step Handoffs (derived from file_flow DSN joins + pipeline.upstream_steps)

Producer step.DD Dataset Consumer step.DD
STEP05R.PRC001 PRC001.FILEOUT AWS.M2.CARDDEMO.TRANSACT.BKUP(+1) STEP05R SORTIN
STEP05R SORTOUT AWS.M2.CARDDEMO.TRANSACT.DALY(+1) STEP10R TRANFILE

This Step's Datasets (STEP10R; STEPLIB/SYSOUT omitted)

DD Dataset DISP Direction
TRANFILE AWS.M2.CARDDEMO.TRANSACT.DALY(+1) SHR input (fed by STEP05R SORTOUT)
CARDXREF AWS.M2.CARDDEMO.CARDXREF.VSAM.KSDS SHR input
TRANTYPE AWS.M2.CARDDEMO.TRANTYPE.VSAM.KSDS SHR input
TRANCATG AWS.M2.CARDDEMO.TRANCATG.VSAM.KSDS SHR input
DATEPARM AWS.M2.CARDDEMO.DATEPARM SHR input
TRANREPT AWS.M2.CARDDEMO.TRANREPT(+1) NEW,CATLG,DELETE output

Cross-Program Dataset Sharing (recorded accessors per cross_corpus.dataset_xref)

These accessor counts are the recorded accessors in the corpus cross-reference, not a claim of corpus-exhaustiveness. The CARDXREF KSDS is the one dataset shared with other programs (four recorded readers, including this one).


s20 — Subprogram Interface

Not applicable — CBTRN03C is a top-level batch report driver, not a called subprogram. It has no LINKAGE SECTION and returns to the system via GOBACK (L349); it passes no return code to a caller. The only outbound call is to the Language Environment abend service CEE3ABD (s07). Abnormal termination is signalled to the operating system via that abend (user code 999), not via a return-code contract.


Negative Assertions (verified absences)

Derived from the STB absence_facts[] array (12 entries, all status=absent, confidence=high):

End of PLM — CBTRN03C.