Skip to main content
Moderne OnlyThis recipe is proprietary to Moderne and runs on the Moderne platform or CLI — it isn’t part of the open-source catalog. Available with a Moderne subscription.Contact Sales

Update mainframe Prethink context

Recipe IDio.moderne.mainframe.prethink.UpdateMainframePrethinkContext
Artifactio.moderne.recipe:recipes-mainframe

Generate Prethink context for a mainframe estate: a FINOS CALM architecture document covering the jobs, programs, data sets, DB2 tables, CICS resources and IMS segments and how they reach each other, a ranked findings report, and the data tables both are derived from. Everything is written under .moderne/context/ to be committed, so an agent reading the repository starts from what the analysis found rather than from the source.

Composite recipeOpenRewriteModerne Proprietary License
Try in PlatformTry this recipe in the Moderne platform. Not a user yet? You’ll get a no-setup demo environment, with nothing to install or configure.

Definition​

Recipes44
44 recipes

Options​

2 parameters
2 optional
ParameterExampleTypeRequired
targetConfigFilesCLAUDE.mdListOptional
Which agent config files to update, creating any that do not exist yet. If not specified, updates all found files.
views—BooleanOptional
Also write one architecture document per view defined in architecture-views.json, each a filter over the same architecture: the nodes of one technology and its neighbours, and the relationships between them.

Usage​

Run this recipe

This recipe has no required configuration options. Users of Moderne can run it via the Moderne CLI.

You will need to have configured the Moderne CLI on your machine before you can run the following command.

shell
mod run . --recipe UpdateMainframePrethinkContext

To also set the recipe's optional settings, add them to the command. The values below are examples, not recommendations; see Options for what each one does.

With optional settings (example values)
mod run . --recipe UpdateMainframePrethinkContext \
--recipe-option "targetConfigFiles=CLAUDE.md" \
--recipe-option "views=true"

If the recipe is not available locally, then you can install it using:

RELEASE resolves to the newest release and LATEST to the newest build of any kind, including snapshots. Either one lets mod config recipes upgrade pull in later versions without editing this command; a pinned version stays where you put it.

mod config recipes jar install io.moderne.recipe:recipes-mainframe:RELEASE

Data tables​

COBOL relationships
org.openrewrite.mainframe.cobol.table.CobolRelationships

Relationships between different COBOL resources.

Export after a run
mod study . --last-recipe-run \
--data-table org.openrewrite.mainframe.cobol.table.CobolRelationships
ColumnDescription
DependentThe resource that defines the relationship.
Dependent typeThe resource type of the resource that defines the relationship.
ActionThe action that links the dependent and dependency.
DependencyThe resource that is exercised or linked to.
Dependency typeThe resource type of the resource that is exercised or linked to.
Dependency missingIndicates whether the dependency is a known resource.
Action metadataAdditional data about the action.
Dependent pathThe source file the dependent's statement was written in, or null when the dependent is a name that has no source here.
Dependent lineThe one-based line the dependent's statement was written on, or null when it has no source here.
Dependency pathThe source file the dependency was written in, or null when the dependency is a name that has no source here, such as a vendor copybook.
Dependency lineThe one-based line the dependency's statement was written on, or null when the dependency is a whole file rather than a statement within one.
Relationship kinds
io.moderne.mainframe.analysis.table.RelationshipKinds

Every relationship a resource of each type can have, both ways round. This is the schema the relationship rows are read against, so a view of one component can show each relationship it is capable of even when it has none — an empty section says "nothing calls this", where a missing section says nothing at all.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.RelationshipKinds
ColumnDescription
Resource typeThe type this relationship is expected of.
DirectionOUTBOUND where the resource is the dependent of the edge, INBOUND where it is the dependency. Every kind has a row each way, which is what makes the inverse renderable.
VerbWhat to call this relationship on a view of the resource: Calls outbound, Called by inbound.
ActionThe action a relationship row carries for this kind.
Related typeThe type at the other end.
Inverse verbWhat the same relationship is called on a view of the related type.
Business rules
io.moderne.mainframe.analysis.table.BusinessRules

One row per decision: a condition a program tests, and everything that follows from it. A record copied field by field is one decision here, not one per field — the individual assignments are in the rule actions table.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.BusinessRules
ColumnDescription
ProgramThe COBOL program.
ParagraphThe paragraph or section the actions are written in. The same test made in two places is two decisions, however alike they read.
WhenThe conditions that must all hold, normalised: condition names expanded to the test they stand for, negation folded into the operator, and each field named where its value came from rather than where it was copied to.
ThenWhat the program does, short enough to read. Fields copied unchanged are counted rather than listed, since a record copied field by field is one act however many statements it takes.
DecidesEvery field assigned and resource acted on, in source order.
ActionsHow many statements the decision covers.
KindsWhat sorts of thing it does: COPY, CONSTANT, COMPUTE, CALL, WRITE. A decision that only copies is plumbing; one that computes or writes is where the business is.
ConditionsThe fields the condition tests.
Inherited fromFields tested under a name other than the one the source wrote, because the value was traced back through a MOVE to where it came from.
AnomalyCONTRADICTORY, UNREACHABLE or SUBSUMED where the decision cannot do what it appears to; empty otherwise.
Rule actions
io.moderne.mainframe.analysis.table.RuleActions

One row per statement a rule decides, which is the grain impact analysis and lineage want: every field the program assigns under a condition, and the condition. Rows sharing a subject are the rows of one decision table; rows sharing a condition are one row of the business rules table.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.RuleActions
ColumnDescription
ProgramThe COBOL program.
ParagraphThe paragraph or section the action is written in.
SubjectWhat the action decides: the field it assigns, or the resource it acts on. Every row sharing this value belongs to one decision table.
RuleThe rule's position in its decision table, in source order. Where two rules cover the same case, the later one is the one that runs.
WhenThe conditions that must all hold, normalised.
ThenWhat happens: the value assigned, or the operation performed.
KindCOPY for a field given another field's value unchanged, CONSTANT for a literal, COMPUTE for arithmetic or an expression, CALL for work handed to another program, WRITE for something written where the outside can see it.
ConditionsThe fields this rule tests, which are the columns of its decision table.
Inherited fromFields the rule tests under a name other than the one the source wrote, because the value was traced back through a MOVE to where it came from.
AnomalyCONTRADICTORY, UNREACHABLE or SUBSUMED where the rule cannot do what it appears to; empty otherwise.
Decision table anomalies
io.moderne.mainframe.analysis.table.DecisionTableAnomalies

Rules that cannot do what they appear to, found by checking the normalised table rather than by reading the code.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.DecisionTableAnomalies
ColumnDescription
ProgramThe COBOL program.
SubjectThe field or resource the rule decides, which is the decision table it belongs to.
KindCONTRADICTORY for conditions that exclude each other, so the rule never fires; UNREACHABLE for a rule in a paragraph nothing reaches; SUBSUMED for a rule an earlier one has already decided.
RuleThe rule, as WHEN conditions THEN outcome.
ParagraphThe paragraph or section the rule is written in.
DetailWhy the rule cannot fire, or which earlier rule already covers it.
Findings
io.moderne.mainframe.analysis.table.Findings

Everything the mainframe analyses found wrong, ranked, with the evidence for each and the line it is on. Sort on priority.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Findings
ColumnDescription
Priority1 for CRITICAL down to 4 for LOW, so the table sorts.
SeverityCRITICAL for code that cannot do what it was written to do, HIGH for what will break a migration if not decided deliberately, MEDIUM for what is worth knowing first, LOW for cleanup.
CategoryWhat kind of problem it is, which is what groups the report into sections: DEAD_RULE, UNREACHABLE_CODE, COPYBOOK_DRIFT, MIGRATION_BLOCKER, RANGE_PATHOLOGY, DEAD_DATA, COMPLEXITY, LAYOUT_DRIFT, IMS_PCB_MISMATCH, IMS_SEGMENT_NOT_SENSITIVE, IMS_IO_AREA_MISMATCH, MFS_MESSAGE_LENGTH, SCREEN_ITEM_UNREACHED, SCREEN_FIELD_UNREACHED, PARSE_FAILURE, UNDOCUMENTED, STALE_DOCUMENTATION, STALE_REFERENCE, UNENFORCED_BUILD_ORDER, UNSCHEDULED_JOB, AUTOCALL_RESOLVED_REFERENCE, UNRESOLVED_EXECUTION_PATH, INHERITED_SETTING, UNLOAD_NEEDS_REDESIGN, UNLOAD_ACCESS_MODE, UNLOAD_CONSISTENCY, UNLOAD_OUTPUT_WIRING, MIXED_SUBSTITUTION.
ProgramThe COBOL program, or the copybook where the finding is about one.
SummaryThe finding in one sentence, written to be read on its own.
EvidenceWhy this is claimed — the conditions that conflict, the two declarations that differ, the caller that made the paragraph unreachable. A finding nobody can check is a finding nobody will act on.
WhereThe paragraph, section or data item the finding is in.
Source pathThe file, so the finding can be opened.
Program complexity
io.moderne.mainframe.analysis.table.ProgramComplexity

