The 7-Phase Discovery Playbook
| Field | Value |
|---|---|
| Type | Skill Resource |
| Source | ~/.copilot/skills/architecture/references/discovery/discovery-playbook.md |
| Description | Not specified |
Source Content
The 7-Phase Discovery Playbook
The full method for reverse-engineering a legacy system before you modernize it. Each phase has a goal, inputs, how AI accelerates it, an output artifact, pitfalls, and a definition-of-done checklist. Run the phases in order — the later ones depend on the earlier ones existing. Platform specifics live in the three decoders, linked per phase; this file never restates them.
Contents
- Two ways to start a modernization
- Phase 1 — Inventory
- Phase 2 — Data model
- Phase 3 — Business rules
- Phase 4 — Dependencies and schedule
- Phase 5 — Test generation
- Phase 6 — Documentation
- Phase 7 — Decide
- Running this safely with an AI
Two ways to start a modernization
Jack, an agency CIO, inherited a 30-year-old benefits system and a board that wanted it “in the cloud by next year.” His team started where it felt productive — converting the RPG to Java, module by module. The conversion passed its unit tests, shipped, and then the first month-end run paid the wrong benefit amounts: a rounding rule lived in a data area nobody had read, and a nightly job had to finish before a federal feed at 6 AM that the rewrite ran hours late. The rules, the data quirks, and the timing were discovered in production, which is the most expensive place to discover them.
Jill, a tech lead at a peer agency, spent the first two months not writing any target code at all. She pointed AI at discovery: an inventory, a decoded data model, a rule catalog with line citations, a batch-job DAG, and golden-master tests that pinned the legacy output. When her team finally rewrote a subsystem, they ran it against the golden masters and caught the rounding rule on day one — before a single claimant saw a wrong check.
Same destination, a fraction of the risk. This playbook is Jill’s path.
Phase 1 — Inventory
Goal
Know the shape of the system — every artifact classified by type and counted — before spending context on any single program.
Inputs
- The exported source repository (or a file listing if source is on the live box).
- The platform family, so you read extensions against the right cheat sheet.
How AI accelerates it
Run the deterministic pass first, then let AI classify only what the script could not.
- Run
scripts/inventory.py <repo>. It walks the tree, classifies by extension against the decoder cheat sheets, and emits a Markdown table plus a CSV. Deterministic code is faster and more reliable than AI for counting and grouping files. - Hand AI only the residue — files with missing, wrong, or ambiguous extensions. AI reads the first few lines and classifies by content (the “first line decides it” tells in each decoder).
- Ask AI to spot the gaps, not just the contents: a system with programs but no display files, or copybooks with no matching programs, means source is missing — a finding in itself.
Here is the deterministic inventory table from scripts/inventory.py, plus thefirst 20 lines of each file the script tagged "unknown". For each unknown file,classify it by content (program / copybook / DDS / JCL / display / other) andname the tell you used. Then list any structural gaps: artifact types you'dexpect for this platform that are absent, and orphans (e.g. copybooks no programCOPYs, display files no program opens). Do not summarize what any program does yet.Output artifact
A per-file inventory table (path, classified type, size, notes) plus counts by type, and a short “gaps and orphans” list. This is the first section assembled into the onboarding doc.
Pitfalls
- Trusting extensions blindly. Teams rename inconsistently on export; confirm ambiguous files by content (see each decoder’s file-extension cheat sheet).
- Skipping the deterministic pass and asking AI to “list all the files.” AI miscounts and hallucinates entries; the script does not.
- Treating “unknown” as noise. An unclassifiable member is often the interesting one — a custom command, a binder source, an assembler stub.
Definition of done
- The inventory count matches the repo file count; nothing is silently dropped.
- Every file has a type, or a note explaining why it could not be classified.
- Gaps and orphans are listed, not assumed away.
- The platform family (or families) is confirmed from real files, not the ticket.
Phase 2 — Data model
Goal
Turn the record layouts into a logical ERD and a field dictionary, with the storage gotchas resolved — so later phases read code against the data, not cold.
Inputs
- Physical files / copybooks / DB2 DDL / VSAM cluster definitions from phase 1.
- The matching decoder: DDS PF/LF from IBM i; copybooks and PIC/USAGE from mainframe COBOL; COMMAREA/map layouts from CICS.
- A live catalog or data dictionary if one is reachable, to validate the reverse-engineered model.
How AI accelerates it
Decode the data before the logic. The record layout tells you what a program is about; the code tells you what it does to that data.
- Feed AI one layout at a time (one copybook, one PF) and ask it to produce a field dictionary: name, type, length, decimals, key role, and the decoded storage. The gotcha catalog — packed decimal, zoned/overpunch, implied decimal, EBCDIC,
REDEFINES,OCCURS, reference fields — lives inreferences/data-model-extraction.md. - Ask AI to infer relationships from shared keys: a claim number that keys both the claim master and the payment file is a foreign-key edge. Mark inferred edges as inferred.
- If a live catalog is reachable, validate: compare AI’s field list to
QSYS2.SYSCOLUMNS(IBM i) orSYSIBM.SYSCOLUMNS(DB2), and reconcile every difference.
Decode this copybook into a field dictionary. One row per field: name, level,PIC, USAGE, decoded type (e.g. "signed money, 2 implied decimals, packed"),length in bytes, and whether it's a key. Flag every REDEFINES with the conditionthat selects each view, every OCCURS DEPENDING ON, and every field whose rawbytes need decoding (COMP-3, zoned, overpunch, EBCDIC). Cite the line number foreach flag. Do not guess a field's business meaning beyond what the name and 88-levels state.Output artifact
A logical ERD (drawn per the technical-writing skill’s diagram rules; see the ERD pattern in references/mermaid-legacy-patterns.md) plus a field dictionary with the decode gotchas resolved. Full method: references/data-model-extraction.md.
Pitfalls
- Transcribing PIC/DDS instead of decoding it. A
PIC S9(7)V99 COMP-3is 5 bytes of signed packed decimal, not a 12-character string — leaving it raw poisons every downstream extract. - Missing
REDEFINESandOCCURS DEPENDING ON. One layout meaning several things, or a variable-length record, breaks any naive flat extract — and the selecting condition is a business rule for phase 3. - Ignoring reference fields (DDS
REFFLD). A field can inherit its definition from a data dictionary entry that lives in another file.
Definition of done
- Every entity has a decoded field dictionary; no raw PIC or DDS left unresolved.
- Packed/zoned/overpunch/implied-decimal/EBCDIC fields are decoded and labeled.
- Every
REDEFINESrecords its selecting condition; everyOCCURS DEPENDING ONis flagged. - Relationships are drawn, and inferred edges are marked as inferred.
- If a live catalog was available, the model was validated against it and differences reconciled.
Phase 3 — Business rules
Goal
Extract the calculations, validations, and state transitions the business actually runs into a traceable rule catalog — each rule citing the program and line range it came from.
Inputs
- The decoded data model from phase 2 (rules read cold are guesses; rules read against the ERD are findings).
- Program source, prioritized: edit routines, calculation paragraphs/subroutines, and the
88-levels / condition names that name states. - Abend history if available — a rule that guards against dirty data is still a rule.
How AI accelerates it
Follow the data, not the call stack. Business logic clusters around reads, writes, and edit routines; references/business-rule-mining.md says exactly where on each platform.
Before reading anything, rank programs by size (lines) and centrality (inbound call count from the phase-4 call graph, or a quick CALL/EXSR grep if phase 4 is not done yet). Take the top N — five is a sane default — and force an explicit read now or defer, with reason decision on each. The largest, most-called programs are the money-movement engines (COACTUPC, XFRFUN, BCASH00P), and left to default they get inventoried but never opened — the highest-risk logic goes uncatalogued by omission, not by choice. Record each decision in the doc; a deferred engine is an honest open question, an un-decided one is a silent gap.
- Point AI at the high-signal spots: COBOL
88-levels andEVALUATE(a decision table in disguise), RPG edit subroutines and indicator sets,COMPUTE/Z-ADDarithmetic near money fields, and CICSRESP/HANDLE CONDITIONexception paths. - For each rule, require the same shape: name, trigger, inputs (as fields from the phase-2 dictionary), the logic in plain English, the output, and the program plus line range. A rule without a citation is a hypothesis.
- Ask AI to name its confidence and to flag rules that depend on state it cannot see — a data area, an
OVRDBF, a COMMAREA field — so an engineer traces those.
From this program, extract every business rule: eligibility checks, validations,calculations, and status transitions. Use the attached field dictionary for fieldmeanings. For each rule output: name, trigger, input fields, plain-English logic,output/effect, and the exact line range. Convert EVALUATE and decision-table codeinto a condition→outcome table. Mark confidence (high/medium/low) and flag anyrule that reads state not in this file (data area, override, COMMAREA). Quote thesource lines you relied on so I can verify each one.Output artifact
A business-rule catalog — one entry per rule, each traceable to source, with an EVALUATE/decision-table view where the code encoded one. Template and platform-specific hunting guide: references/business-rule-mining.md.
Pitfalls
- Uncited rules. “The system caps the benefit at 26 weeks” is worthless without the program and line that proves it; require the citation.
- Missing rules that live outside the program — in a data area’s value, an
OVRDBFredirect, aCOPY … REPLACING, or a sort control card doing a real transform. - Reading indicator-heavy RPG cold. A flag named
*IN43carries meaning only by convention; trace every indicator to where it is set and tested before writing the rule.
Definition of done
- Every catalog entry cites a program and line range.
- Every entry states trigger, inputs, logic, and output.
- Decision-table code (
EVALUATE, indicator webs) is rendered as a condition→outcome table. - Rules depending on external state (data areas, overrides, COMMAREA) are flagged for an engineer to trace.
- Confidence is marked; low-confidence rules are listed for validation against live data.
Phase 4 — Dependencies and schedule
Goal
Draw what calls what, which jobs read and write which files, when the batch runs, and where the system talks to the outside — the operational map a migration must preserve.
Inputs
- Program-to-program calls (
CALL/CALLP, CICSLINK/XCTL), CLSBMJOB, JCL step order. - File I/O per program (RPG
CHAIN/READ/WRITE, COBOLREAD/REWRITE, JCLDDstatements, CICSFILE()). - The scheduler export (Control-M / CA-7 / TWS) if reachable — it holds the true nightly cycle, worth more than any single program.
- Integration points: data queues, TDQ triggers, external feeds, MQ, FTP.
How AI accelerates it
Build four views, each answering a different operational question.
- Call graph — every cross-program edge. Watch for ILE service programs: a
CALLPmay resolve into a*SRVPGMyou must open separately (see ILE), and CICSXCTLis a transfer with no return, an edge not a call. - File-usage (CRUD) matrix — program on one axis, file on the other, cells marked C/R/U/D. This surfaces the write owner of each table and the read-only consumers.
- Batch-job DAG — job order and dependencies from JCL
COND/scheduler rules, with the timing windows that constrain a migration. - Integration inventory — every point the system touches something outside itself, including the easy-to-miss async ones (data queues, TDQ triggers).
From these JCL jobs and CL programs, build the batch dependency graph. For eachjob: what triggers it, what it reads (DISP=SHR), what it writes (DISP=OLD/NEW),which jobs must finish first, and any hard timing window in comments or thescheduler. Output as an ordered list I can turn into a DAG, and separately flagevery SBMJOB, data-queue send/receive, TDQ trigger, and external feed as anintegration edge. Cite the job/step for each dependency.Output artifact
A call graph, a CRUD file-usage matrix, a batch-job DAG, and an integration inventory (diagrams drawn per the technical-writing skill’s diagram rules and the legacy patterns). Full method: references/dependency-mapping.md.
Pitfalls
- Reading the JCL and ignoring the scheduler. The JCL shows a job’s steps; the scheduler holds the order and the “must finish before 6 AM” constraints. If you can get the scheduler export, prioritize it.
- Missing runtime redirection. An
OVRDBF(IBM i) or aDDoverride changes which file a program really touches — “the code says X, production does Y.” - Missing async integration. A
*DTAQsend/receive or a TDQ that triggers a transaction is a real dependency with no visible network call.
Definition of done
- The call graph resolves service-program and
XCTLedges, not just direct calls. - The CRUD matrix names the write owner of every table.
- The batch DAG shows order, dependencies, and timing windows — drawn, not implied.
- The integration inventory includes async edges (data queues, TDQ triggers) and external feeds.
- Runtime file redirections (
OVRDBF,DDoverrides) are noted where found.
Phase 5 — Test generation
Goal
Produce tests that let a rewrite prove equivalence — golden-master tests that pin current behavior, plus edge cases mined from the code’s own defenses. This is the bridge between “we understand it” and “we can safely replace it.” It has no separate reference file, so the full method is here.
Inputs
- The rule catalog (phase 3) and the decoded data model (phase 2) — every rule is a test target, every field a source of boundary values.
- Real record layouts, so test inputs are byte-accurate (packed decimal, implied decimals, EBCDIC).
- The ability to run the legacy program (or a captured sample of its inputs and outputs) to record the golden master.
- Abend history and edit routines as free edge-case sources.
Golden-master tests: pin the behavior you cannot yet explain
A golden-master (or characterization) test captures what the legacy system does today and asserts the new system does the same — without needing to know why. It is the safety net that lets you rewrite code whose rules you have not fully mined.
flowchart TD subgraph capture["fas:fa-box-archive Capture from legacy"] IN["fas:fa-file-import Real input records"] --> RUNOLD["fas:fa-server Run legacy program"] RUNOLD --> GOLDEN[("fas:fa-lock Golden output — frozen")] end subgraph verify["fas:fa-code-compare Verify the rewrite"] RUNNEW["fas:fa-code Run new program<br/>same inputs"] --> CMP{"fas:fa-equals Output matches<br/>golden?"} end GOLDEN --> CMP CMP -->|"byte-equal"| PASS["fas:fa-circle-check Equivalent"] CMP -->|"differs"| FAIL["fas:fa-triangle-exclamation Rule missed —<br/>go back to phase 3"] classDef a fill:#e8eef7,stroke:#5b7aa8,color:#1a2a3a classDef b fill:#f3ecda,stroke:#b08a3a,color:#3a2e14 classDef ok fill:#e5efe6,stroke:#5a8a5f,color:#1e2e1f classDef bad fill:#f7e8e8,stroke:#a85b5b,color:#3a1a1a class IN,RUNOLD,GOLDEN a class RUNNEW,CMP b class PASS ok class FAIL badWhat to notice: the golden output is frozen from the legacy run, and a mismatch does not send you to debug the new code — it sends you back to phase 3, because a difference means the rewrite is missing a rule you never mined.
How AI accelerates the golden-master build:
- Ask AI to identify representative input records for each rule and status path in the catalog — one input per branch, plus a real-data sample if you have production extracts.
- Have AI generate the harness: feed inputs to the legacy program, capture every output (files written, report lines, status codes, updated fields), and store them as the frozen expected result.
- When the rewrite runs, AI compares output field-by-field, decoding packed/zoned values first so a byte difference is reported as a value difference an engineer can read.
Using the rule catalog and field dictionary, propose a golden-master test set forthis program. For each rule and each status transition, give one representativeinput record (as decoded field values AND the raw byte layout), the legacy outputI should capture, and what a meaningful difference would be. Group tests by therule they exercise. Then write the comparison logic that decodes packed/zonedfields before diffing, so mismatches read as value differences, not byte noise.Edge cases: mine them from the system’s own defenses
The legacy code already tells you where its boundaries are. Four sources, in order of yield:
Edit routines and validations
Every validation in the code implies at least two tests: the value that passes and the value that fails. An RPG edit subroutine or a COBOL IF amount > limit names a boundary — test at the limit, one below, and one above.
88-level condition names
Each 88-level (COBOL) or its RPG/CICS equivalent names a business state with an explicit value set. Test every named value, plus one value outside the set — legacy code often has an undefined-behavior gap for the unexpected value, and the rewrite must match it, quirk and all.
Abend history
A history of S0C7 abends (data exception on packed/numeric data) tells you the real data contains values the rules must tolerate — nulls, spaces in numeric fields, uninitialized COMP-3. Each recurring abend is an edge case the rewrite must handle the same way the patched legacy code does. Abend meanings are in the COBOL decoder.
Boundary values from the data model
The field dictionary hands you boundaries for free: the maximum a PIC 9(5) holds, the sign flip on a signed field, the largest OCCURS index, a date at year-end or a leap day. Generate the min, max, zero, and just-past-max case for every numeric and date field a rule reads.
For each validation and 88-level in this program, generate edge-case tests: thepassing value, the boundary value, one just past it, and (for 88-levels) one valueoutside the named set. Add boundary tests from the field dictionary — field max,zero, sign flip, largest OCCURS index, year-end and leap-day dates. For each test,say which rule or field it targets and what the legacy program is expected to do,citing the line that defines the boundary.Output artifact
A test suite in two parts — golden-master cases (input record + frozen legacy output + decoded comparison) grouped by rule, and edge-case cases grouped by their source (validation, 88-level, abend, boundary). Each test cites the rule or field it exercises. This suite is the acceptance gate for whichever disposition phase 7 chooses.
Pitfalls
- Comparing raw bytes instead of decoded values. A packed-decimal field that differs by encoding but not value will fail a naive byte diff; decode before comparing.
- Testing only the happy path. The rules you have not mined are exactly the ones a golden master catches — but only if the input set covers every branch and real dirty data.
- Freezing a golden master over a bug. The legacy output may be wrong; capture it anyway, mark it, and decide per case whether the rewrite should replicate or fix it. Replicating a known bug is sometimes required for downstream compatibility.
- Byte-inaccurate inputs. A test record with the wrong packing or a stored decimal point does not exercise the real code path; build inputs from the phase-2 layouts.
Definition of done
- Every rule and status transition in the catalog has at least one golden-master test.
- The golden output is captured from the legacy run, frozen, and decoded for comparison.
- Every validation and
88-level has passing, boundary, and out-of-set edge cases. - Abend history and field-dictionary boundaries are mined into tests.
- Test inputs are byte-accurate to the real record layouts.
- Known-bug golden masters are marked, with a replicate-or-fix decision noted.
Phase 6 — Documentation
Goal
Assemble the artifacts into docs/onboard.md — a document a reader who has never seen a green screen can follow to understand the system.
Inputs
- The four load-bearing artifacts: inventory (1), data model (2), rule catalog (3), dependency and schedule maps (4).
- The test suite (5) as evidence the behavior is pinned.
- The glossary, for decoding every platform term on first use.
How AI accelerates it
The document is assembled from compact findings, not generated from raw source. Keep the code reads in the subagents; bring back filled-in artifacts.
- Feed AI the artifacts, not the programs. Ask it to write each section against the onboarding template and to decode every platform term on first use against the glossary.
- Require a two-person story at the top of each explanatory section and a “what to notice” line under every diagram (both per the
technical-writingskill, which now owns the diagram rules). - Have AI write the honest-bounds section: what was not read, not decoded, or assumed — silent gaps read as “fully understood” when they are not.
Assemble docs/onboard.md from these artifacts (inventory, ERD + field dictionary,rule catalog, dependency maps, test suite) using the onboarding template. Write fora reader who has never seen this platform: decode every term on first use againstthe glossary, open each explanatory section with a two-person story from the personaroster, and put a "what to notice" line under every diagram. Add a "what we did notread or decode" section listing the gaps honestly. Do not paste source code; citethe artifact each claim comes from.Output artifact
docs/onboard.md, structured to the section layout in references/onboard-template.md, jargon-decoded and honestly bounded.
Pitfalls
- Generating prose from source instead of from artifacts. That reintroduces raw code into the top thread and produces a summary, not a discovery.
- Leaving jargon undecoded. “The nightly cycle abends on a S0C7” means nothing to the reader the doc is for; decode it.
- Hiding the gaps. An honest “we did not decode the fraud subsystem” is worth more than a confident paragraph that is a guess.
Definition of done
- Every section follows the onboarding template.
- Every platform term is decoded on first use.
- Every diagram has a “what to notice” line; explanatory sections open with a story.
- A “what we did not read or decode” section exists and is specific.
- Every claim cites the artifact (not the source) it came from.
Phase 7 — Decide
Goal
Score each subsystem on the disposition rubric and recommend per subsystem — retire, rehost, re-platform, refactor, rebuild, or replace — grounded in the artifacts, not instinct.
Inputs
- All four load-bearing artifacts (1–4) and the test suite (5). Phase 7 is not reachable without them.
- The disposition rubric factors: data gravity, rule volatility, coupling, latency/SLA class, and COTS fit.
How AI accelerates it
Score, do not vibe. One monolith usually contains a retire candidate, a COTS-replaceable module, and a genuinely custom rules engine that deserves a careful rebuild — a single “rewrite it all” verdict is almost always wrong.
- Break the system into subsystems along the coupling seams the dependency map (phase 4) already found.
- Score each subsystem on the rubric factors, citing the artifact behind each score (data gravity from the CRUD matrix, rule volatility from the catalog, coupling from the call graph).
- Recommend a disposition per subsystem with the factors that drove it, and name the migration pattern (strangler fig, anti-corruption layer, data-first) where relevant. Full rubric:
references/modernization-strategy.md.
Using the dependency map, rule catalog, and CRUD matrix, split this system intosubsystems along its coupling seams. Score each on data gravity, rule volatility,coupling, latency/SLA class, and COTS fit — citing the artifact behind each score.Recommend a disposition per subsystem (retire/rehost/re-platform/refactor/rebuild/replace) with the driving factors, and flag any subsystem where the score is closebetween two options. Do not give one verdict for the whole system.Output artifact
A scored disposition table — one row per subsystem, the rubric factors, the recommendation, and the driving citations. Rubric and migration patterns: references/modernization-strategy.md.
Pitfalls
- One verdict for the whole system. Score per subsystem; the seams are already in the dependency map.
- Scoring on instinct. Every score cites an artifact, or it is a guess dressed as analysis.
- Skipping straight here. If phases 1–4 do not exist, the scores are fiction — see the running-safely rules below.
Definition of done
- The system is split into subsystems along real coupling seams.
- Each subsystem is scored on every rubric factor, with a citation per score.
- Each recommendation names its driving factors and, where relevant, the migration pattern.
- Close calls between two dispositions are flagged, not hidden.
- No single system-wide “rewrite it all” verdict.
Running this safely with an AI
AI is a discovery accelerator, not an oracle. These rules keep it honest and keep the top thread thin (per the delegate-tool-heavy-work standard).
- Keep raw code reads out of the top thread. Delegate per-program reads to subagents that return a filled-in finding — a decoded layout, a rule entry, a dependency edge — not the source. The onboarding doc is assembled from compact artifacts, so the root context stays coherent across a long discovery.
- Chunk large programs. A 10,000-line RPG program will not fit usefully in one read. Split by subroutine or paragraph, extract per chunk, and reconcile — but track which chunks you have not read.
- Always cite the program and line range. Every claim — a rule, an edge, a field decode — names the file and lines it came from. An uncited claim is a hypothesis, and the reader must be able to tell the two apart.
- Mark confidence. High for “the code plainly says this,” low for “this is inferred from a field name.” Low-confidence findings go on a validate-this list, not into the doc as fact.
- Validate against the code and, if available, live data. Reconcile AI’s field list against the live catalog; reconcile inferred rules against production values. AI reading EBCDIC packed decimal from a hex dump is a common failure — check it.
- Never let anyone jump to phase 7 before 1–4 exist. A disposition scored without an inventory, a data model, a rule catalog, and a dependency map is a guess with a table around it. Phases 1–4 are the load-bearing archaeology; the decision only means something once they are filled.