Start Today

← Documentation

Matching Buffers to COBOL REDEFINE Structures

{`

<!DOCTYPE html>

<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>COBOL REDEFINE Matching Strategies — Documentation</title> <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Source+Serif+4:ital,opsz,wght@0,8..60,300;0,8..60,400;0,8..60,600;0,8..60,700;1,8..60,400&family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet"> <style> :root { --ink: #1a1a2e; --paper: #f8f6f1; --accent: #c45d3e; --accent-light: #f0d5cb; --accent-dark: #9a3a20; --green: #2d6a4f; --green-light: #d4edda; --amber: #b8860b; --amber-light: #fff3cd; --blue: #2c5282; --blue-light: #d0e4f5; --gray-100: #f3f1ec; --gray-200: #e8e4dd; --gray-300: #d1cdc6; --gray-400: #9e9a93; --gray-500: #6b6761; --mono: 'IBM Plex Mono', monospace; --serif: 'Source Serif 4', Georgia, serif; --sans: 'DM Sans', sans-serif; }

  • { margin: 0; padding: 0; box-sizing: border-box; }

body { font-family: var(--serif); background: var(--paper); color: var(--ink); line-height: 1.7; font-size: 17px; -webkit-font-smoothing: antialiased; }

/* --- NAV --- */ .topbar { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(248,246,241,0.92); backdrop-filter: blur(12px); border-bottom: 1px solid var(--gray-200); padding: 0 2rem; height: 56px; display: flex; align-items: center; justify-content: space-between; } .topbar-logo { font-family: var(--mono); font-weight: 600; font-size: 14px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent); } .topbar-links { display: flex; gap: 1.5rem; font-family: var(--sans); font-size: 13px; font-weight: 500; } .topbar-links a { color: var(--gray-500); text-decoration: none; transition: color 0.2s; } .topbar-links a:hover { color: var(--ink); } .topbar-links a.active { color: var(--accent); }

/* --- SIDEBAR --- */ .layout { display: grid; grid-template-columns: 260px 1fr; min-height: 100vh; padding-top: 56px; } .sidebar { position: sticky; top: 56px; height: calc(100vh - 56px); overflow-y: auto; border-right: 1px solid var(--gray-200); padding: 2rem 1.5rem; font-family: var(--sans); font-size: 13.5px; } .sidebar-section { margin-bottom: 1.8rem; } .sidebar-title { font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--gray-400); margin-bottom: 0.7rem; font-weight: 600; } .sidebar a { display: block; padding: 0.35rem 0.8rem; color: var(--gray-500); text-decoration: none; border-radius: 5px; transition: all 0.15s; font-weight: 500; line-height: 1.5; } .sidebar a:hover { color: var(--ink); background: var(--gray-100); } .sidebar a.active { color: var(--accent-dark); background: var(--accent-light); font-weight: 600; }

/* --- MAIN CONTENT --- */ .main { max-width: 860px; padding: 3rem 4rem 6rem; }

.breadcrumb { font-family: var(--mono); font-size: 12px; color: var(--gray-400); margin-bottom: 2rem; letter-spacing: 0.02em; } .breadcrumb span { color: var(--gray-300); margin: 0 0.4rem; }

.hero-title { font-family: var(--serif); font-size: 2.6rem; font-weight: 700; line-height: 1.2; margin-bottom: 1rem; color: var(--ink); letter-spacing: -0.01em; } .hero-subtitle { font-family: var(--sans); font-size: 1.1rem; color: var(--gray-500); line-height: 1.6; margin-bottom: 2.5rem; max-width: 640px; }

.meta-bar { display: flex; gap: 2rem; padding: 1rem 0; border-top: 1px solid var(--gray-200); border-bottom: 1px solid var(--gray-200); margin-bottom: 3rem; font-family: var(--mono); font-size: 12px; color: var(--gray-400); } .meta-bar strong { color: var(--gray-500); font-weight: 600; }

/* --- SECTIONS --- */ h2 { font-family: var(--serif); font-size: 1.7rem; font-weight: 700; margin-top: 3.5rem; margin-bottom: 1rem; color: var(--ink); letter-spacing: -0.01em; padding-top: 1rem; border-top: 2px solid var(--gray-200); } h2:first-of-type { border-top: none; padding-top: 0; margin-top: 0; }

h3 { font-family: var(--sans); font-size: 1.15rem; font-weight: 700; margin-top: 2rem; margin-bottom: 0.6rem; color: var(--ink); }

p { margin-bottom: 1rem; }

/* --- STRATEGY CARDS --- */ .strategy-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin: 2rem 0 2.5rem; } .strategy-card { border: 1px solid var(--gray-200); border-radius: 10px; padding: 1.5rem; background: #fff; transition: transform 0.2s, box-shadow 0.2s; position: relative; overflow: hidden; } .strategy-card:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.06); } .strategy-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; } .strategy-card:nth-child(1)::before { background: var(--green); } .strategy-card:nth-child(2)::before { background: var(--blue); } .strategy-card:nth-child(3)::before { background: var(--accent); }

.card-number { font-family: var(--mono); font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 0.6rem; } .strategy-card:nth-child(1) .card-number { color: var(--green); } .strategy-card:nth-child(2) .card-number { color: var(--blue); } .strategy-card:nth-child(3) .card-number { color: var(--accent); }

.card-title { font-family: var(--sans); font-size: 1rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--ink); } .card-desc { font-size: 0.88rem; color: var(--gray-500); line-height: 1.55; font-family: var(--sans); }

/* --- CODE BLOCKS --- */ .code-block { background: var(--ink); color: #d4d4d4; border-radius: 8px; padding: 1.4rem 1.6rem; margin: 1.2rem 0 1.5rem; font-family: var(--mono); font-size: 13px; line-height: 1.7; overflow-x: auto; position: relative; } .code-block .label { position: absolute; top: 0.6rem; right: 0.8rem; font-size: 10px; color: #666; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 600; } .code-block .kw { color: #c792ea; width:100%; } .code-block .str { color: #c3e88d; } .code-block .num { color: #f78c6c; } .code-block .cmt { color: #676e95; font-style: italic; } .code-block .fn { color: #82aaff; } .code-block .type { color: #ffcb6b; } .code-block .var { color: #89ddff; }

/* --- COMPARISON TABLE --- */ .comparison-table { width: 100%; border-collapse: separate; border-spacing: 0; margin: 2rem 0; font-family: var(--sans); font-size: 0.9rem; border-radius: 10px; overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,0.06); } .comparison-table thead th { background: var(--ink); color: #fff; padding: 1rem 1.2rem; text-align: left; font-weight: 600; font-size: 0.82rem; letter-spacing: 0.03em; } .comparison-table thead th:first-child { border-radius: 10px 0 0 0; } .comparison-table thead th:last-child { border-radius: 0 10px 0 0; } .comparison-table tbody td { padding: 1rem 1.2rem; border-bottom: 1px solid var(--gray-200); vertical-align: top; line-height: 1.55; } .comparison-table tbody tr:last-child td { border-bottom: none; } .comparison-table tbody tr:nth-child(even) td { background: var(--gray-100); } .comparison-table tbody td:first-child { font-weight: 600; color: var(--ink); white-space: nowrap; }

.badge { display: inline-block; padding: 0.15rem 0.55rem; border-radius: 4px; font-size: 0.75rem; font-weight: 600; letter-spacing: 0.02em; vertical-align: middle; } .badge-green { background: var(--green-light); color: var(--green); } .badge-amber { background: var(--amber-light); color: var(--amber); } .badge-red { background: #fde8e8; color: #c53030; } .badge-blue { background: var(--blue-light); color: var(--blue); }

/* --- CALLOUT --- */ .callout { border-left: 4px solid var(--accent); background: #fff; padding: 1.2rem 1.5rem; margin: 1.5rem 0; border-radius: 0 8px 8px 0; font-size: 0.95rem; box-shadow: 0 1px 4px rgba(0,0,0,0.04); } .callout.info { border-left-color: var(--blue); } .callout.warn { border-left-color: var(--amber); } .callout-title { font-family: var(--sans); font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 0.3rem; } .callout.info .callout-title { color: var(--blue); } .callout.warn .callout-title { color: var(--amber); } .callout .callout-title { color: var(--accent); }

/* --- FLOW DIAGRAMS --- */ .flow-diagram { display: flex; align-items: center; gap: 0.5rem; margin: 1.5rem 0; flex-wrap: wrap; font-family: var(--sans); font-size: 0.85rem; } .flow-step { background: #fff; border: 1px solid var(--gray-200); padding: 0.6rem 1rem; border-radius: 6px; font-weight: 500; white-space: nowrap; } .flow-arrow { color: var(--gray-300); font-size: 1.2rem; } .flow-step.highlight { border-color: var(--accent); background: var(--accent-light); color: var(--accent-dark); font-weight: 600; }

/* --- DEEP DIVE SECTIONS --- */ .section-anchor { scroll-margin-top: 80px; }

.detail-block { background: #fff; border: 1px solid var(--gray-200); border-radius: 10px; padding: 2rem; margin: 1.5rem 0; } .detail-block h4 { font-family: var(--sans); font-size: 1rem; font-weight: 700; margin-bottom: 0.8rem; display: flex; align-items: center; gap: 0.5rem; } .detail-block p { font-size: 0.95rem; }

.icon-circle { width: 28px; height: 28px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; flex-shrink: 0; } .icon-green { background: var(--green-light); color: var(--green); } .icon-blue { background: var(--blue-light); color: var(--blue); } .icon-red { background: #fde8e8; color: var(--accent); }

/* --- VERDICT / RECOMMENDATION --- */ .verdict-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin: 2rem 0; } .verdict-item { text-align: center; background: #fff; border: 1px solid var(--gray-200); border-radius: 10px; padding: 1.5rem 1rem; } .verdict-label { font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--gray-400); margin-bottom: 0.5rem; font-weight: 600; } .verdict-pick { font-family: var(--sans); font-size: 1rem; font-weight: 700; color: var(--ink); margin-bottom: 0.3rem; } .verdict-reason { font-family: var(--sans); font-size: 0.8rem; color: var(--gray-500); line-height: 1.4; }

/* --- INLINE CODE --- */ code { font-family: var(--mono); background: var(--gray-100); padding: 0.15rem 0.4rem; border-radius: 3px; font-size: 0.88em; color: var(--accent-dark); }

/* --- FOOTER --- */ .footer { border-top: 1px solid var(--gray-200); padding: 2rem 0; margin-top: 4rem; font-family: var(--sans); font-size: 0.82rem; color: var(--gray-400); display: flex; justify-content: space-between; }

/* --- RESPONSIVE --- */ @media (max-width: 900px) { .layout { grid-template-columns: 1fr; } .sidebar { display: none; } .main { padding: 2rem 1.5rem 4rem; } .strategy-cards { grid-template-columns: 1fr; } .verdict-grid { grid-template-columns: 1fr; } .hero-title { font-size: 2rem; } .comparison-table { font-size: 0.8rem; } .comparison-table thead th, .comparison-table tbody td { padding: 0.7rem 0.8rem; } }

/* --- ANIMATIONS --- */ @keyframes fadeUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } } .main > * { animation: fadeUp 0.5s ease both; } .main > *:nth-child(1) { animation-delay: 0.05s; } .main > *:nth-child(2) { animation-delay: 0.1s; } .main > *:nth-child(3) { animation-delay: 0.15s; } .main > *:nth-child(4) { animation-delay: 0.2s; } .main > *:nth-child(5) { animation-delay: 0.25s; }

.pros-cons { margin: 1rem 0; } .pros-cons div { padding: 0.3rem 0; font-family: var(--sans); font-size: 0.9rem; } .pro::before { content: '✓ '; color: var(--green); font-weight: 700; } .con::before { content: '✗ '; color: var(--accent); font-weight: 700; } </style>

</head> <body>

<div class="layout">

<!-- SIDEBAR -->

<aside class="sidebar"> <div class="sidebar-section"> <div class="sidebar-title">Overview</div> <a href="#overview" class="active">Introduction</a> <a href="#the-problem">The Problem</a> <a href="#strategies">The Three Strategies</a> </div> <div class="sidebar-section"> <div class="sidebar-title">Strategy Deep Dive</div> <a href="#strategy-1">1 — Explicit Selection</a> <a href="#strategy-2">2 — Design-Time Discovery</a> <a href="#strategy-3">3 — Runtime Matching</a> </div> <div class="sidebar-section"> <div class="sidebar-title">Analysis</div> <a href="#comparison">Comparison Matrix</a> <a href="#design-effort">Design-Time Effort</a> <a href="#performance">Runtime Performance</a> <a href="#accuracy">Result Accuracy</a> </div> <div class="sidebar-section"> <div class="sidebar-title">Conclusion</div> <a href="#recommendation">Recommendation</a> <a href="#decision-tree">Decision Tree</a> </div> </aside>

<!-- MAIN CONTENT -->

<main class="main">

<!-- THE PROBLEM -->
<h2 id="the-problem">The Problem</h2>

<p>
  When a COBOL copybook contains <code>REDEFINES</code> clauses, the same memory region is described by multiple competing field layouts. A single raw buffer can be interpreted in several structurally valid ways — but only one interpretation reflects the data the sending program actually wrote.
</p>

<div class="code-block">
  <span class="label">COBOL</span>

<span class="kw">01</span> ACCOUNT-RECORD.

  <span class="kw">05</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ACCT-TYPE          <span class="type">PIC X(1)</span>. 

<span class="kw">05</span>     ACCT-DATA.

  <span class="kw">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PERSONAL-INFO. 

     <span class="kw">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FULL-NAME       <span class="type">PIC X(30)</span>.

     <span class="kw">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATE-OF-BIRTH   <span class="type">PIC 9(8)</span>.

  <span class="kw">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BUSINESS-INFO   <span class="kw">REDEFINES</span> PERSONAL-INFO.

     <span class="kw">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COMPANY-NAME    <span class="type">PIC X(25)</span>.

     <span class="kw">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TAX-ID          <span class="type">PIC X(13)</span>.

  <span class="kw">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRUST-INFO      <span class="kw">REDEFINES</span> PERSONAL-INFO.

     <span class="kw">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRUST-NAME      <span class="type">PIC X(30)</span>.

     <span class="kw">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRUSTEE-CODE    <span class="type">PIC 9(8)</span>.

</div>

<p>
  The challenge is: given a raw byte buffer received from the mainframe, how do you determine which REDEFINE branch was actually populated — so you can produce a correct, meaningful JSON output?
</p>

<div class="callout info">
  <div class="callout-title">Key Insight</div>
  With <em>n</em> independent REDEFINE groups in a copybook, the total number of interpretation paths grows as the Cartesian product of all branch options. A copybook with just 4 REDEFINE groups of 3 branches each yields 3⁴ = 81 possible interpretations.
</div>

<!-- THREE STRATEGIES OVERVIEW -->
<h2 id="strategies">The Three Strategies</h2>

<div class="strategy-cards">
  <div class="strategy-card">
    <div class="card-number">Strategy 1</div>
    <div class="card-title">Explicit Selection</div>
    <div class="card-desc">You know the buffer structure in advance and can specify exactly which REDEFINE branches to select at design time.</div>
  </div>
  <div class="strategy-card">
    <div class="card-number">Strategy 2</div>
    <div class="card-title">Design-Time Discovery</div>
    <div class="card-desc">You enumerate — at design time — only the REDEFINE paths that are actually used in production, rather than testing all permutations.</div>
  </div>
  <div class="strategy-card">
    <div class="card-number">Strategy 3</div>
    <div class="card-title">Runtime Matching</div>
    <div class="card-desc">You attempt to match the buffer against candidate REDEFINE paths at runtime, iterating until a valid interpretation is found.</div>
  </div>
</div>

<!-- ==================== STRATEGY 1 ==================== -->
<h2 id="strategy-1" class="section-anchor">Strategy 1 — Explicit Selection</h2>

<p>
  In this approach, you already know — before processing any data — which REDEFINE branch applies. This knowledge typically comes from system documentation, a discriminator field in the record, or coordination with the sending application team.
</p>

<h3>How It Works</h3>
<div class="flow-diagram">
  <span class="flow-step">Analyze Copybook</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step highlight">Lock REDEFINE Choices</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step">Configure Parser</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step">Deserialize Buffer</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step">Output JSON</span>
</div>

<p>
  The developer configures the parser or converter with a fixed set of REDEFINE branch selections. Every incoming buffer is then interpreted using this single, predetermined layout. There is no ambiguity at runtime — the structure is fully resolved before the first byte is processed.
</p>

<div class="code-block">
  <span class="label">Configuration</span>

<span class="cmt">// Parser configuration — explicit REDEFINE selection</span> { <span class="str">"copybook"</span>: <span class="str">"ACCOUNT-RECORD.cpy"</span>, <span class="str">"redefines"</span>: { <span class="str">"ACCT-DATA"</span>: <span class="str">"PERSONAL-INFO"</span> <span class="cmt">// ← fixed choice</span> } }

</div>

<div class="detail-block">
  <h4><span class="icon-circle icon-green">1</span> Characteristics</h4>
  <div class="pros-cons">
    <div class="pro">Zero runtime overhead — structure is resolved once at startup</div>
    <div class="pro">100% accuracy when the assumption is correct</div>
    <div class="pro">Simplest implementation and easiest to test</div>
    <div class="con">Requires intimate knowledge of the data source</div>
    <div class="con">Breaks silently if the sender starts using a different branch</div>
    <div class="con">Not viable when a single stream carries multiple record variants</div>
  </div>
</div>

<!-- ==================== STRATEGY 2 ==================== -->
<h2 id="strategy-2" class="section-anchor">Strategy 2 — Design-Time Discovery</h2>

<p>
  Rather than assuming a single branch, you investigate — before deployment — which REDEFINE paths actually appear in real production data. You might analyze sample files, consult with mainframe developers, or run profiling against historical buffers. The result is a curated list of <em>active paths</em>, much smaller than the full Cartesian product of all possible branch permutations.
</p>

<h3>How It Works</h3>
<div class="flow-diagram">
  <span class="flow-step">Analyze Copybook</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step highlight">Profile Real Data</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step highlight">Curate Active Paths</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step">Build Matching Rules</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step">Deserialize</span>
</div>

<p>
  This typically involves examining discriminator values, field-level heuristics (e.g. "if bytes 12–14 are numeric, this is layout B"), or using domain knowledge to prune impossible combinations. The developer constructs a decision map that covers all realistic scenarios without resorting to brute-force permutation.
</p>

<div class="code-block">
  <span class="label">Configuration</span>

<span class="cmt">// Design-time discovered paths</span> { <span class="str">"copybook"</span>: <span class="str">"ACCOUNT-RECORD.cpy"</span>, <span class="str">"activePaths"</span>: [ { <span class="str">"condition"</span>: <span class="str">"ACCT-TYPE == 'P'"</span>, <span class="str">"select"</span>: { <span class="str">"ACCT-DATA"</span>: <span class="str">"PERSONAL-INFO"</span> } }, { <span class="str">"condition"</span>: <span class="str">"ACCT-TYPE == 'B'"</span>, <span class="str">"select"</span>: { <span class="str">"ACCT-DATA"</span>: <span class="str">"BUSINESS-INFO"</span> } } ] }

</div>

<div class="callout warn">
  <div class="callout-title">Important</div>
  The quality of this strategy depends entirely on how thoroughly you profile the real data. Missing an edge-case path means those records will either fail or be misinterpreted.
</div>

<div class="detail-block">
  <h4><span class="icon-circle icon-blue">2</span> Characteristics</h4>
  <div class="pros-cons">
    <div class="pro">Handles multiple record layouts within a single data stream</div>
    <div class="pro">Dramatically reduces search space compared to full permutation</div>
    <div class="pro">High accuracy when profiling is thorough</div>
    <div class="con">Significant upfront analysis effort — may require mainframe SME access</div>
    <div class="con">Curated path list must be maintained as copybooks evolve</div>
    <div class="con">Risk of blind spots if sample data isn't representative</div>
  </div>
</div>

<!-- ==================== STRATEGY 3 ==================== -->
<h2 id="strategy-3" class="section-anchor">Strategy 3 — Runtime Matching</h2>

<p>
  In this fully automated approach, the parser generates candidate REDEFINE interpretations and attempts to deserialize the buffer against each one at runtime. It evaluates each attempt using validation heuristics — numeric field validity, string plausibility, packed-decimal integrity, field-level constraints — and selects the interpretation that best fits.
</p>

<h3>How It Works</h3>
<div class="flow-diagram">
  <span class="flow-step">Receive Buffer</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step highlight">Generate Candidates</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step highlight">Try Each Path</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step highlight">Score &amp; Validate</span>
  <span class="flow-arrow">→</span>
  <span class="flow-step">Best Match → JSON</span>
</div>

<p>
  The matching engine may use strategies such as: checking packed decimal sign nibbles, validating date fields, evaluating whether alphanumeric fields contain printable characters, or scoring how many fields pass their <code>PIC</code> clause constraints. The first candidate that passes all validation checks — or the highest-scoring one — wins.
</p>

<div class="code-block">
  <span class="label">Pseudocode</span>

<span class="kw">function</span> <span class="fn">matchBuffer</span>(buffer, copybook): candidates = <span class="fn">generateRedefinePaths</span>(copybook) bestScore = <span class="num">-1</span> bestResult = <span class="kw">null</span>

<span class="kw">for</span> path <span class="kw">in</span> candidates:
    result = <span class="fn">tryDeserialize</span>(buffer, path)
    score  = <span class="fn">validateFields</span>(result)

    <span class="kw">if</span> score > bestScore:
        bestScore  = score
        bestResult = result

<span class="kw">return</span> bestResult.<span class="fn">toJSON</span>()

</div>

<div class="callout">
  <div class="callout-title">Combinatorial Warning</div>
  Without pruning, the number of candidate paths can explode exponentially. A copybook with 5 REDEFINE groups each having 3 options creates 3⁵ = 243 candidate paths per record. For high-throughput streams, this can become a serious bottleneck.
</div>

<div class="detail-block">
  <h4><span class="icon-circle icon-red">3</span> Characteristics</h4>
  <div class="pros-cons">
    <div class="pro">Zero upfront analysis — works with any copybook out of the box</div>
    <div class="pro">Self-adapting: handles new record variants without reconfiguration</div>
    <div class="pro">Maximum flexibility for unknown or evolving data streams</div>
    <div class="con">Highest runtime cost — each record may require multiple deserialization attempts</div>
    <div class="con">Accuracy depends on the quality of validation heuristics</div>
    <div class="con">Risk of false positives when two layouts produce superficially valid results</div>
  </div>
</div>

<!-- ==================== COMPARISON ==================== -->
<h2 id="comparison" class="section-anchor">Comparison Matrix</h2>

Dimension

Strategy 1: Explicit

Strategy 2: Design-Time

Strategy 3: Runtime

Design-Time Effort

<span class="badge badge-green">Low</span> — select branches once

<span class="badge badge-amber">Medium</span> — profile & curate paths

<span class="badge badge-green">Low</span> — no upfront analysis needed

Runtime Performance

<span class="badge badge-green">Optimal</span> — single-pass parse

<span class="badge badge-green">Near-Optimal</span> — conditional branch, no iteration

<span class="badge badge-red">Variable</span> — multiple parse attempts per record

Result Accuracy

<span class="badge badge-green">100%</span> when assumption holds

<span class="badge badge-blue">High</span> — bounded by profiling quality

<span class="badge badge-amber">Heuristic</span> — bounded by validation logic

Adaptability

<span class="badge badge-red">Rigid</span> — single layout only

<span class="badge badge-amber">Moderate</span> — requires re-profiling

<span class="badge badge-green">High</span> — self-adapting

Maintenance

<span class="badge badge-green">Minimal</span>

<span class="badge badge-amber">Ongoing</span> — path list updates

<span class="badge badge-green">Minimal</span> — heuristics are generic

Risk Profile

Silent failure if assumption breaks

Gaps if profiling misses edge cases

False positives from ambiguous layouts

<!-- ==================== DEEP DIVE: DESIGN EFFORT ==================== -->
<h2 id="design-effort" class="section-anchor">Deep Dive: Design-Time Effort</h2>

<h3>Strategy 1 — Minimal</h3>
<p>
  The developer simply reads the copybook, selects the relevant REDEFINE branch, and configures the parser. This is often a matter of minutes and doesn't require access to sample data. However, it implicitly assumes the developer has domain knowledge or documentation about which branch the sender uses.
</p>

<h3>Strategy 2 — Moderate to Significant</h3>
<p>
  This strategy front-loads work into a discovery phase. The developer must obtain representative sample data (ideally production snapshots), analyze discriminator patterns, and build a mapping table. For complex copybooks with nested REDEFINES, this can take days and may require collaboration with mainframe application teams who understand the business logic governing which layouts are used.
</p>
<p>
  The payoff is a well-documented, validated mapping that provides near-certain accuracy with near-zero runtime cost. However, every time the copybook changes or a new record variant enters the stream, the mapping must be revisited.
</p>

<h3>Strategy 3 — Minimal (Shifted Effort)</h3>
<p>
  Paradoxically, the most complex runtime strategy requires the least upfront effort from the developer. The matching engine is a reusable component — once built, it can be pointed at any copybook. The effort is shifted from <em>per-copybook design work</em> to <em>one-time engine development</em>. However, tuning the validation heuristics to produce accurate results across diverse copybooks can be a significant engineering investment.
</p>

<!-- ==================== DEEP DIVE: PERFORMANCE ==================== -->
<h2 id="performance" class="section-anchor">Deep Dive: Runtime Performance</h2>

<h3>Throughput Impact</h3>
<p>
  For high-volume mainframe data pipelines — millions of records per batch — the performance difference between strategies is material.
</p>

Metric

Explicit

Design-Time

Runtime

Parse ops / record

1

1 (+ condition eval)

1 … <em>n</em> (worst case = all paths)

Branching cost

None

O(1) lookup or simple if/else

Validation scoring per attempt

Memory overhead

Single layout in memory

All active layouts loaded

All permutations (or lazy generation)

Scalability

Linear with volume

Linear with volume

Linear × paths with volume

<div class="callout info">
  <div class="callout-title">Optimization Note</div>
  Strategy 3 performance can be improved with early-exit optimizations: if the first validation check fails (e.g. an expected numeric field contains non-numeric data), that candidate path is immediately discarded without completing the full deserialization. Smart ordering of candidates — putting the most common layouts first — can also reduce average attempts significantly.
</div>

<!-- ==================== DEEP DIVE: ACCURACY ==================== -->
<h2 id="accuracy" class="section-anchor">Deep Dive: Result Accuracy</h2>

<h3>What Can Go Wrong</h3>

<p>
  <strong>Strategy 1</strong> is binary: if the assumption is correct, you get perfect JSON every time. If the assumption is wrong — for instance, the sender starts writing a different REDEFINE branch — every record is silently misinterpreted. There's no fallback and often no error signal, because the buffer is the same length regardless of which branch was used.
</p>

<p>
  <strong>Strategy 2</strong> offers strong accuracy for known paths. The risk lies in the unknown: a newly introduced record variant, a rare branch that wasn't present in the profiling sample, or a copybook update that adds branches. These edge cases will either cause a match failure (detectable) or a misclassification (harder to catch).
</p>

<p>
  <strong>Strategy 3</strong> faces the most nuanced accuracy challenges. Consider two REDEFINE branches where one defines <code>PIC X(10)</code> and the other defines <code>PIC 9(10)</code> over the same bytes. If the data happens to be a 10-digit number, <em>both</em> branches will validate successfully. The heuristic must resolve this ambiguity — and it won't always guess right. Accuracy is fundamentally bounded by how distinguishable the REDEFINE branches are from each other at the byte level.
</p>

<div class="callout">
  <div class="callout-title">The Ambiguity Problem</div>
  COBOL REDEFINES were not designed with self-describing data in mind. Unlike tagged unions or discriminated types in modern languages, a REDEFINE carries no tag bits. The <em>same byte sequence</em> is always valid under the original definition. Disambiguation is inherently a best-effort exercise unless an explicit discriminator field exists.
</div>

<!-- ==================== RECOMMENDATION ==================== -->
<h2 id="recommendation" class="section-anchor">Recommendation</h2>

<p>
  No single strategy is universally best. The right choice depends on your constraints:
</p>

<div class="verdict-grid">
  <div class="verdict-item">
    <div class="verdict-label">Best for Accuracy</div>
    <div class="verdict-pick">Strategy 1 + 2</div>
    <div class="verdict-reason">Combine explicit selection where possible, with design-time discovery as a safety net for multi-variant streams.</div>
  </div>
  <div class="verdict-item">
    <div class="verdict-label">Best for Performance</div>
    <div class="verdict-pick">Strategy 1</div>
    <div class="verdict-reason">Single-pass parsing with zero overhead. Ideal for high-throughput pipelines with well-understood data.</div>
  </div>
  <div class="verdict-item">
    <div class="verdict-label">Best for Flexibility</div>
    <div class="verdict-pick">Strategy 3</div>
    <div class="verdict-reason">Self-adapting, zero-config. Best when you can't access mainframe SMEs or the data is unpredictable.</div>
  </div>
</div>

<!-- ==================== DECISION TREE ==================== -->
<h2 id="decision-tree" class="section-anchor">Decision Tree</h2>

<p>Use this flow to select the right strategy for your situation:</p>

<div class="detail-block" style="font-family: var(--sans); font-size: 0.92rem; line-height: 2;">
  <strong>Q1:</strong> Do you know which REDEFINE branch the sender uses?

  &nbsp;&nbsp;↳ <strong>Yes, always the same branch</strong> → <span class="badge badge-green">Strategy 1</span> Explicit Selection

  &nbsp;&nbsp;↳ <strong>No, or it varies by record</strong> → continue to Q2



  <strong>Q2:</strong> Can you access sample production data and/or mainframe SMEs?

  &nbsp;&nbsp;↳ <strong>Yes</strong> → <span class="badge badge-blue">Strategy 2</span> Design-Time Discovery

  &nbsp;&nbsp;↳ <strong>No</strong> → continue to Q3



  <strong>Q3:</strong> Is the throughput requirement high (&gt;100K records/sec)?

  &nbsp;&nbsp;↳ <strong>No</strong> → <span class="badge badge-amber">Strategy 3</span> Runtime Matching

  &nbsp;&nbsp;↳ <strong>Yes</strong> → <span class="badge badge-amber">Strategy 3</span> with aggressive caching and early-exit optimization, or invest in <span class="badge badge-blue">Strategy 2</span> despite the effort
</div>

<div class="callout info">
  <div class="callout-title">Hybrid Approach</div>
  In practice, many production systems combine strategies. Use Strategy 1 for well-known, stable copybooks. Use Strategy 2 for critical business feeds where accuracy is paramount. Fall back to Strategy 3 for ad-hoc or exploratory data integration work.
</div>

<!-- FOOTER -->
<div class="footer">
  <span>Mainframe ⇄ JSON Documentation</span>
  <span>© 2026</span>
</div>

</main> </div>

<script> // Highlight sidebar links on scroll const sections = document.querySelectorAll('.section-anchor, [id]'); const sidebarLinks = document.querySelectorAll('.sidebar a'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const id = entry.target.id; sidebarLinks.forEach(link => { link.classList.toggle('active', link.getAttribute('href') === '#' + id); }); } }); }, { rootMargin: '-80px 0px -60% 0px', threshold: 0 }); sections.forEach(section => { if (section.id) observer.observe(section); }); // Smooth scroll document.querySelectorAll('a[href^="#"]').forEach(a => { a.addEventListener('click', e => { e.preventDefault(); const target = document.querySelector(a.getAttribute('href')); if (target) target.scrollIntoView({ behavior: 'smooth' }); }); }); </script>

</body> </html> `}

Read more