Size and complexity per program, for ranking a portfolio by risk and effort.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ProgramComplexity
ColumnDescription
ProgramThe COBOL program.
Cyclomatic complexityMcCabe: one plus every decision the program can take, counting each operand of a compound condition separately.
StatementsProcedure division statements.
Source linesLines of the program as written.
Comment linesSource lines that are comments: an asterisk or slash in the indicator column.
Expanded linesLines with every copybook inlined where it is copied, which is what the compiler reads. A copybook that was not found adds nothing.
Expanded comment linesComment lines with every copybook inlined.
ParagraphsParagraphs declared.
SectionsSections declared.
Data itemsData items declared, including those copied in.
CopybooksDistinct copybooks copied in. More than twenty marks a program that is expensive to change, because its shape is set by files it does not own.
CallsDistinct programs called.
Halstead volumeVolume over COBOL operators and operands. The absolute value means little; the spread across a portfolio is what ranks programs.
Maintainability indexThe conventional 171-based index. Below about 65 reads as hard to maintain, below 20 as effectively unmaintainable.
FlagsThresholds crossed, from published operating experience rather than invented: more than 20 copybooks, more than 100 statements per paragraph on average, cyclomatic complexity over 50, or a maintainability index under 65.
Dead data
io.moderne.mainframe.analysis.table.DeadData

Declared fields that nothing reads, and fields written but never read back.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.DeadData
ColumnDescription
ProgramThe COBOL program.
FieldThe field, qualified by the records containing it.
SectionWhere it is declared. LINKAGE and FILE items are read and written by something outside this program, so they are reported separately rather than treated as unused.
VerdictUNUSED for a field neither read nor written; DEAD_STORE for one written but never read back.
PictureThe declared picture, for sizing what would be saved by dropping it.
CopybookThe copybook the field came from, where it came from one. A field dead in this program may well be live in another that copies the same book, so a copybook field is only safe to drop once every program is checked.
Unreachable procedures
io.moderne.mainframe.analysis.table.UnreachableProcedures

Paragraphs and sections that no path from the program's entry point reaches.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.UnreachableProcedures
ColumnDescription
ProgramThe COBOL program.
ProcedureThe unreachable paragraph or section.
KindWhether it is a paragraph or a section.
PositionIts position in source order, counting from zero.
Reachable proceduresHow many procedures the program does reach, for comparison against its total.
Total proceduresHow many procedures the program declares.
PERFORM THRU range pathology
io.moderne.mainframe.analysis.table.ProcedureRangePathology

Ranges that overlap without nesting, and jumps that leave a range part-way through.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ProcedureRangePathology
ColumnDescription
ProgramThe COBOL program.
KindOVERLAPPING_RANGE for two ranges that partly overlap; RANGE_JUMP for a GO TO that leaves a performed range before its exit.
RangeThe range concerned, as START THRU END.
Conflicts withFor an overlap, the other range. For a jump, the procedure jumped to.
DetailWhy it matters for anyone trying to restructure or extract the code.
Mainframe migration blockers
io.moderne.mainframe.analysis.table.MainframeMigrationBlockers

CICS and IMS constructs that need a design decision before a program can be moved.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.MainframeMigrationBlockers
ColumnDescription
ProgramThe COBOL program.
ParagraphThe paragraph or section containing the construct.
CategoryThe kind of problem the construct poses.
ConstructThe command or call that raised it.
DetailWhat has to be decided, and why the construct does not carry over on its own.
CICS command usages
io.moderne.mainframe.analysis.table.CicsCommandUsages

Every EXEC CICS command, with the options it was given.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.CicsCommandUsages
ColumnDescription
ProgramThe COBOL program containing the command.
ParagraphThe paragraph or section containing the command.
CommandThe CICS command, including its qualifier where it has one, such as SEND MAP.
API groupThe CICS API the command belongs to, which is the unit a Java replacement is chosen for.
OptionsThe command's options and operands as written.
Copybook source information
org.openrewrite.mainframe.cobol.table.CopybookSource

Information about copybook references in a COBOL source.

Export after a run
mod study . --last-recipe-run \
--data-table org.openrewrite.mainframe.cobol.table.CopybookSource
ColumnDescription
Source pathThe source path of the file that contains the copy statement.
Copybook nameThe copybook name from a copy statement in a COBOL source.
Copybook source pathThe source path of the copybook that was resolved during resolution of copybooks.
Resolution statusThe status of the resolved copybook in a copy statement.
Marked wordThe current word being visited from the post-processed LST.
Copybook drift
io.moderne.mainframe.analysis.table.CopybookDrift

Fields that a copybook declares differently, or not at all, in different programs.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.CopybookDrift
ColumnDescription
CopybookThe copybook whose copies disagree.
FieldThe field the copies disagree about.
VariantThe picture this group of programs sees, GROUP for a field with no picture of its own, or ABSENT for programs whose copy does not declare the field at all.
ProgramsThe programs seeing this variant.
Program countHow many programs see it. A variant held by one program against twenty is a different problem from an even split.
Copybook impact
io.moderne.mainframe.analysis.table.CopybookImpact

Every program that copies a copybook, what it does with each field, and what those fields reach there.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.CopybookImpact
ColumnDescription
CopybookThe copybook the field is declared in.
FieldThe field, qualified by the records containing it.
PictureThe picture as written in this program. A field whose picture differs between programs is not one field, whatever the copybook says.
ProgramA program that copies the copybook.
UsageREAD, WRITTEN, BOTH, or UNUSED where the program copies the field and never touches it. Unused is the common case and the useful one: it is what makes a copybook change smaller than it looks.
EndpointsWhat the field reaches in this program — the files, queues, maps and IMS segments a change to it would be visible at.
Resource CRUD matrix
io.moderne.mainframe.analysis.table.ResourceCrud

Which programs create, read, update and delete which files, queues, DB2 tables and IMS segments, across CICS, DL/I, SQL and native file I/O.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ResourceCrud
ColumnDescription
ProgramThe COBOL program.
ParagraphThe paragraph or section containing the statement.
Resource kindWhether the store is a file, a temporary storage or transient data queue, a DB2 table or an IMS segment.
ResourceThe resource as the program names it.
External nameWhat the resource is called outside the program — the ASSIGN name for a native file. This is the column two programs have to agree on before they can be said to share a store.
CRUDCREATE, READ, UPDATE or DELETE.
OperationThe statement as written. Two accesses that agree on CRUD can still differ in ways worth seeing.
DynamicWhether the resource name came from a data item rather than a literal.
Batch CRUD matrix
io.moderne.mainframe.analysis.table.BatchCrud

Which job step runs which program against which data set, and what the program does with it.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.BatchCrud
ColumnDescription
JobThe job name, empty for a member with no JOB card.
MemberThe JCL member.
StepThe step name. An unnamed step is empty, and cannot be referred to by a later step or by a scheduler.
Step programThe program the step names on PGM=.
ProgramThe program that names the file. Not always the step's program: a subprogram opens the DDs of the step that runs its caller.
DD nameThe DD name, which is the only word the JCL and the program both contain.
FileThe file as the program names it, from SELECT.
Written inThe member that asked for the DD, where the program's own text does not — a SAS %INCLUDE reads another member in where the statement stands, so what that member needs the step has to allocate. Empty for a DD the program names itself.
Data setThe data set as the installation knows it, with any member.
Data set kindWhether the DD names a catalogued data set, a generation, a library member, something temporary, in-stream data, DUMMY, SYSOUT, or a data set passed by an earlier step.
DispositionThe DISP operand as written. The status is what says whether the step expects the data set to exist.
CRUDCREATE, READ, UPDATE or DELETE, empty where nothing is bound.
OperationsThe statements the CRUD was read from.
BindingHow far the DD name and the ASSIGN clause got towards meeting. Anything other than BOUND is a gap between the JCL and the program, or a limit of what the sources read can say.
CICS resource usages
io.moderne.mainframe.analysis.table.CicsResourceUsages

Which CICS resources each program touches, and how.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.CicsResourceUsages
ColumnDescription
ProgramThe COBOL program touching the resource.
ParagraphThe paragraph or section containing the command.
Resource kindWhether the resource is a file, a queue, a program, a transaction or a map.
ResourceThe resource name. For a dynamic reference this is the resolved name where one literal reaches the operand, and otherwise the data name supplying it.
AccessWhat the command does to the resource.
DynamicWhether the resource name came from a data item rather than a literal. Dynamic references are the ones an automated migration has to leave to a person.
CommandThe CICS command that produced this access.
IMS DL/I calls
io.moderne.mainframe.analysis.table.ImsDliCalls

