2026-10-10 · CobolStack
AWS CardDemo counted from its repository, our installed copy diffed line by line against upstream, the upstream bugs it reproduces, and two business days run.
When people evaluate a mainframe modernization tool, they need a test application that looks like real work: CICS screens, VSAM files, a nightly batch cycle, copybooks shared between online and batch. Few organisations can hand their own production code to an outside team, so AWS published one. AWS CardDemo is a sample credit-card management application written for z/OS. AWS released it as open source under the Apache-2.0 licence in December 2022.[2] In July 2025 it added a set of optional modules for Db2, IMS DB and MQ.[3]
This post does three things. It describes what CardDemo contains, with every number counted from the repository. It reports what we found when we compared, line by line, the CardDemo installed on SteelFrame (our mainframe-compatible environment) against AWS's current source. And it shows what ran on it today: two simulated business days of online work and the full batch cycle. SteelFrame is an independent clean-room implementation, not IBM z/OS, and CobolStack is not affiliated with AWS or IBM.
AWS describes CardDemo as "an open source mainframe application developed by AWS to demonstrate mainframe modernization capabilities".[3] It models a small card issuer. Regular users view and update accounts and cards, list, view and add transactions, request transaction reports and pay a bill. Administrators maintain the users who may sign on. A batch cycle posts the day's transactions, calculates interest, and produces statements and reports. The repository README says the application "intentionally incorporates various coding styles and patterns" so that it exercises analysis and migration tools.[1] The data is synthetic: 50 accounts, 50 cards, 50 customers and 300 daily transactions.
The repository on GitHub, 10 October 2026. Source: aws-samples/aws-mainframe-modernization-carddemo (Apache-2.0).
The July 2025 AWS post adds five optional areas: credit-card authorizations using IMS, Db2 and MQ; transaction-type maintenance in Db2; account extraction over MQ; extra JCL utilities (FTP, text to PDF, Db2 and IMS load/unload, internal reader); and wider data-format coverage (ESDS, RRDS, alternate indexes, GDGs, variable-length records, REDEFINES, OCCURS and OCCURS DEPENDING ON).[3] The user menu gains option 11, "Pending Authorization View", and the admin menu gains options 05 and 06 for transaction types.
AWS's user-flow diagram (orange: base application, blue: optional module). Source: aws-samples/aws-mainframe-modernization-carddemo, diagrams/Application-Flow-User.png (Apache-2.0).
We counted the files on GitHub's main branch at commit 59cc6c2
(16 October 2025), the latest commit when we checked. The base application lives in
app/; each optional module has its own folder.
| Artifact | Base application | Optional modules | Total |
|---|---|---|---|
| COBOL programs | 31: 17 CICS online, 13 batch, 1 shared date-validation subroutine (CSUTLDTC) | 13: authorizations 8, transaction types 3, VSAM-MQ 2 | 44 (30,175 lines) |
| BMS mapsets | 17 | 4 | 21 |
| Copybooks (incl. Db2 DCLGENs) | 30, plus 17 symbolic-map copybooks | 14, plus 4 symbolic-map copybooks | 65 |
| JCL members | 38, plus 2 procedures | 8 | 46 + 2 PROCs |
| CICS transactions (CSD) | 18 | 7 (CP00, CPVS, CPVD; CTLI, CTTU; CDRA, CDRD) | 25 |
| CICS files (CSD) | 8 VSAM files, including 2 alternate-index paths | 8 | |
| Assembler | 2 programs (MVSWAIT, COBDATFT), 2 macros | 4 | |
| Database definitions | 6 Db2 DDL, 4 IMS DBDs, 4 PSBs, 7 Db2 control decks | 21 | |
| Sample data | 13 EBCDIC data sets (binary) and 9 ASCII equivalents | 1 IMS unload | |
| Scheduler definitions | CA-7 and Control-M exports of the batch flow | 2 |
Two details matter for anyone using it as a benchmark. First, one of the 18 base transactions, CDV1 ("developer transaction"), names a program (COCRDSEC) that the repository does not contain. Second, the README's "full batch" order begins by reloading every master file from the 2022 sample data. That is right for a first install, but run every day it would wipe each day's postings. A daily cycle has to use the second half of that list. We come back to this below.
Our CardDemo
guide on SteelFrame says the sample is installed "as-is". Before repeating that here, we
checked it. On the day of writing, we took each member of the installed libraries, decoded its
EBCDIC (code page 037) 80-byte records, and compared them line by line with the matching file in
a fresh clone of the GitHub repository. We also compared the shipped EBCDIC data files byte for
byte. Our local reference copy of the repository is identical to GitHub's current
main.
| Library on SteelFrame | Members | Result against upstream |
|---|---|---|
BMS source (CARDDEMO.BMS) | 21 | 21 byte-identical, all 80 columns |
COBOL source (CARDDEMO.SOURCE) | 44 | 36 byte-identical. 5 differ only in whitespace: a trailing empty line in four files was dropped on upload, and COTRTLIC contains one tab character, which was expanded to blanks. 3 batch programs carry commented corrections (below). |
Copybooks (CARDDEMO.COPYLIB) | 65 | Of the 44 hand-written copybooks and DCLGENs, 41 are byte-identical; 3 differ only in whitespace (CUSTREC and CSLKPCDY ship with tab characters, which were expanded to blanks; COSTM01 lost a trailing empty line). The 21 symbolic-map copybooks are generated, not copied (below). |
JCL (CARDDEMO.JCL) | 47 | 44 byte-identical. 2 carry commented corrections (CBEXPORT, CBIMPORT). 1 member, RELDPADB, is ours: it reloads the IMS database from the shipped unload, and is marked as SteelFrame-authored in its header. |
| PROCs, control cards, assembler, macros, CSD, DDL, IMS DBD/PSB | 2 + 7 + 2 + 2 + 4 + 6 + 4 + 4 | All identical (one control card differs only by a trailing empty line) |
| Shipped EBCDIC data sets | 13 | 12 byte-identical. DALYTRAN.PS is the daily transaction feed, so each business day replaces it, as it is designed to. |
So every online CICS program, every BMS map, every PROC and every hand-written copybook is AWS's source. In each changed member the change is marked in the member itself. These are the changes, in full:
RECORD KEY IS EXPORT-SEQUENCE-NUM, but
that field is declared in working storage, not in the file's record. The COBOL language
reference requires the key to be described in a record of that
file.[5] The correction declares a 4-byte key at
the same offset inside the record description. Nothing else changes.KEYS(4 28). In the CVEXPORT
layout the sequence number starts at byte 27 (counting from zero), so the member now says
KEYS(4 27). CBIMPORT.jcl lacked a CARDOUT DD for the card
output file that the program opens; one was added.DISPLAY of the job name. The original also compiles
cleanly here; it is the address walk at run time that has no equivalent. The statement logic
is untouched.cpy-bms/). SteelFrame does not upload those. It assembles the unmodified BMS
source and generates its own, as a z/OS build would. Field for field, 14 of the 21 generated
maps match AWS's copies. In the other 7, our generator emits the one-byte extended-attribute
fields (colour, highlight, and so on) in a different order, and one input field defined with
PICIN='99999999999' is generated as PIC X(11) rather than
PIC 9(11). Record lengths are the same, and the programs compile against the
generated maps. We list this as a difference in SteelFrame's output, not in CardDemo.An emulation that "fixes" a test application quietly is not a faithful test bed. If a modernization changes behaviour, you want to find out from the comparison, not have the reference hide it. CardDemo has real bugs, and SteelFrame reproduces them. Three are easy to see:
TRAN-AMT to the totals again. That field still holds the last
record read. The end-of-file path also skips the last account's "Account Total" line. This is
the report SteelFrame produced today for three transactions, of 12.75, 27.40 and 34.99:0000000000000001 00000000002 01-Purchase 0001-Regular Sales Draft POS TERM 12.75
Account Total.......................................................+ 12.75
0000000000000003 00000000020 01-Purchase 0001-Regular Sales Draft POS TERM 27.40
Account Total.......................................................+ 27.40
0000000000000002 00000000012 01-Purchase 0001-Regular Sales Draft POS TERM 34.99
Page Total .........................................................+ 110.13
Grand Total.........................................................+ 110.13
// columns condensed to fit. True sum 75.14; 110.13 = 75.14 + 34.99; no Account Total for account 12
ELSE branch that the loop can never reach, so
account 50 has its interest transaction written but its balance never updated.Today an AI agent (Claude Haiku 5.5) operated CardDemo through the 3270 screens and ISPF, like an operator, following a written runbook. It ran two complete business days on the hosted estate. The sample cards expire in 2025, and CardDemo's posting program rejects transactions on expired accounts, so the runbook uses business dates 1 and 2 September 2025.
Results: 40 jobs (JOB10501 to JOB10540). Every one ended with return code 0, except POSTTRAN with 4 on both days. CardDemo uses RC 4 to mean "some transactions rejected", and the one reject each day was the planned expired account (reason 103). Each day POSTTRAN read 5 feed transactions, posted 4 and rejected 1. On day 1 COMBTRAN merged 55 records (the earlier history plus that day's interest transactions) back into the transaction file; on day 2 it merged 111. CBEXPORT exported 259 records on day 1 and 315 on day 2, and CBIMPORT read back every one with 0 errors. Balances moved as the programs dictate: account 34 started day 1 at 2,401.49, paid it off through CB00, and ended the day at 46.09 after that day's posting and interest.
The first image is AWS's own screenshot of the main menu from the repository. The rest were captured on SteelFrame today, through the public web 3270 terminal, signed on as the sample user USER0001. All are read-only screens.
AWS's screenshot of the main menu. Source: aws-samples/aws-mainframe-modernization-carddemo, diagrams/Main-Menu.png (Apache-2.0).
The same menu on SteelFrame, from the same COMEN01C and COMEN01 map: transaction CM00, eleven options in the same layout.
Sign-on (CC00, COSGN00C), including the program's ASCII-art banknote. AppID and SysID are the SteelFrame CICS region's own names.
Account view (CAVW, COACTVWC) for account 14 after the two business days: the balance of 1,601.52 is the one the agent's log records after day 2. All customer data is CardDemo's synthetic sample.
Credit card list (CCLI, COCRDLIC), seven cards per page with F7/F8 paging.
Transaction list (CT00, COTRN00C) after the cycle: day-1 online entries posted with their business date, the CB00 bill payment, and the interest transactions INTCALC wrote. The first three rows are from an earlier demo the same day.
Being exact about faithfulness means being exact about gaps too. On the hosted demo, as of this post:
A test application is only useful as a reference if you know exactly what it is. Teams that use CardDemo to compare a rewrite, a recompile or a rehost against "the mainframe" need two things: the original code, and somewhere to run it that leaves its behaviour alone, bugs included. You can check the first yourself with a diff like ours. The second is what SteelFrame is for: the CardDemo on it is a working estate with spool, catalog, GDGs and VSAM files that you can run a cycle against and compare byte by byte. Your licensed z/OS system remains the final authority. A reference that differs from upstream in only five commented places, and still gets the report totals wrong in the same way, is a useful place to start.
main at commit 59cc6c2 (16 October 2025), Apache-2.0: README, app/ tree, CSD decks, diagrams. All counts in this post are from this commit.Counts were made on GitHub's main at commit 59cc6c2
on 10 October 2026. The installed-versus-upstream comparison was run the same day against the
hosted estate's libraries. Members were decoded from EBCDIC (CCSID 037) and compared as
80-column records, and the data sets byte for byte. Job numbers, return codes and counts come
from the operator log of the two-day run and the job output. The diagrams and main-menu
screenshot are AWS's, from the repository, reproduced under its Apache-2.0 licence. AWS, Amazon
Web Services and CardDemo are trademarks or names of Amazon.com, Inc. or its affiliates. IBM,
z/OS, CICS, Db2, IMS, VSAM, MQ and other marks are trademarks of their respective owners. Claude
is a trademark of Anthropic. CobolStack is not affiliated with, endorsed by, or sponsored by
Amazon Web Services or IBM. SteelFrame is an independent clean-room mainframe-compatible
implementation that conforms to the published specifications but is not identical to them; your
licensed system remains the sole conformance authority.