> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metaphi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Unit format

> The directory run_unit and open_terminal take: its tree, run.json, chains, data set geometry and the oracle.

A unit is a directory in a mainframe codebase's own shape, plus a `run.json` that says what to run.

## The tree

```text theme={"dark"}
unit/
  Progs/            COBOL source, found by PROGRAM-ID. Any directory name works
  Copybooks/        COPY members, by member name
  BMS/              BMS mapset macro source, assembled on every run
  Procs/            decks and cataloged PROCs (*.jcl, *.prc, *.proc), by file stem
  CATALOG/          one file per data set, named by its data set name, plus _geometry.json
  DB/seed.sql       Db2 DDL and rows, applied once to a fresh volume
  CHAIN/chain.json  many jobs with dependencies
  ORACLE/           the expected end state
  run.json          what to run, and the settings
```

`CATALOG/`, `DB/`, `CHAIN/` and `ORACLE/` are reserved. Every other directory is a source library. A source file at the top of the tree is never found: put it in a subdirectory. A copybook directory must be named `cpy`, `cpyv1`, `copy` or `copybooks` (any case) to be searched.

## The demand

Exactly one of these says what to run:

| Demand | Runs |
| - | - |
| `run.json` `"compile": ["PROGRAM-ID", ...]` | Compiles, runs nothing. One job per name, with the full listing |
| `run.json` `"submit": ["DECK", ...]` | Decks by file stem in `Procs/`, in order |
| `CHAIN/chain.json` | Many jobs with dependencies and one clock |
| `run.json` `"cics"` with `screens` | A transaction, started from the PCT, one task per screen. No deck |

Declaring two of `compile`, `submit` and `CHAIN/` is refused.

## run.json

```json theme={"dark"}
{
  "submit": ["BILLJOB"],
  "clock": "20261103120000",
  "resolution": "strict",
  "capture": {"datasets": ["PAY.TOTAL"], "tables": ["ACCOUNTS"]}
}
```

Every setting is optional. What `run.json` leaves out comes from the codebase's `harwell.toml` `[run]`, then from the default. An unknown key is refused by name. The report carries the resolved settings, where each came from, and one digest over them under `configuration`: two runs with the same digest ran under the same settings.

| Key | Default | Description |
| - | - | - |
| `clock` | `20240101120000` | The run clock, `YYYYMMDDHHMMSS` or `YYYYMMDD`. Every date and time a program reads comes from it. It does not advance within a run |
| `utc_offset` | none | `+HHMM` or `-HHMM`: the local clock's offset from UTC |
| `resolution` | `authoring` | A CALL to a program the tree lacks. `authoring` links a no-op stub and says so on the result. `strict` fails the step `S806` |
| `sql_callees` | `native` | SQL in a CALLed subprogram. `native` runs it on the caller's unit of work. `stub` links a no-op, for baselines recorded that way; the result says so on its own line |
| `codeset` | `ascii` | How data sets are stored: `ascii` or `ebcdic` |
| `code_page` | `cp037` | The EBCDIC code page. Also sets the collating sequence of character comparisons and sorts |
| `date_fmt` | `ISO` | Db2's DATE FORMAT: `ISO`, `JIS`, `EUR`, `USA` or `LOCAL` |
| `symbols` | `{}` | The scheduler's symbol table. A PROC default outranks it |
| `declared` | `{}` | Symbols the submitter declares. They outrank PROC defaults |
| `load_modules` | `false` | `EXEC PGM=` loads modules from the volume's load library, so a source edit takes effect only after a compile step relinks |
| `paragraph_trace` | `false` | Report the paragraphs and sections each step ran, as `executed` on each step |
| `sql_trace` | `false` | Trace SQL for this run; the report carries the trace |
| `step_timeout_s` | `60` | Seconds before a step is ended. Its note opens `STEP-TIMEOUT:` |
| `output_limit` | `1000000` | Records a step may print on one channel without `OUTLIM=`. A step at the limit ends `S722` |
| `capture` | none | Data sets and tables to return on the report after the run, in the shape `ORACLE/` takes |
| `cics` | none | The region and its screens. See [Drive a CICS transaction](https://docs.metaphi.ai/harwell/guides/cics-transactions.md#3-the-region-and-the-screens) |

A `run.json` may not restate what a codebase is (its libraries, search orders, JOB card, region or Db2 parameters). Those live in `harwell.toml` `[site]`.

## CHAIN/chain.json

```json theme={"dark"}
{
  "clock": "20261103220000",
  "jobs": [
    {"name": "EODEXTR"},
    {"name": "EODVALD", "after": ["EODEXTR"]},
    {"name": "EODPOST", "after": ["EODVALD"]},
    {"name": "EODRPT",  "after": ["EODPOST"], "tolerate": [4]}
  ]
}
```

| Key | Description |
| - | - |
| `jobs[].name` | The deck's file stem in `Procs/` |
| `jobs[].deck` | Another stem to run under this name |
| `jobs[].jcl` | The deck text inline. Wins over `name` and `deck` |
| `jobs[].after` | Jobs that must end `ok` first. A job whose predecessor failed is `blocked` and does not run. Without `after`, jobs run in written order |
| `jobs[].tolerate` | Return codes that still count as `ok` |
| `clock` | One clock for the whole chain |
| `symbols`, `load_modules`, `sql_callees` | Chain-wide values, overridable per job |

## CATALOG/\_geometry.json

```json theme={"dark"}
{"PAY.INPUT": {"lrecl": 15, "recfm": "FB"},
 "PAY.REJECTS": {"lrecl": 4092, "recfm": "VB"},
 "ACCT.KSDS": {"cluster": {"organization": "ksds", "record_size": 300,
                           "key_length": 11, "key_offset": 0}}}
```

| Key | Description |
| - | - |
| `lrecl` | The record length. A maximum for variable formats |
| `recfm` | `F`, `V` or `U`, then any of `B`, `S`, `A`, `M`, `T` |
| `cluster` | A VSAM cluster built from the flat file: `organization` (`ksds` or `rrds`), `record_size`, and for a KSDS `key_length`, `key_offset` and `alternate_keys` |

A fixed-format data set holds fixed-length records with no newlines. A file that is exactly N lines of LRECL bytes is read as N records with the newlines dropped. Any other misfit is read as it is, and the result's `seed:` line says where records start going wrong.

## ORACLE/

```text theme={"dark"}
ORACLE/
  datasets/<DSN>       expected bytes, compared byte for byte
  tables/<TABLE>.txt   expected table contents
  jobs.json            {"JOBNAME": "ok" | "failed" | "blocked"}
  absent.json          ["DSN", ...] that must not exist after the run
  screens.json         {"screens": [entry | null, ...], "exact"?: true}
```

With an `ORACLE/`, the result carries a verdict. It checks only what it names.

**Tables.** One row per line, fields joined with `|`, rows ordered by every column. `\N` is NULL. Escape `\\`, `\|`, `\n` and `\r`. Trailing blanks are not significant.

**Screens.** One entry per map sent, in order. `null` skips one. An entry is `{"map", "mapset", "fields": {NAME: value}}`, compared as the screen shows the fields, trailing blanks dropped. A field whose value is `null` must be on the map, and its value is not checked. `"exact": true` also checks the number of maps sent.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.