Every DL/I database and message call, however it was written.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ImsDliCalls
ColumnDescription
ProgramThe COBOL program making the call.
ParagraphThe paragraph or section containing the call.
InterfaceThe DL/I language interface: CBLTDLI, AIBTDLI, CEETDLI, PLITDLI, or EXEC DLI.
FunctionThe DL/I function, such as GU, GN, ISRT, REPL or DLET. Empty when the function code is supplied by a data item that more than one literal reaches.
Function operandThe argument the function code was passed in, whether or not it resolved.
PCBThe PCB the call was issued against.
PCB positionThe PCB's position in the PSB, counting from zero, or -1 when the program does not declare it at its entry point. The PSB has to be joined on this position to name the database, because nothing in the COBOL does.
Message callWhether the call is against the I/O PCB, making it a message queue read or write rather than a database call.
AccessWhat the call does: READ, CREATE, UPDATE, DELETE, CHECKPOINT or SYSTEM.
SegmentsSegment names the call is qualified by, where they could be resolved.
JCL step detail
io.moderne.mainframe.analysis.table.JclStepDetail

Every data set each job step allocates, with the procedure the step came from and the attributes the data set is allocated with.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.JclStepDetail
ColumnDescription
JobThe job name, empty for a member with no JOB card.
MemberThe JCL member the job was read from.
Source pathThe file the job was read from, which is the file to open at the line below.
LineThe one-based line the step's EXEC card is on. A step a procedure supplies is written in that procedure and has no line in the job, so it is the calling EXEC card that is given — the line the job's reader has. The procedure is read on its own as well, and its steps carry their own lines there.
Step numberWhere the step falls in the job as it runs, procedures expanded, counting from one. Ordering by it is what makes the rows a step-by-step listing rather than a pile.
ProcedureThe procedure the step is written in. Empty for a step written in the job itself; filled in with the procedure it calls when that procedure was not supplied, which is the one case where the step below it cannot be read.
StepThe step name, qualified by the step that called its procedure — EXTRACT.RUN — which is how a listing names it and how a DD override refers to it.
ProgramThe program the step loads, symbols filled in. A DL/I or BMP region names itself on PGM= and the program it loads in its PARM, and it is that program which is reported.
PSBThe PSB an IMS region step runs under, from its PARM. Empty for anything that is not one.
DD nameThe DD name, which is the only word the JCL and the program both contain.
Data setThe data set as the installation knows it, with any member. A DD that concatenates several is one row each, because only the data set name joins one job to another.
Data set kindWhether the DD names a catalogued data set, a generation, a library member, something temporary, in-stream data, DUMMY, SYSOUT, or a data set passed by an earlier step.
GenerationThe relative generation of a generation data group, +1 for the one this step creates and 0 or -1 for one it reads. Empty for everything else.
DispositionThe DISP operand as written. The status is what says whether the step expects the data set to exist.
Record formatRECFM, from the keyword or from within DCB.
Record lengthLRECL, from the keyword or from within DCB. 0 is written on purpose and is not the same as absent, so an omitted one is left empty.
Block sizeBLKSIZE, from the keyword or from within DCB. 0 asks the system to choose one.
SpaceThe SPACE operand without its outer parentheses, CYL,(10,5),RLSE. Only a step that creates a data set writes one.
UnitThe UNIT operand, the device or esoteric group the data set is allocated on.
CRUDThe letters of everything the step's programs do to the data set — C, R, U, D, in that order. Empty where nothing in the run unit assigns the DD, or where the program was not among the sources read.
Execution paths
io.moderne.mainframe.analysis.table.ExecutionPaths

Every job step with the program it runs, the procedure it came through, what its PARM passes, where its control cards are written, and the verdict on whether all of that could be read from the source supplied.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ExecutionPaths
ColumnDescription
JobThe job name, empty for a member with no JOB card.
MemberThe JCL member the job was read from.
Source pathThe file the job was read from, which is the file to open at the line below.
LineThe one-based line of the EXEC card the path starts at. A step a procedure supplies is written in that procedure and has no line in the job, so it is the calling EXEC card that is given — the line the job's reader has, and the card a transformation would be applied to.
Step numberWhere the step falls in the job as it runs, procedures expanded, counting from one.
ProcedureThe procedure the step is written in. Empty for a step written in the job itself; filled in with the procedure it calls when that procedure was not supplied, which is the case where nothing below can be read.
StepThe step name, qualified by the step that called its procedure — UNLHST.UNL. This is the name the reasons below are written against.
ProgramThe program the step names on PGM=, with its symbols filled in. What that program then loads is its own business and is usually in the PARM beside it: an IMS region names itself here, and a utility names an engine that reads its real instructions off the control cards.
PARMWhat PARM= passes the program, symbols filled in and the apostrophes that carried it taken off. Empty where the step passes none.
PARM positionsThe same PARM split into the positions the program reads it as, separated by | , with a group left whole — ssid,uid,HIDDEN(user,pswd) is three positions and not four. A utility reads its parameters by position, so this is where the subsystem a step runs against is written.
DD nameThe DD that hands the step a deck of control cards. Empty for a step handed none; a step handed several has a row each, since the cards rather than the JCL are what such a step really runs.
CardsWhere those cards are written: IN_STREAM in this member's own job stream, PROCEDURE in the stream of the procedure the step calls, MEMBER in the library member the DD names. Empty where the step is handed no cards.
Cards memberThe data set and member the DD names, CLM.PROD.CTLCARD(UNLCLM01). Empty for cards written in a stream. Where the member name is itself a symbol the job passed, this is what it resolved to — which for a job whose deck is named only on DECK= is the one line that says what the job does.
VerdictRESOLVED where every name was followed and everything the step does is written in what was read, INHERITED where every name was followed and part of what it does is a setting written outside the application libraries, UNRESOLVED where a name was not followed at all. Only RESOLVED is safe to rewrite without asking anyone anything. The verdict is the whole path's, so the rows of one path all carry it.
ReasonsEvery reason the verdict is not RESOLVED, separated by ; , each written as the kind, the step and DD it was found under, and its subject — KEYWORD_INHERITED UNLPOL.UNL.SYSIN FORMAT. Empty for a resolved path. One row per reason, with the kinds counted, is ExecutionPathGaps.
Execution path gaps
io.moderne.mainframe.analysis.table.ExecutionPathGaps

One row per reason a job step's execution path is not fully determined by the source supplied: the kind of gap, the step and DD it was found under, and what it is about.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ExecutionPathGaps
ColumnDescription
JobThe job name, empty for a member with no JOB card.
MemberThe JCL member the job was read from.
Source pathThe file the job was read from.
LineThe one-based line of the EXEC card whose path this reason belongs to, which is the line of this file a reader opens. With the member it is the key back to the ExecutionPaths rows of the same path.
StepThe step the reason was found in, qualified by the step that called its procedure — a keyword left uncoded in a deck the procedure's SYSIN names is found in UNLHST.UNL and belongs to the path of UNLHST.
KindPROCEDURE_MISSING for a procedure that was not in the library supplied, SYMBOL_UNDEFINED for a symbol nothing sets, MEMBER_MISSING for a library member a DD names and nobody supplied, CARDS_NOT_READ for a deck that opens a statement of a language read here and could not be read as one, KEYWORD_INHERITED for a keyword a deck leaves to a setting written outside the application libraries.
DD nameThe DD the reason was found under. Empty where it was not found under one — a missing procedure, or a symbol on the EXEC card itself.
NameWhat the reason is about: the procedure, the symbol without its &, the member, or the keyword. Empty for CARDS_NOT_READ, where the DD is itself the subject.
VerdictThe verdict this kind of reason carries a path to: UNRESOLVED for a name that was not followed, INHERITED for behaviour that is a site setting. A path's own verdict is the worst its reasons carry.
Control card kinds
io.moderne.mainframe.analysis.table.ControlCardKind

What each control card deck is, and which steps read it. A control card library holds sort cards, IDCAMS cards, DSN command decks and parm cards side by side, and nothing in a member's name says which is which — the kind here is read off the deck's first statement. A deck written in a job stream is here too, under the job it is written in, where what it says types it.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ControlCardKind
ColumnDescription
MemberThe control card member, or the job a deck written in the stream is written in. A member two libraries hold has a row for each, which is how an environment's copy is told from the application's own.
Source pathThe file the cards are in.
DDThe DD a deck written in the stream arrives on, empty for a member of its own. Which DD it is depends on the utility: DFSORT reads SYSIN, DFSPARM or a xxxxCNTL an ICETOOL USING names.
LineThe one-based line of that file the deck begins on, which is 1 for a member of its own.
KindDFSORT, IDCAMS, DSN, DB2_UTILITY or PLAIN, judged by the first statement the deck writes. A member is not typed by its name: the shops that call them SRTxxxxx and DEFxxxxx are following a convention, not a rule.
StatementsHow many control statements the deck holds. 0 where no grammar has read it: a PLAIN or DSN deck, and a deck that reached the analysis as plain text because the ingestion did not run the parser that types it.
ReferencesHow many job steps read this member. 0 for a member nothing supplied here reads, which is either a deck run by hand or a job that was not supplied; 1 for a deck written in the stream, which is read by the step it is written in.
Referenced byThe steps that read it, as JOB.STEP(DD), joined with commas. A step reaching the deck through a procedure names the DD as it was written on the override, RUN.SYSTSIN.
Load module composition
io.moderne.mainframe.analysis.table.LoadModuleComposition

What each load module is built from, one row per program, map set or external routine bound into it, read from the link-edit deck that declares the module and from the listing that reports the module as built. Neither the COBOL nor the JCL says which programs share a module: a step names a module and runs whatever the binder last put in it, so a change to a statically bound subroutine is felt by every module holding a copy and by nothing else.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.LoadModuleComposition
ColumnDescription
ModuleThe load module, which is the name a step, a CALL or a CICS program definition asks for.
LibraryThe load library the module is written to, from the SYSLMOD of the step that links it or from the listing. Which library a module is in is what tells a batch module from a CICS one where both carry the program's name.
PartA program, map set or external routine the module holds. Every module holds the program of its own name; a statically called subroutine is a second part of every module that includes it.
Part kindPROGRAM, ASSEMBLER or MAPSET where the part was read, STUB for a language interface known by name, EXTERNAL for an object nobody supplied. Runtime sections the binder's autocall pulls in are not parts and get no row.
Part pathThe part's file, empty for a stub or an external routine. A module built from a program no ingestion holds is how a gap shows.
ReconciliationBOTH where the deck declares the part and the listing reports it, DECLARED_ONLY where the module has not been listed since the deck was written, OBSERVED_ONLY where the module holds something no deck asked for — the module in the library and the deck in the library have drifted apart — and BUILT_ONLY where a job writes the module and neither describes it.
InferredTrue where no card names the part. The compile hands the binder its object on SYSLIN without naming it, so the program a module is named for is a part of it that the deck does not write down; every other part is on a card of its own.
Entry pointWhere control enters the module: the program's own section, or a label in it such as the DLITCBL a DL/I batch program declares.
AliasesThe module's other directory entries, space separated. An alias is a second name the same module answers to, which is how a renamed program goes on being called by its old name.
DeckThe link-edit deck that declares the module, empty where none was read. A deck written in a job stream is that job.
Deck lineThe line of the deck the part's INCLUDE card is on, or of the NAME card for the program the module is named for. Zero where no deck declares the part.
ListingThe listing the module was read from, empty where none covers it. A listing is what was printed on the day it last ran, so a module built since is missing from it rather than absent from the library.
Listing lineThe line of the listing the part's control section is reported on. Zero where no listing covers the module.
Linked by jobThe job whose step reads the deck, empty where no job read here does.
Linked by stepThe step of that job, which is what has to be rerun to rebuild the module.
Loaded by jobA job whose step runs this module, empty where none does. Four cards say so: PGM=, the PARM an IMS region takes its program in, the RUN PROGRAM of a DSN deck the step reads, and the APPLCTN of a stage 1 deck — which is not a job at all, and names the stage 1 member instead. A module several steps run has a row for each.
Loaded by stepThe step that runs it, named as the job writes it rather than as the procedure does, or APPLCTN for a module the IMS message region loads.
DB2 bind chain
io.moderne.mainframe.analysis.table.Db2BindChain

What each bind card declares, one row per plan or package it names: the deck it is written in, the job that runs that deck, the collection the package lands in, the DBRM it is bound from and the program that DBRM was precompiled from. The deck is the only place the chain from a plan to the program that runs under it is written down — neither the COBOL nor the JCL says any of it.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Db2BindChain
ColumnDescription
DeckThe member the deck is: a bind library member under its own name, or the job the deck is written in the stream of.
Deck pathThe file the card was written in.
LineThe one-based line of that file the subcommand begins on, counting from the top of the job for a deck written in-stream.
CommandBIND where the card makes the object, REBIND where it names one that already exists. Only a BIND says what an object is bound from.
BindsWhether the card binds a PLAN or a PACKAGE.
PlanThe plan, empty for a package bind. A plan is what a batch step names in RUN PROGRAM(...) PLAN(...) and what the CICS resource definition names.
CollectionThe collection the packages are bound into, empty for a plan bind. This is the name an environment varies: the same deck binds into another collection on another subsystem.
PackageThe package, empty for a plan bind. * where a REBIND names every package of the collection rather than one.
DBRMThe DBRM member the package is bound from, from MEMBER. Empty for a plan bind and for a REBIND, which is bound from whatever it was bound from before.
ProgramThe program the DBRM was precompiled from. A DB2 precompile writes the DBRM under the program's own name, so the DBRM member, the package and the program are the same word — this is the join from a plan to the code that runs under it.
Program pathThe program's file, empty where no program of that name was read. A bind for a program nobody supplied is how a gap in an ingestion shows.
Package listThe packages a plan may run, from PKLIST, as written: an entry names a collection and either one package or * for all of them. Empty for a package bind.
QualifierWhat unqualified table names in the package resolve to. This is the schema the SQL in the program actually reads, which the program never names.
OwnerThe authorization identifier the object is owned by.
JobThe job whose step runs this deck, empty where no job read here does. A deck run by two jobs has a row for each.
StepThe step of that job, which is where the bind is placed among the compiles.
DB2 package plans
io.moderne.mainframe.analysis.table.Db2PackagePlans

The bind chain read from the package's side: which plans may run each package, and so which plans a change to the program behind it is felt under. A plan lists either the package outright or the whole collection with *, so the plans a package runs under are written down nowhere one name at a time.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Db2PackagePlans
ColumnDescription
CollectionThe collection the package is bound into.
PackageThe package.
ProgramThe program the package is bound from, which is the DBRM member of the same name. Empty where no bind read here says what the package holds.
PlanA plan that may run the package. Empty where none read here lists it.
Listed asPACKAGE where the plan's PKLIST names the package outright, COLLECTION where it names the collection with * and so picks up every package bound into it, NOT_LISTED where no plan reaches it.
Package deckThe deck the package is bound in.
Plan deckThe deck the plan is bound in, which is often not the one the package is bound in.
DB2 tables
io.moderne.mainframe.analysis.table.Db2Tables

One row per table the DDL creates: where it is defined, what it is made of, and who reaches it. This is the summary a person opens a table on — the columns, the primary key, the foreign keys either way and the indexes, with the programs, packages and plans that use it — so the question "what is this table and what would a change to it break" is one row rather than a search.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Db2Tables
ColumnDescription
TableThe table, qualified as the DDL wrote it. This is the name the SQL in a program has to resolve to, and the one an unqualified name is resolved against the bind qualifier to reach.
SchemaThe qualifier the table was created under, empty for a table created unqualified — which leaves it to whatever SET CURRENT SQLID was in force.
NameThe table's own name, without its schema.
Table spaceThe table space the table lives in, empty where the DDL leaves it to DB2. This is what a RUNSTATS or a REORG card names, so it is the join from a table to the utility jobs that maintain it.
MemberThe DDL member the table is created in, or the job that creates it in its own stream.
Source pathThe file the CREATE TABLE was read from, which is the file to open at the line below.
LineThe one-based line of that file the CREATE TABLE begins on, counting from the top of the job for DDL written in a stream.
WrittenWhether the DDL is a member of a library or written in a job's stream. A table created in a stream exists nowhere else, so the job is its definition and not just the thing that ran it.
ColumnsHow many columns the table has.
Primary keyThe primary key's columns in key order, empty for a table declaring none — which happens, and is then enforced by a unique index instead.
Foreign keysHow many foreign keys this table declares, which is how many parents it has.
Referenced byHow many foreign keys point at this table, which is how many children it has. A table with children cannot have a row deleted without deciding what happens to them.
IndexesHow many indexes are defined on the table.
ProgramsHow many programs name the table in an EXEC SQL statement, unqualified names resolved against the qualifier their package was bound with.
PackagesHow many DB2 packages reach the table, which is the programs above joined to the bind decks that bind them.
PlansHow many plans reach the table through those packages, a PKLIST naming a whole collection expanded. Every plan counted here has to be rebound when the table changes.
DB2 columns
io.moderne.mainframe.analysis.table.Db2Columns

Every column of every table the DDL creates, in the order a SELECT * and a host structure both take: what it holds, whether it may be absent, where it sits in the primary key, the table it points at through a foreign key, and the indexes it is a key of. The last is what says whether a predicate written on the column has an access path or a table space scan behind it.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Db2Columns
ColumnDescription
TableThe table the column belongs to, qualified as the DDL wrote it.
OrdinalWhere the column sits in the table, counting from one. This is the order a SELECT * and a host structure both take, so it is what aligns a column with the COBOL field receiving it.
ColumnThe column name.
TypeThe type as the DDL writes it, length and scale included: CHAR(12), DECIMAL(9, 2), DATE.
NullableWhether the column may hold no value. A primary key column may not, whether or not the DDL says NOT NULL — DB2 requires it and supplies it when it is left out. A nullable column is the one a program has to fetch with an indicator variable.
Key sequenceWhere the column sits in the primary key, counting from one, or 0 for a column that is not part of it.
Foreign key toThe table this column points at through a foreign key, empty where it points at none. A column carrying two foreign keys names both.
IndexesThe indexes the column is a key of, each with its position in that key and the direction it is held in — CLM.XPOLICY1(2 ASC). A column with none is a column no predicate can be selective on.
MemberThe DDL member the column is declared in, or the job that declares it in its own stream.
Source pathThe file the column was read from, which is the file to open at the line below.
LineThe one-based line of that file the column is declared on.
DB2 primary keys
io.moderne.mainframe.analysis.table.Db2Keys

The primary key of each table, one row per key column in key order, with the unique index that enforces it. DB2 will not accept a primary key without one, so a key whose index is missing here is DDL that would not run — and the index is also the access path every foreign key check and every keyed read goes through.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Db2Keys
ColumnDescription
TableThe table the key belongs to, qualified as the DDL wrote it.
ConstraintThe name the DDL gives the constraint, empty where it names none — which is usual for a primary key, and leaves DB2 to name it after the index.
ColumnThe key column.
Key sequenceWhere the column sits in the key, counting from one. A composite key is only usable left to right, so the order is the whole of what it is good for.
Enforced byThe unique index whose key is exactly these columns, empty where the DDL read here declares none. DB2 requires one and creates it implicitly when a shop lets it, so an empty value means the index was not supplied rather than that there is none.
MemberThe DDL member the key is declared in, or the job that declares it in its own stream.
Source pathThe file the key was read from, which is the file to open at the line below.
LineThe one-based line of that file the PRIMARY KEY is written on.
DB2 indexes
io.moderne.mainframe.analysis.table.Db2Indexes

Every index the DDL creates, with the table it is on and the key it holds. An index is how a batch job reaches a table cheaply, so which columns it is keyed on is which predicates the schema was designed to answer — and an index no program writes a predicate for is maintenance nothing collects on.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Db2Indexes
ColumnDescription
IndexThe index, qualified as the DDL wrote it.
TableThe table the index is on, qualified as the DDL wrote it.
UniqueWhether the index enforces uniqueness, which is what a primary key needs and what a shop with no primary key uses instead of one.
Key columnsThe key in order, each column with the direction it is held in — STATUS_CODE ASC, POLICY_NO ASC. A composite key is only usable left to right.
Enforces the primary keyWhether this is the unique index whose key is exactly the table's primary key, which is the index DB2 requires a primary key to have.
MemberThe DDL member the index is created in, or the job that creates it in its own stream. An index added to a live table years after its table is routinely in a job of its own, and that job is the only place it exists.
Source pathThe file the CREATE INDEX was read from, which is the file to open at the line below.
LineThe one-based line of that file the CREATE INDEX begins on, counting from the top of the job for DDL written in a stream.
DB2 foreign keys
io.moderne.mainframe.analysis.table.Db2ForeignKeys

One table pointing at another, which is the referential arrow of the model diagram and the one relationship between two tables that can be read without reading a program. A key is written either in the CREATE TABLE or in an ALTER TABLE afterwards, and both are read here.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Db2ForeignKeys
ColumnDescription
ConstraintThe name the DDL gives the relationship, empty where it names none. This is the name a -904 or a load utility message reports, so it is worth carrying even though nothing joins on it.
TableThe child table, the one holding the key, as the CREATE TABLE that creates it names it — or as the key names it where nothing here creates one.
ColumnsThe child's columns, in key order.
Referenced tableThe parent table the key points at.
Referenced columnsThe parent's columns, in key order. The DDL usually leaves these out and means the parent's primary key, and that key is filled in here — a row with a parent and no columns would say less than the DDL does.
Delete ruleWhat DB2 does to the child's rows when a parent row goes away: RESTRICT, CASCADE, SET NULL or NO ACTION. Empty where the DDL leaves it to the default of NO ACTION.
MemberThe DDL member the key is declared in, or the job that declares it in its own stream.
Source pathThe file the key was read from, which is the file to open at the line below.
LineThe one-based line of that file the FOREIGN KEY is written on.
Db2 unloads
io.moderne.mainframe.analysis.table.Db2Unloads

Every unload a job runs, the dialect its control cards are written in, what it unloads and where it writes it, and what it would take to run the same unload on the base Db2 utility.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.Db2Unloads
ColumnDescription
JobThe job name, empty for a member with no JOB card.
MemberThe JCL member the job was read from.
Source pathThe file the job was read from, which is the file to open at the line below.
LineThe one-based line of the EXEC card written in that member. A step a procedure supplies has no line in the job, so it is the calling card that is given — the card a transformation would be applied to.
StepThe step name, qualified by the step that called its procedure — UNLHST.UNL.
ProgramThe program the step names on PGM=, with its symbols filled in. It does not say which engine runs: the unload product reads three vendors' dialects through one program name of its own, and a shop may alias the base utility's program to the product's compatibility entry point.
DialectThe language the control cards are written in: HIGH_PERFORMANCE_UNLOAD for the unload product's own, BASE_UTILITY for the one the Db2 utilities read. This, and not the program name, is what says which engine runs.
Proven byWhat in the deck settled the dialect — the SELECT and OUTDDN of the product, the FROM TABLE or SHRLEVEL of the base utility — and, where the program name says otherwise, that it does.
DeckThe control card member the cards are written in, or the JCL member for a deck written in the job stream.
Deck pathThe file that member was read from, empty where the member was named but not supplied.
Deck lineThe one-based line of that file the UNLOAD statement is written on.
CardsWhere the cards are written: IN_STREAM in this member's own job stream, PROCEDURE in the stream of the procedure the step calls, MEMBER in the library member the DD names.
Table spaceThe table space unloaded, empty where the deck leaves it to be worked out from the tables the SELECTs name — which an image copy unload does.
TablesThe tables the rows come from, separated by , : one per SELECT in the product's dialect, one per FROM TABLE in the base utility's.
SelectsHow many SELECT or FROM TABLE blocks the unload writes. More than one is one pass over the table space fanned out to several files, and the base utility needs a statement and a pass each.
Output DDsEvery DD the rows are written to. The product has no default and every deck names its own; the base utility defaults to SYSREC, so these names are written twice — once here and once in the JCL — and a change to either has to be a change to both.
Load card DDsEvery DD the generated LOAD cards are written to. The base utility defaults this one to SYSPUNCH. A name here may be a TEMPLATE of the deck rather than a DD of the job.
Copy DDThe DD an image copy is read from instead of the table space, empty where the unload reads the table space. LAST_IC or a negative number is a catalog search the base utility does not do.
FormatsThe layout each SELECT writes. A SELECT that codes none is not listed, because what it writes is then a site setting rather than something the deck says.
AccessHow the rows are read: NO off the data sets outside Db2, FORCE through a dynamic cursor, YES for either as the SQL allows. The bytes written are not the same across the three. Empty where the deck leaves it to the site parmlib.
ConsistencyWhat the deck says about reading a table space somebody else may be writing — LOCK YES QUIESCE YES in the product's dialect, SHRLEVEL REFERENCE in the base utility's. The two are not one for one: only LOCK YES QUIESCE YES, and LOCK YES under DB2 FORCE, are documented as ensuring consistency.
VerdictHow far the step reads, from FindExecutionPaths: RESOLVED, INHERITED where a keyword comes from the site parmlib, UNRESOLVED where a name was not followed at all.
MigrationWhat it would take to run this unload on the base utility: ALREADY_THE_TARGET for a deck already written in its language, MAPS_KEYWORD_FOR_KEYWORD where IBM's own option table covers every keyword, NEEDS_REDESIGN where it does not, NOT_DECIDABLE where the source does not say enough to judge.
EvidenceWhy that verdict, separated by ; — the keywords the mapping covers, the constructs it does not, or the reasons the path could not be read. A verdict nobody can check is a verdict nobody will act on.
Control-M schedule
io.moderne.mainframe.analysis.table.ControlMSchedule

Every job the scheduler runs, with the JCL member it submits. A JCL member says what a job does and nothing anywhere else says when it runs, out of which library the member is taken, or under which table and application it is ordered — so this is the far end of the batch estate, and the row carries the definition as written for the Scheduler Info report.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ControlMSchedule
ColumnDescription
JobThe name the scheduler knows the job by. A table is a job too, and carries its own scheduling days and conditions.
TableThe table the job is ordered in, which is the folder it is written under in an export and the panel's GROUP field otherwise. A table names itself.
SMART tableWhether that table is a SMART table — one ordered, held and rerun as a unit, and so worth a containment edge — rather than a plain folder. Two folders of the same name, one of each kind, is a real export; nothing but this tells their jobs apart. A panel says which table a job is in but not what kind, so a job read from one always answers false, and so does a table itself.
GroupThe group the definition names for itself: the panel's GROUP, the export's SUB_APPLICATION. The panel writes one field where the export writes two, so on a panel this is the table again.
Member nameThe JCL member submitted, from MEMNAME. Empty for a table, which runs the jobs under it rather than a member of its own.
Member libraryThe library the member is taken from, from MEMLIB. Two applications routinely schedule a member of the same name out of different libraries.
ApplicationThe application the job is ordered under.
Task typeJob for a member submitted to JES, SMART Table for a table, and a dozen others for the work the scheduler does itself.
CalendarsThe calendars the scheduling days are validated against, each as the kind of decision it makes and the calendar name: CONFIRMATION says which days the job may run on at all, DAYS and WEEK which of the days written apply.
JCL pathThe file the member was read from, empty where no member of that name was read. A schedule for a member nobody supplied is how a gap in an ingestion shows.
Definition pathThe file the definition was written in: the export, or the member holding the one panel.
Definition lineThe one-based line of that file the definition begins on.
DefinitionThe definition as written, which is what the Scheduler Info report shows. A table carries its jobs inside it, so a table's own definition is its opening tag.
Control-M dependencies
io.moderne.mainframe.analysis.table.ControlMDependencies

Which job the scheduler runs before which, one row per pair. Nothing in a schedule names another job: a job adds a condition when it ends and another job waits for that name, so the order the night runs in is only readable by joining the two — and the join holds across tables and across applications without either side saying so.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ControlMDependencies
ColumnDescription
PredecessorThe job that adds the condition, which is the one that has to end first.
Predecessor tableThe table the predecessor is ordered in.
Predecessor pathThe file the predecessor's definition was written in.
Predecessor lineThe one-based line of that file the predecessor's definition begins on.
SuccessorThe job that waits for the condition.
Successor tableThe table the successor is ordered in.
Successor pathThe file the successor's definition was written in.
Successor lineThe one-based line of that file the successor's definition begins on.
ConditionThe name both jobs write and neither explains. Shops name it after the predecessor, which is convention rather than syntax — a chain whose names do not follow it still runs in this order.
Order dateThe run the successor asks for the condition on: ODAT for today's, PREV for the one before, which is how a job waits on the work of the night before rather than on tonight's.
Across tablesWhether the two jobs are ordered in different tables. A chain inside one table is what an operator sees on one screen; one that leaves it is the dependency nobody remembers is there.
Control-M calendars
io.moderne.mainframe.analysis.table.ControlMCalendars

The days each calendar has, a row per year it carries. A schedule writes the days a job is a candidate to run on and the calendar decides which of those the shop is open for, so the days a job really runs are only readable by decoding the year as exported: twelve months of thirty-one positions, Y or N, a position past the end of a month being N.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ControlMCalendars
ColumnDescription
CalendarThe name the schedules refer to it by.
TypeRegular for a calendar of dates, Periodic for one whose days are named periods, Rule Based for one generated from a rule.
Data centerThe Control-M data center the calendar is defined in. The same name is routinely defined in several, with different days in each.
YearThe year these days are in, or 0 for a calendar carrying no year — which is either a rule-based one or, where no file defines it at all, a gap in what was supplied.
DaysHow many days of that year the calendar has.
DatesEvery day the calendar has, in order, as ISO dates. This is what turns "runs on CLMWORK" into the year calendar of execution days.
Definition pathThe file the calendar was defined in, empty where a schedule names one no export defines.
Definition lineThe one-based line of that file the definition begins on.
Build order
io.moderne.mainframe.analysis.table.BuildOrder

Every order the build requires between two jobs, with what the scheduler does about it. A link-edit deck that includes an object binds whatever the object library held when the binder ran, so the job that compiles the object has to have run first — and no one file says so: the deck names a member, the JCL names the library it is written to and read from, and only the scheduler can make one job wait for another.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.BuildOrder
ColumnDescription
ModuleThe load module whose deck requires the order.
DeckThe link-edit deck that includes the object. A deck written in a job stream is that job.
Deck lineThe one-based line of the deck the INCLUDE card is on.
ObjectThe member the card includes, which is the compiled subroutine, map set or assembler object bound into the module.
Object data setThe library member the include resolves to, from the DD the card names as the linking step allocates it. This is what joins the deck to the job that writes the object.
Producer jobThe job that writes the object, which is the one that has to run first.
Producer stepThe step of that job, on whose SYSLIN or SYSLMOD the object is written.
Producer schedulesThe scheduler's jobs that submit the producing member, comma separated. Empty where nothing schedules it.
Consumer jobThe job that link-edits the module, which is the one that has to run second.
Consumer stepThe step of that job that reads the deck.
Consumer schedulesThe scheduler's jobs that submit the consuming member, comma separated. Empty where nothing schedules it.
EnforcementENFORCED where the consumer waits on a condition the producer adds, ENFORCED_THROUGH where the conditions in between impose the order anyway, MISSING where both are scheduled and neither waits for the other, UNSCHEDULED where one of them has no schedule at all, and SAME_JOB where one job does both and its own step order decides it.
Enforced throughThe jobs the order runs through where no condition joins the two directly, producer first: CLMASMB > CLMCMPC > CLMCMPI. Empty for every other verdict.
Schedule coverage
io.moderne.mainframe.analysis.table.ScheduleCoverage

Every job of the JCL library with the schedules that order it. A JCL member says what a job does and never says when it runs, so a member with no schedule is one somebody submits by hand, or one nothing runs at all — and either way it is outside everything the operations side of the estate is documented and monitored by.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ScheduleCoverage
ColumnDescription
JobThe JCL member, which is the name a schedule's MEMNAME writes.
Source pathThe file the job was read from.
SchedulesThe scheduler's jobs that submit this member, comma separated. A member two applications order is submitted by a job of each.
TablesThe tables those jobs are ordered in, comma separated, which is where an operator looks for them.
DefinitionsThe files the schedules were read from, comma separated. A shop that supplies both the panel and the export supplies each job twice.
VerdictORDERED, or UNSCHEDULED for a job no schedule submits.
IMS segment access
io.moderne.mainframe.analysis.table.ImsSegmentAccess

Every DL/I call with the database it reaches, which the COBOL never names: the call gives a PCB and the PSB turns that into a database, and only then does the segment name mean something.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ImsSegmentAccess
ColumnDescription
ProgramThe program making the call.
ParagraphThe paragraph or section the call is in.
InterfaceCBLTDLI, AIBTDLI, CEETDLI, PLITDLI or EXEC DLI. Which one it is decides how the PCB is named: by position in the entry list, by PCBNAME in the AIB, or by number among the database PCBs.
FunctionThe DL/I function, such as GU, GN, ISRT, REPL or DLET.
CRUDCREATE, READ, UPDATE, DELETE, CHECKPOINT or SYSTEM, from the function.
PSBThe PSB the program runs under, empty where nothing says which one. A batch program's PSB is on the PARM of the region step; a message driven program's is the APPLCTN macro of the stage 1 deck.
PCBThe PCB as the PSB names it — its PCBNAME, else the PSB and the position, written CLMPSB02(3).
PCB positionThe PCB's one-based position among the PSB's PCB statements, or zero where it did not resolve. This is not the mask: an I/O PCB is a mask and not a PCB statement.
MaskThe one-based position of the PCB in the program's entry list, or zero for a call that names its PCB rather than counting to it.
ReachesSEGMENT for a database call, MESSAGE_QUEUE for the queue or the scratchpad, LOG for a checkpoint or restart, SEQUENTIAL for a GSAM record, UNRESOLVED where no PSB answered for the PCB.
DatabaseThe IMS database the PCB opens, empty where the PCB is not a database one or did not resolve. This is the column nothing in the COBOL carries.
Index databaseThe secondary index the PCB's PROCSEQ walks the roots in, empty where it has none. A call through such a PCB reaches the database through the index.
SegmentsThe segments the call's search arguments name, space separated. A path call names several and reaches them all in the one call.
Source pathThe program's file.
LineThe one-based line the call is written on.
IMS chain
io.moderne.mainframe.analysis.table.ImsChain

One row per path from something that starts a program to a database it may reach: a transaction code or a job step, the program, the PSB it runs under, one PCB of that PSB, and the database and segments behind it.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ImsChain
ColumnDescription
Start kindTRANSACTION where a message schedules the PSB, JOB_STEP where a region step runs it.
StartThe transaction code, or the job.
StepThe job step, empty for a transaction.
ProgramThe program the region loads, empty where nothing in the estate says which one. A batch region takes it on the PARM beside the PSB; a message region loads the module named for the PSB, so which program that module holds is the link-edit deck's to say.
Program pathThe program's file, empty where it was not read here.
PSBThe PSB, which is what turns a PCB position into a database.
PSB pathThe PSB's file, empty where no gen source for it was read.
PCBThe PCB as the PSB names it — its PCBNAME, else the PSB and the position.
PCB positionThe PCB's one-based position among the PSB's PCB statements.
PCB typeDB for a database PCB and GSAM for a sequential one. Message PCBs get no row: they reach the terminal network rather than a database.
Processing optionsThe PROCOPT the PCB opens the database with, which is what says whether the path is a read or a write.
DatabaseThe IMS database the PCB opens.
Database pathThe DBD's file, empty where no gen source for it was read.
Index databaseThe secondary index named on PROCSEQ, empty where the PCB has none.
Sensitive segmentsThe segments the PSB lets the program see through this PCB, space separated. GSAM has none.
SegmentsThe segments the program's calls through this PCB actually name, space separated. Narrower than the sensitive list wherever a program is given more than it uses, and empty where the program was not read.
IMS databases
io.moderne.mainframe.analysis.table.ImsDatabases

One row per DBD: how it is organised, the DD names a job has to supply for it, and what it holds.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ImsDatabases
ColumnDescription
DatabaseThe DBD name, which is what a PCB's DBDNAME and a stage 1 DATABASE macro name it by.
OrganizationHDAM, HIDAM, HISAM, INDEX, GSAM or LOGICAL — the first operand of ACCESS, which says how a segment is found.
Access methodThe operating system access method under it, VSAM or BSAM, from the second operand of ACCESS.
RandomizerThe RMNAME module an HDAM database hashes its root keys with, empty for every other organization.
DD namesThe DD names the DATASET statements ask for, space separated. This is also an edge to every job step that runs against the database, since the step has to supply them.
Root segmentThe segment with no parent, empty for GSAM, which has no segments at all.
SegmentsHow many segments the DBD defines.
FieldsHow many FIELD statements it defines across those segments.
Record lengthsThe RECORD lengths of a GSAM or HISAM data set group, space separated, empty where none is written.
ReferencesThe other databases this one names and why, written LOGICAL_PARENT CLMDBD02.POLROOT, space separated. A logical relationship and a secondary index are the only ways one DBD names another.
Source pathThe gen source the DBD is written in.
LineThe one-based line of the DBD statement.
IMS segments
io.moderne.mainframe.analysis.table.ImsSegments

The segment hierarchy of each DBD: the parent, the length, the sequence field and the fields with their offsets, which is the layout the copybook a program reads it into has to agree with.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ImsSegments
ColumnDescription
DatabaseThe DBD the segment belongs to.
SegmentThe segment name, which is what a search argument's first eight bytes carry.
ParentThe physical parent, empty for the root.
LevelHow far down the hierarchy the segment sits, 1 for the root.
BytesThe BYTES length, which is the length of the I/O area a program reads it into — unless the PCB is field sensitive, in which case the SENFLD list is.
Sequence fieldThe field the segment is keyed on, empty where it has none.
Sequence startThe one-based byte the sequence field starts at, zero where there is none.
Sequence lengthHow many bytes the sequence field is, zero where there is none.
UniqueWhether the sequence field is unique, which is what decides whether two occurrences can share a key.
FieldsEvery FIELD of the segment, written CLMKEY 1(10) with a type where one is given, space separated and in source order.
Logical parentThe segment in another database this one is the logical child of, written CLMDBD02.POLROOT, empty where it is not one.
Logical childrenThe logical children pointed at from here, space separated. Written on the parent's side, which is the side a reader of the DBD sees first.
Secondary indexesThe indexes built over this segment, written CLMDBX01.CLMXSEG on CLMXADJ, space separated. The XDFLD says which field is indexed and the LCHILD says which database holds the index.
Source pathThe gen source the segment is written in.
LineThe one-based line of the SEGM statement.
IMS field-sensitive I/O areas
io.moderne.mainframe.analysis.table.ImsFieldSensitiveAreas

What a field-sensitive PCB hands a program, against the copybook the program reads it with. Where a PCB carries SENFLDs the I/O area is not the segment: it holds those fields, at those offsets, and a program using the whole segment's layout reads every field after the first omission out of the wrong bytes.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ImsFieldSensitiveAreas
ColumnDescription
ProgramThe program making the call.
PSBThe PSB the program runs under.
PCBThe PCB as the PSB names it — its PCBNAME, else the PSB and the position, written CLMPSB02(2).
SegmentThe segment the SENSEG names, which is the one the call asks for.
Sensitive fieldsThe SENFLDs in the order they build the area, each with the byte it starts at: CLMKEY 1 CLMPOL 11. A field of the segment that is not here is not in the area.
Expected bytesHow long the area is: the last SENFLD's start plus the length the DBD gives that field. Zero where a SENFLD names a field the DBD does not.
I/O areaThe data item the call moves the segment into.
CopybookThe copybook that declares the I/O area, empty where the program declares it itself.
Copybook bytesHow many bytes that declaration describes, zero where it cannot be laid out.
VerdictMATCH where the copybook is the length the SENFLDs build, DIFFERENT_LENGTH where it is not, UNKNOWN where one of the two lengths could not be worked out.
Source pathThe program's file.
LineThe one-based line the call is written on.
Screen fields
io.moderne.mainframe.analysis.table.ScreenFields

Every field of every screen, where it is drawn and which COBOL data item reaches it. CICS generates a symbolic map the program moves values into, and IMS supplies an area the program lays a copybook over, so the two halves are joined differently and both are here.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ScreenFields
ColumnDescription
TechnologyBMS for a CICS map set, MFS for an IMS format set.
Map set or format setThe DFHMSD for BMS, the FMT for MFS.
Map or pageThe DFHMDI for BMS, the DPAGE for MFS. A format set with two device pages carries the same labels twice at different positions, which is why the page is part of what names a field.
Message or recordFor MFS, the MSG that carries the field — the MID it arrives on or the MOD it goes out on. For BMS, the symbolic map record the program's item is declared in. Empty for a field no message and no program reaches.
FieldThe label the map set or format set gives the field. Empty for a literal written straight onto the screen, which no program can name.
RowThe line the field starts on, counted from one. Zero where the definition gives no position, which is what a message field carrying a literal does.
ColumnThe column the field starts at, counted from one. BMS counts the attribute byte here and paints the data from the next column; MFS counts the first byte of the data itself.
LengthHow many characters the field occupies on the screen, or how many bytes it occupies in the message where it is only in the message.
AttributesHow the field is drawn and whether it can be typed into, space separated and as the definition writes them: ASKIP NORM for BMS, PROT HI for MFS.
Initial value or literalThe text the field is drawn with whatever the program does, from BMS INITIAL= or the MFS literal. Padding is kept, because it is what decides how wide the field is.
ProgramThe COBOL program that reaches the field. Empty where nothing analysed does, which for a labelled field is worth reading twice.
Data itemWhat the program calls the field. For BMS this is the generated item the program names — TITLEO and TITLEL are the same field. For MFS the program names nothing, so this is the copybook item lying at the field's displacement, matched by order and length and never by name.
Subfield or offsetFor BMS which part of the field the item is: OUTPUT carries the value, LENGTH says how much the operator typed, COLOR how it is drawn. For MFS the field's displacement in the message area, counted from zero and past the four byte prefix IMS supplies and no MFLD describes.
Source pathThe map set or format set the field is defined in.
LineThe one-based line of the DFHMDF or DFLD.
Screen lines
io.moderne.mainframe.analysis.table.ScreenLines

Each screen as the terminal paints it, one row per line: the literals where they are written and an underscore for every character the program supplies. This is what a green screen viewer draws, and what makes a map set readable without a terminal.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ScreenLines
ColumnDescription
TechnologyBMS for a CICS map set, MFS for an IMS format set.
Map set or format setThe DFHMSD for BMS, the FMT for MFS.
Map or pageThe DFHMDI for BMS, the DPAGE for MFS.
DeviceWhat the screen is drawn on: the BMS TERM=, or the MFS DEV TYPE= with its model. A printer is laid out the same way and is not a screen anybody types into.
RowsHow many lines the screen holds: 12 for a model 1, 24 for a model 2, or the BMS SIZE=. Where the device says nothing, the last line a field is on.
ColumnsHow many characters wide the screen is, which is what a BMS POS=n displacement is counted against.
RowWhich line of the screen this is, counted from one.
TextThe line as it is painted: literals in place, an underscore for every character a field supplies, and a blank everywhere the map writes nothing. Trailing blanks are kept so the columns line up.
Source pathThe map set or format set the screen is defined in.
Record layouts
io.moderne.mainframe.analysis.table.RecordLayouts

The same record described in two languages, field by field, with where the two descriptions disagree.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.RecordLayouts
ColumnDescription
RecordThe layout being compared: the control section of an assembler DSECT, or the member whose INPUT statement reads the record for SAS.
LanguageASSEMBLER or SAS: which language wrote the description being compared with the COBOL one.
Source pathThe file the description is in.
LineThe line the description starts on.
Compared withThe COBOL record: the copybook that declares it, or the program where it is declared in an FD and in no copybook at all.
Compared pathThe file the COBOL record is declared in.
OffsetWhere the field starts, counted from zero at the start of the record.
FieldThe field as the other language names it, empty where it describes nothing at this offset.
BytesHow many bytes the other language gives the field, 0 where it describes none.
COBOL fieldThe field the COBOL record has at that offset, empty where it has none.
COBOL bytesHow many bytes the COBOL record gives it, 0 where it has no field there.
AgreementMATCH where both put a field of the same length at the same byte, DIFFERENT_LENGTH where they start one at the same byte and disagree about its length, MISSING where the COBOL record does not describe the bytes, and NOT_READ where it describes bytes the other language leaves alone.
Run book coverage
io.moderne.mainframe.analysis.table.RunBookCoverage

Every program and job of the portfolio with the run book member that documents it, and every run book with the component it is about.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.RunBookCoverage
ColumnDescription
ComponentThe program, job or data set: the PROGRAM-ID, the JCL member name, or the data set name a DOCFICH carries on its FILE line.
Component typeWhat the component is, in the relationship model's vocabulary: COBOL, ASSEMBLER, SAS, JCL or DATA_SET.
Source pathThe file the component is in, or empty where nothing in the portfolio answers to the name.
Run bookThe documentation member, or empty where none documents the component.
ShapeWhich kind of run book it is, from its own first word: DOCJOB, DOCPGM, DOCFICH, DOCAPPL or DOCOPER.
Run book pathThe file the run book is in.
VerdictDOCUMENTED, UNDOCUMENTED for a component no run book is about, or SUBJECT_MISSING for a run book whose subject nothing answers to.
Names resolvedHow many of the names the run book writes down are components of the portfolio. A run book is prose, so what it mentions over-answers until it is looked up; this is what survived the lookup.
Environment copies
io.moderne.mainframe.analysis.table.EnvironmentCopies

The same member held in more than one environment's libraries, and whether the copies still agree. Read from one copy's side, so a member promoted through three environments has a row from each of the three to each of the other two.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.EnvironmentCopies
ColumnDescription
MemberThe member name both copies answer to.
Component typeWhat the member is, in the types of ComponentIndex. Empty for a plain text member no DD names, which the portfolio has no type for.
EnvironmentThe environment this copy is held in, as the segment of its path that names one: SLPROD, PREPROD, PROD.
Source pathThis copy's file.
Owning applicationThe application whose library this is, where the layout says which segment names it. Empty where an environment holds one library for the whole site, which is what the default layout reads.
Other environmentThe environment the copy this row compares against is held in.
Other source pathThat copy's file.
ComparisonIDENTICAL where the two are the same line for line, ENVIRONMENT_NAMES where a bind deck differs only in the subsystem, collection and DBRM library it binds on, and DIVERGED where they differ anywhere else. Only the last is drift somebody has to answer for.
Differing linesHow many of this copy's lines the other copy has not. Lines are matched wherever they sit, so a card moved is not a difference and a card changed is one on each side. Counted as written, so a bind deck bound on another subsystem has differing lines and no drift.
Column lineage
io.moderne.mainframe.analysis.table.ColumnLineage

Which input field feeds each field the program writes out, in the shape OpenLineage's column lineage facet asks for, with the statement that did it.

Export after a run
mod study . --last-recipe-run \
--data-table io.moderne.mainframe.analysis.table.ColumnLineage
ColumnDescription
ProgramThe PROGRAM-ID, which is the job the lineage belongs to.
Source pathThe program's file, which the offsets below index into.
Input namespaceThe technology the value came in through, as a scheme: cics://file, ims://segment, sql://table, file://record and so on. The kind is in the namespace rather than the name because a CICS file and a CICS queue can share one. Empty when nothing outside the program feeds the field.
Input datasetThe resource the value came from, or the kind of endpoint where the statement names none. A screen is named mapset.map, which is what identifies it across an estate; a program that decides at run time which map it sends still gets the map it sent, read off the record BMS generated.
Input fieldThe field the value landed in when it entered the program, qualified by the records containing it — or, where the resource has its own name for it, that name: the column a SELECT read, or the screen field an operator typed into.
Output namespaceThe technology the value goes out through, in the same scheme form as the input.
Output datasetThe resource written, named the same way as the input.
Output fieldThe field whose value crossed the boundary. A row about a screen names the field the mapset declares rather than the data item BMS generated from it, so TRNNAMEO reads as TRNNAME. The length, flag and attribute bytes of a screen field drive the terminal rather than carrying a value, and are not rows.
Transformation typeAlways DIRECT. A field only tested in a condition moves no value and is never an edge, so this analysis never has the INDIRECT kind to report.
Transformation subtypeIDENTITY when every step along the route only copies the value, TRANSFORMATION when arithmetic, STRING or UNSTRING changed it.
StepsHow many statements the value passes through, counting the one that brought it in and the one that wrote it out. One means it was read and written by a single statement.
PathThe route the value takes, statement by statement. This is what makes the answer reviewable rather than something to be taken on trust.
Output lineWhere the statement that wrote the value out begins, one-based.
Output columnThe column that statement begins at, one-based. Sequence numbers and the identification area are not part of it.
Output start offsetThe statement's first character, as an index into the source file. This is what a catalog that highlights the code it is describing asks for.
Output end offsetOne past the statement's last character. Zero, with the offset and line, when a copybook wrote the statement and it has no position in this program.
Input lineWhere the statement that brought the value in begins, one-based. A program often reads the same table twice, and without this the two rows differ in nothing a reader can see.
Input start offsetThat statement's first character, as an index into the source file.
Input end offsetOne past that statement's last character. Zero when the value came from nowhere outside the program, or the statement was written by a copybook.
Context registry
org.openrewrite.prethink.table.ContextRegistry

Registry of available context files for coding agents.

Export after a run
mod study . --last-recipe-run \
--data-table org.openrewrite.prethink.table.ContextRegistry
ColumnDescription
Display nameThe display name of the context.
Short descriptionA brief description of what context this provides.
Context filePath to the markdown file describing this context.
Source files that had results
org.openrewrite.table.SourcesFileResults

Source files that were modified by the recipe run.

Export after a run
mod study . --last-recipe-run \
--data-table org.openrewrite.table.SourcesFileResults
ColumnDescription
Source path before the runThe source path of the file before the run. null when a source file was created during the run.
Source path after the runA recipe may modify the source path. This is the path after the run. null when a source file was deleted during the run.
Parent of the recipe that made changesIn a hierarchical recipe, the parent of the recipe that made a change. Empty if this is the root of a hierarchy or if the recipe is not hierarchical at all.
Recipe that made changesThe specific recipe that made a change.
Estimated time savingAn estimated effort that a developer to fix manually instead of using this recipe, in unit of seconds.
CycleThe recipe cycle in which the change was made.
Source files that had search results
org.openrewrite.table.SearchResults

Search results that were found during the recipe run.

Export after a run
mod study . --last-recipe-run \
--data-table org.openrewrite.table.SearchResults
ColumnDescription
Source path of search result before the runThe source path of the file with the search result markers present.
Source path of search result after run the runA recipe may modify the source path. This is the path after the run. null when a source file was deleted during the run.
ResultThe trimmed printed tree of the LST element that the marker is attached to.
DescriptionThe content of the description of the marker.
Recipe that added the search markerThe specific recipe that added the Search marker.
Source files that errored on a recipe
org.openrewrite.table.SourcesFileErrors

The details of all errors produced by a recipe run.

Export after a run
mod study . --last-recipe-run \
--data-table org.openrewrite.table.SourcesFileErrors
ColumnDescription
Source pathThe file that failed to parse.
Recipe that made changesThe specific recipe that made a change.
Stack traceThe stack trace of the failure.
Recipe performance
org.openrewrite.table.RecipeRunStats

Statistics used in analyzing the performance of recipes.

Export after a run
mod study . --last-recipe-run \
--data-table org.openrewrite.table.RecipeRunStats
ColumnDescription
The recipeThe recipe whose stats are being measured both individually and cumulatively.
Source file countThe number of source files the recipe ran over.
Source file changed countThe number of source files which were changed in the recipe run. Includes files created, deleted, and edited.
Cumulative scanning time (ns)The total time spent across the scanning phase of this recipe.
Max scanning time (ns)The max time scanning any one source file.
Cumulative edit time (ns)The total time spent across the editing phase of this recipe.
Max edit time (ns)The max time editing any one source file.