# Fixture inventory and expected outputs The tutorial builds one pipeline, chapter by chapter, and every chapter leans on the same set of checked inputs and captured outputs. This page is the inventory of those fixtures: what files exist, what the pipeline is expected to produce from them, which captures are real, and how to regenerate the corpus when the runtime changes. Use it as a lookup surface while you work through the tutorial, and as the provenance record when you need to know whether a number or a transcript can be trusted. A few terms carry the whole page. A fixture is a checked input or captured output used by the tutorial. A hank is the JSON program that contains codons; a codon **runs** as one sealed task in that program; a rig is a setup script for fixed checks. The tables and captures below come from the named fixture files, so each section tells you which file it describes before asking you to read it. ## Corpus files Everything starts with the corpus manifest for the `quote-template-unification` fixture. Each row records a file's `path`, an eight-character `sha256` prefix, its `media_type`, and its `data_class`, so the table doubles as an integrity check: if a file's hash prefix does not match, the file is not what the tutorial was tested against. | path | sha256 (8) | media\_type | data\_class | | ----------------------------------------------------------- | ---------- | ------------------------------------------------------------------- | ----------- | | `digitized-extracts/aster-quote-qb-1047_rev2.json` | `4b28baf0` | `application/json` | `synthetic` | | `digitized-extracts/dover-quote.json` | `a6b02224` | `application/json` | `synthetic` | | `digitized-extracts/embar-quote.md` | `298d9c4b` | `text/markdown` | `synthetic` | | `digitized-extracts/fjord-erp.tsv` | `00f50a04` | `text/tab-separated-values` | `synthetic` | | `digitized-extracts/harbor-quote.json` | `c780aad1` | `application/json` | `synthetic` | | `digitized-extracts/iris-quote.json` | `a9ebe6ee` | `application/json` | `synthetic` | | `digitized/aster.datalab-contract-fixture.json` | `dc746a89` | `application/json` | `synthetic` | | `digitized/beacon.reducto-contract-fixture.json` | `a9477fcf` | `application/json` | `synthetic` | | `digitized/cedar.generic-ocr-contract-fixture.json` | `00eff5b4` | `application/json` | `synthetic` | | `fixtures/failures/ambiguous-ocr-part-number.json` | `46b83ba8` | `application/json` | `synthetic` | | `fixtures/failures/award-brief-unsupported-number.md` | `8e436143` | `text/markdown` | `synthetic` | | `fixtures/failures/bad-source-sha256.json` | `67dd8989` | `application/json` | `synthetic` | | `fixtures/failures/broken-source-ref.json` | `e7230c78` | `application/json` | `synthetic` | | `fixtures/failures/datalab-missing-block-id.json` | `9c1ab469` | `application/json` | `synthetic` | | `fixtures/failures/duplicate-source-line.json` | `1214389f` | `application/json` | `synthetic` | | `fixtures/failures/expired-quote.json` | `378a0b11` | `application/json` | `synthetic` | | `fixtures/failures/freight-exclusion-omitted.json` | `bfadf2c8` | `application/json` | `synthetic` | | `fixtures/failures/missing-currency.json` | `98dc3084` | `application/json` | `synthetic` | | `fixtures/failures/no-bid-as-zero.json` | `1c4fa856` | `application/json` | `synthetic` | | `fixtures/failures/per-pack-as-per-each.json` | `01bbd4e3` | `application/json` | `synthetic` | | `fixtures/failures/quote-revision-a.json` | `8d6f739b` | `application/json` | `synthetic` | | `fixtures/failures/reducto-citation-page-out-of-range.json` | `baa05b7b` | `application/json` | `synthetic` | | `fixtures/failures/reducto-result-type-url.json` | `f723fb0f` | `application/json` | `synthetic` | | `fixtures/failures/stated-total-mismatch.json` | `ae458dc9` | `application/json` | `synthetic` | | `fixtures/failures/unknown-part-alias.json` | `123bf1e8` | `application/json` | `synthetic` | | `fixtures/failures/unknown-uom-conversion.json` | `8a7e1972` | `application/json` | `synthetic` | | `fixtures/failures/unlabeled-synthetic-document.json` | `ab089bf8` | `application/json` | `synthetic` | | `fixtures/failures/unsupported-substitution.json` | `b96e85c3` | `application/json` | `synthetic` | | `lookups/fx-rates.json` | `19926921` | `application/json` | `synthetic` | | `lookups/part-aliases.json` | `fee1fed3` | `application/json` | `synthetic` | | `lookups/unit-conversions.json` | `bfb1e105` | `application/json` | `synthetic` | | `rfq/northstar-bom-0042-rev-a.xlsx` | `b50f9e89` | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` | `synthetic` | | `rfq/northstar-bom-0042-rev-b.xlsx` | `92dd7f00` | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` | `synthetic` | | `rfq/northstar-rfq-0042-rev-a.pdf` | `431d1eba` | `application/pdf` | `synthetic` | | `rfq/northstar-rfq-0042-rev-b.pdf` | `ac4c9fd1` | `application/pdf` | `synthetic` | | `source-quotes/aster-quote-qb-1047.xlsx` | `3f39fa37` | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` | `synthetic` | | `source-quotes/beacon-quote-8821.pdf` | `854431e5` | `application/pdf` | `synthetic` | | `source-quotes/cedar-quote-cw-77-scan.png` | `51a6e23d` | `image/png` | `synthetic` | | `source-quotes/granite-bid.xlsx` | `717fecf5` | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` | `synthetic` | | `SYNTHETIC-DATA-NOTICE.txt` | `b17b4ba0` | `text/plain` | `synthetic` | | `truth/exceptions.csv` | `ea213c0f` | `text/csv` | `synthetic` | | `truth/expected.csv` | `914dc8c1` | `text/csv` | `synthetic` | | `truth/notes.csv` | `fa5d55b4` | `text/csv` | `synthetic` | Reading the paths column top to bottom traces the shape of the corpus. It has seven directories: `rfq/` contains buyer-side request for quotation (RFQ) and bill of materials (BOM) revisions; `source-quotes/` contains native pre-digitization files; `digitized/` contains hand-authored contract fixtures; `digitized-extracts/` contains already-digital dialects; `lookups/` contains aliases, unit conversions, and FX rates; `truth/` contains the golden oracle; and `fixtures/failures/` contains the negative fixtures. The generator and checker live in a sibling `generator/` directory, outside the corpus and agent input. The table lists all 43 hashed manifest entries, including `SYNTHETIC-DATA-NOTICE.txt`; the forge report separately records 44 files and 944K on disk. Most of that size comes from the Cedar scan PNG's uncompressed pixel data, a deliberate zero-dependency trade-off rather than real OCR input. The [release bundle](/content-assets/cf45dff5691c48c0/fixtures/0.10.0/hankweave-fixtures-0.10.0.tar.gz) is `/fixtures/0.10.0/hankweave-fixtures-0.10.0.tar.gz`, with individual files under `/fixtures/0.10.0/files/`. The archive contains one top-level `hankweave-fixtures-0.10.0/` directory; extract it in its parent, then use `hankweave-fixtures-0.10.0/minimal-single-provider` or `hankweave-fixtures-0.10.0/chapters/ch1`–`ch5`. These are fixture directories, not Git tags. ```bash mkdir fixtures-parent && cd fixtures-parent tar -xzf ../hankweave-fixtures-0.10.0.tar.gz cd hankweave-fixtures-0.10.0 ``` Do not create a second `hankweave-fixtures-0.10.0/` directory and extract into it; the archive already supplies that prefix. For an introduction to the inputs, normalized shapes, lookup data, oracle files, and negative cases listed above, start with [the tour](/0.10.0/files/tutorial/0-tour). To understand the JSON program that consumes them, see [hanks](/0.10.0/files/concepts/hanks). ## Supplier dialects and their hazards With the file list in hand, the next question is what those files put in front of the pipeline. The corpus covers eight suppliers quoting against a five-part BOM (bill of materials), and each supplier's input arrives in a different shape with a different planted hazard. Here, a dialect means an input file shape, not a programming language: the corpus has 10 entries – Datalab XLSX, Reducto PDF, generic-OCR PNG, six already-digital forms, and Granite's quarantined unknown-template XLSX – and each has a named hazard. The five BOM parts are `NC-1001-A` mounting bracket, `NC-1002-A` locking pin, `NC-1003-B` fastener kit, `NC-1004-A` gasket sheet, and `NC-1005-A` rating label roll; the rev-B quantities are 500, 2000, 1000, 25, and 5000. Three lookup files give the pipeline its reference data. `part-aliases.json` maps `NC-1OO5-A` to `NC-1005-A` by correcting `O` to `0`, maps `FJ-33xx` to `NC-10xx`, and carries the `BI-2002-X` substitution. `unit-conversions.json` maps `PACK(100)` to `EA` and `BOX(10)` to `EA`; an unknown pair fails closed. `fx-rates.json` is USD-only for the core run and has `as_of`, `base`, `rates`, `source`, and `fixture_kind` fields. Granite is the quarantined unknown-template supplier rather than a normal expected supplier result. The `digitized/` entries are the Datalab, Reducto, and generic-OCR contract shapes; `digitized-extracts/` shows already-digital forms, while the inventory retains Granite's unknown-template source. [Determinism](/0.10.0/files/tutorial/2-determinism) covers normalization; [validate and repair](/0.10.0/files/tutorial/3-validate-and-repair) covers aliases, units, and exception routing. ## Expected records and exceptions The dialects and hazards above exist to produce one checkable result. The golden-truth tables define the unified records and exception ledger that the anchor hank–the JSON program for the full pipeline–must reproduce. `expected.csv` contains 40 rows with `supplier_code`, `buyer_part_id`, `qty`, `unit_price_minor` (price in USD cents), `price_basis`, `status`, and `ranking_eligible`. `exceptions.csv` contains eight rows with `exception_id`, `type`, and `detail`. `notes.csv` is also part of the truth directory. ### Expected records The first table is the oracle for record content: every supplier–part combination the pipeline should emit, with its normalized price and ranking flag. | supplier\_code | buyer\_part\_id | qty | unit\_price\_minor | price\_basis | status | ranking\_eligible | | -------------- | --------------- | ---- | ------------------ | ------------ | ----------- | ----------------- | | AST | NC-1001-A | 500 | 410 | PER\_EACH | QUOTED | true | | AST | NC-1002-A | 2000 | 79 | PER\_EACH | QUOTED | true | | AST | NC-1003-B | 1000 | 115 | PER\_EACH | QUOTED | true | | AST | NC-1004-A | 25 | 640 | PER\_EACH | QUOTED | true | | AST | NC-1005-A | 5000 | 22 | PER\_EACH | QUOTED | true | | BCN | NC-1001-A | 500 | 395 | PER\_EACH | QUOTED | true | | BCN | NC-1002-A | 2000 | 81 | PER\_EACH | QUOTED | true | | BCN | NC-1003-B | 1000 | 115 | PACK | QUOTED | true | | BCN | NC-1004-A | 25 | 675 | PER\_EACH | QUOTED | true | | BCN | NC-1005-A | 5000 | 19 | PER\_EACH | QUOTED | true | | CDR | NC-1001-A | 500 | 425 | PER\_EACH | QUOTED | false | | CDR | NC-1002-A | 2000 | 88 | PER\_EACH | QUOTED | false | | CDR | NC-1003-B | 1000 | 110 | BOX | QUOTED | false | | CDR | NC-1004-A | 25 | | PER\_EACH | NO\_BID | false | | CDR | NC-1005-A | 5000 | 24 | PER\_EACH | QUOTED | false | | DVR | NC-1001-A | 500 | 402 | PER\_EACH | QUOTED | true | | DVR | NC-1002-A | 2000 | 83 | PER\_EACH | QUOTED | true | | DVR | NC-1003-B | 1000 | 118 | PER\_EACH | QUOTED | true | | DVR | NC-1004-A | 25 | 655 | PER\_EACH | QUOTED | true | | DVR | NC-1005-A | 5000 | 21 | PER\_EACH | QUOTED | true | | EMB | NC-1001-A | 500 | 430 | PER\_EACH | QUOTED | true | | EMB | NC-1002-A | 2000 | 90 | PER\_EACH | QUOTED | true | | EMB | NC-1003-B | 1000 | 105 | PER\_EACH | QUOTED | true | | EMB | NC-1004-A | 25 | 690 | PER\_EACH | QUOTED | true | | EMB | NC-1005-A | 5000 | 26 | PER\_EACH | QUOTED | true | | FJR | NC-1001-A | 500 | 398 | PER\_EACH | QUOTED | true | | FJR | NC-1002-A | 2000 | 80 | PER\_EACH | QUOTED | true | | FJR | NC-1003-B | 1000 | | PER\_EACH | UNRESOLVED | false | | FJR | NC-1004-A | 25 | 660 | PER\_EACH | QUOTED | true | | FJR | NC-1005-A | 5000 | | PER\_EACH | UNRESOLVED | false | | HBR | NC-1001-A | 500 | 405 | PER\_EACH | QUOTED | true | | HBR | NC-1002-A | 2000 | 86 | PER\_EACH | QUOTED | true | | HBR | NC-1003-B | 1000 | 112 | PER\_EACH | QUOTED | true | | HBR | NC-1004-A | 25 | | PER\_EACH | QUARANTINED | false | | HBR | NC-1005-A | 5000 | | PER\_EACH | QUARANTINED | false | | IRS | NC-1001-A | 500 | 418 | PER\_EACH | QUOTED | true | | IRS | NC-1002-A | 2000 | 84 | PER\_EACH | QUOTED | true | | IRS | NC-1003-B | 1000 | 116 | PER\_EACH | QUOTED | true | | IRS | NC-1004-A | 25 | 645 | PER\_EACH | QUOTED | true | | IRS | NC-1005-A | 5000 | 23 | PER\_EACH | QUOTED | true | ### Expected exceptions The second table is the oracle for the exception ledger: the eight hazard types the pipeline must surface rather than silently absorb. | exception\_id | type | detail | | ------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | EX-01 | EXPIRED\_VALIDITY | CDR valid\_until 2026-01-20 < award decision date 2026-02-01 | | EX-02 | NO\_BID | CDR rendered NO BID for NC-1004-A | | EX-03 | DEDUP\_CONFLICT | same supplier+RFQ rev submitted twice: doc-aster-qb-1047 stated\_total 604000 vs doc-aster-qb-1047-rev2 stated\_total 604001 (1-cent drift on NC-1004-A printed extension) | | EX-04 | PAGE\_SPLIT\_LINE | NC-1004-A row split across page break: qty on page 1, price+extension on page 2 | | EX-05 | UNKNOWN\_TEMPLATE | granite-bid.xlsx: first-time supplier, layout not recognized by any known template family | | EX-06 | UNRESOLVED\_PRICE | Fjord ERP export prices TBD for NC-1003-B (FJ-3343) and NC-1005-A (FJ-3345) | | EX-07 | LOW\_CONFIDENCE | Harbor JSON ocr\_confidence 0.81, warnings:\["low\_confidence: page 2"] | | EX-08 | NOTE\_ROUTED | handwriting annotation "can do 5% if you take all 5000" on NC-1005-A | Read the two tables together. Five rows in the records table are excluded from ranking with null prices: CDR/`NC-1004-A` is `NO_BID`; FJR/`NC-1003-B` and FJR/`NC-1005-A` are `UNRESOLVED`; and HBR/`NC-1004-A` and HBR/`NC-1005-A` are `QUARANTINED`. Each of those exclusions has a corresponding entry in the exceptions table, which is where the reason lives. The truth files are the golden oracle and are not shown to the agent under test. The 40 expected rows are data rows. The anchor's separate `41/41` label compares the two 41-line files line-for-line, including their header rows; it does not add a 41st data row. For example, `AST`/`NC-1001-A` is `QUOTED` and ranking-eligible, while `EX-01` records an expired-validity exception. [Determinism](/0.10.0/files/tutorial/2-determinism) and [validate and repair](/0.10.0/files/tutorial/3-validate-and-repair) use these files as comparison targets. ## Failure fixtures The truth tables describe what a correct run produces. The 19 standalone negative fixtures describe the opposite: each one is malformed in a specific way, and each row names the file, what is wrong with it, and the pipeline behavior that malformation must trigger. | # | File | What's wrong | Pipeline must | | --- | --------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------- | | F01 | bad-source-sha256.json | manifest hash mismatch | preflight rig exits nonzero; STOP before any codon \[S§validations-2] | | F02 | datalab-missing-block-id.json | block lacks `block_id` | schema-validate fail; evidence immutable → typed exception, source excluded \[S§validations-1,3] | | F03 | reducto-result-type-url.json | `result.type=="url"`, chunks absent | adapter explicitly fetch-or-reject; never read missing chunks as empty doc \[S§fixtures] | | F04 | reducto-citation-page-out-of-range.json | citation page 3 of 2 | ref-integrity fail; exception, excluded \[S§validations-4] | | F05 | duplicate-source-line.json | same `source_line_id` twice | validation fail; repair dedups or line excluded – never silently kept \[S§validations-6] | | F06 | unknown-part-alias.json | part id absent from aliases | line → `UNRESOLVED` + exception; no price invention \[S§validations-6] | | F07 | ambiguous-ocr-part-number.json | NC-1OO5-A without disambiguating context | → `UNRESOLVED` + exception (deterministic; distinct from JC-1) \[S§fixtures] | | F08 | no-bid-as-zero.json | NO BID rendered `$0.00` | normalize to `status:NO_BID`; zero valid only if source says zero with `QUOTED` \[S§contract-enums] | | F09 | per-pack-as-per-each.json | pack price read per-each (100× error) | TOTAL\_MISMATCH blocks; repair via price\_basis fields \[S§validations-9] | | F10 | unknown-uom-conversion.json | UOM pair not in conversions | fail closed: `UNRESOLVED`, no guessed factor \[S§validations-7] | | F11 | missing-currency.json | currency field absent | exception + excluded from ranking; never fabricate FX \[S§contract-fx] | | F12 | quote-revision-a.json | quote targets RFQ rev A | route to exceptions; excluded from rev-B comparison \[S§validations-5] | | F13 | expired-quote.json | valid\_until < award date | cannot win ranking; stays visible; JC-1 banner (§4) \[S§validations-10, G§4-break-it] | | F14 | stated-total-mismatch.json | stated ≠ computed total | blocking TOTAL\_MISMATCH; never "fix" source total \[S§validations-9] | | F15 | freight-exclusion-omitted.json | EXW note dropped | validation fail; `freight_included:false` w/ source\_ref required \[S§contract] | | F16 | unsupported-substitution.json | sub without approval info | `substitution.approval_required:true` + exception; not counted as clean QUOTED \[S§contract-enums] | | F17 | broken-source-ref.json | ref to nonexistent block | citation-integrity fail; repair or exception \[S§validations-4] | | F18 | unlabeled-synthetic-document.json | watermark absent | final gate STOP; no publication \[S§validations-14] | | F19 | award-brief-unsupported-number.md | brief number not in comparison.json | `final_validate.py` fails; publication blocked \[S§validations-11] | The bracketed references are anchors in `corpus-spec.md`; `EXW` marks the freight-excluded condition, and `JC-1` names the planted expired-at-award judgment call. The required behaviors split along the runtime's own boundaries. A rig–a setup script for fixed checks–**executes** before codon work, and a codon–a sealed task in the hank–**runs** after it. F01 proves that the preflight rig exits nonzero before any codon. F02 proves that schema validation, which checks data against its expected shape, creates a typed exception while excluding the source. F08 keeps `NO_BID` as a status, not a zero price. F09 blocks a total mismatch and repairs through price-basis fields. F10 fails closed for an unknown unit conversion, producing `UNRESOLVED` without a guessed factor. F18 makes the final gate stop when the `FICTIONAL TRAINING FIXTURE` notice is missing. The checker verifies that each of the 19 files is malformed in the way its row claims. > **DeepDive:** The 19 failure fixtures are generated programmatically from golden inputs, rather than hand-mutated. The checker independently verifies each break, making the set a reproducible regression suite. Two rows are worth singling out because they anchor the ends of the pipeline. F01 is the preflight case: the pipeline must stop before a codon. F08 is the source-data case: `NO_BID` must remain visible instead of becoming a price. [Validate and repair](/0.10.0/files/tutorial/3-validate-and-repair) applies the typed ledger; [errors and exit codes](/0.10.0/files/reference/errors-and-exit-codes) is the runtime error reference. ## Chapter captures The fixtures above feed the five tutorial directories–Baseline, Determinism, Validate & Repair, Observe & Budget, and Break, Resume & Inspect–each independently runnable at 0.10.0. The table below records what a passing run of each chapter looked like when captured: the cumulative codons, model identities, credentials needed before that run, tracked codon cost, and exit status. These are dated capture-manifest values, not a price promise; provider health checks and sentinel calls (small observer requests) are outside the tracked-codon total. | chapter | cumulative codons | models | credentials before run | tracked codon cost | exit | | ------- | ------------------------------------------- | ------------------------------------------------- | -------------------------------------- | -----------------: | ---: | | ch1 | `normalize-aster` | `haiku` | `ANTHROPIC_API_KEY` | $0.10441000 | 0 | | ch2 | ch1 + `normalize-beacon`, `normalize-cedar` | `haiku` | `ANTHROPIC_API_KEY` | $0.16203200 | 0 | | ch3 | ch2 + `validate-and-repair` | `haiku`; `pi/baseten/deepseek-ai/DeepSeek-V4-Pro` | `ANTHROPIC_API_KEY`, `BASETEN_API_KEY` | $0.28754050 | 0 | | ch4 | ch3 + `reconcile` | `haiku`; `pi/baseten/deepseek-ai/DeepSeek-V4-Pro` | `ANTHROPIC_API_KEY`, `BASETEN_API_KEY` | $0.40847623 | 0 | | ch5 | ch4 + `survey-and-extracts`, `award-brief` | `haiku`; `pi/baseten/deepseek-ai/DeepSeek-V4-Pro` | `ANTHROPIC_API_KEY`, `BASETEN_API_KEY` | $0.70680328 | 0 | Each chapter recipe is self-contained and starts from its own directory. Prepare that recipe's `task-data/` once; the destination must not already exist. Preparation copies `digitized/`, `digitized-extracts/`, `lookups/`, `rfq/`, `source-quotes/`, and a filtered manifest, while keeping `truth/`, `generator/`, and the planted failures outside the agent input. The ch1 sequence shows the pattern: ```bash cd chapters/ch1 python3 ../../verify.py prepare-data ../../quote-template-unification task-data bunx hankweave@0.10.0 hank.json task-data --validate bunx hankweave@0.10.0 hank.json task-data --headless --start-new --execution exec --max-cost 9 --shim-idle-timeout 1800 --overwrite-output -o out python3 ../../verify.py chapter 1 out ``` Run the same sequence from `chapters/ch2` through `chapters/ch5`, changing the final checker number; keep each chapter's `task-data/` with that chapter's `hank.json`. In ch5, run `bun rigs/render-exceptions.ts out --check && bun rigs/render-award.ts out --check` after the Python check. For an independent ch2 comparison, run both fresh attempts from `chapters/ch2` with the already prepared `task-data/` and distinct execution/output directories, then check both outputs before comparing their required fields: ```bash cd chapters/ch2 bunx hankweave@0.10.0 hank.json task-data --headless --start-new --execution exec-a --max-cost 9 --shim-idle-timeout 1800 --overwrite-output -o out-a bunx hankweave@0.10.0 hank.json task-data --headless --start-new --execution exec-b --max-cost 9 --shim-idle-timeout 1800 --overwrite-output -o out-b python3 ../../verify.py chapter 2 out-a python3 ../../verify.py chapter 2 out-b python3 ../../verify.py compare-json out-a out-b ``` The shown `bunx` command uses the package's Node entrypoint, so use Node `>=22.19.0`; `npx hankweave@0.10.0` is the equivalent npm launcher. These fixture commands assume Bun and Git are installed and are run as a non-root user. Chapters are directories, not checkpoint tags (saved run markers). Ch1–ch2 use `ANTHROPIC_API_KEY`; ch3–ch5 and the full anchor add `BASETEN_API_KEY`. A passing preflight is not evidence that the Baseten key is valid. For recovery, reuse the same chapter-local `task-data/` and execution without `--start-new`; do not present an unperformed recovery or comparison as a capture. The chapters build on each other. Ch1 is the smallest complete run. Ch2 adds checksum, shape, and watermark preflight before the Beacon and Cedar normalizers. Ch3 adds the judgment layer and its validated-record and exception-ledger outputs. Ch4 adds reconciliation, `onExceeded: fail`, the quality observer, and budgets. Ch5 adds the survey and award steps and records the full eight-supplier scope. Its completed capture is evidence for the seven-codon run and measured cost; it is not, by itself, an interruption-recovery transcript. The progression is cumulative, but each directory has its own `hank.json`, expected capture, and self-contained task-data recipe. These chapter-local copies are not one shared physical directory. If you reuse an existing prepared copy from a new working directory, pass the correct relative data argument; do not change the recipe's checker paths. Work through these directories in the [tutorial](/0.10.0/files/tutorial/0-tour), ending with [Break, Resume & Inspect](/0.10.0/files/tutorial/5-break-resume-inspect). For the rollback model, see [checkpoints](/0.10.0/files/concepts/checkpoints). ## The anchor run The chapters culminate in the anchor hank, the full seven-codon pipeline run end to end against the held-out oracle. Its capture is the strongest evidence on this page, and it deserves a careful reading of what it does and does not establish. Run the anchor recipe from `anchor-hank/`, keeping its prepared `task-data/` for validation, execution, checks, and repeats: ```bash cd anchor-hank python3 ../verify.py prepare-data ../quote-template-unification task-data bunx hankweave@0.10.0 hank.json task-data --validate bunx hankweave@0.10.0 hank.json task-data --headless --start-new --execution exec --max-cost 9 --shim-idle-timeout 1800 --overwrite-output -o out python3 ../verify.py anchor out bun rigs/render-exceptions.ts out --check && bun rigs/render-award.ts out --check ``` For an independent anchor attempt, retain `task-data/` and use `--start-new` with separate execution/output directories, then run `python3 ../verify.py anchor out-a` (and the corresponding check for `out-b`). To recover an interrupted run, use the same anchor-local `task-data/` and execution without `--start-new`; a separate chapter-local `task-data/` is not the same physical directory. The anchor uses `haiku` for `normalize-aster`, `normalize-beacon`, `normalize-cedar`, `survey-and-extracts`, and `award-brief`; `validate-and-repair` and `reconcile` use `pi/baseten/deepseek-ai/DeepSeek-V4-Pro`. The configured per-codon caps are $0.50, $0.50, $0.50, $1.50, $3.00, $2.00, and $1.00, totaling $9.00; that is configuration arithmetic, not a bill or universal retry ceiling. The capture row below summarizes the verified outcome. | codons | oracle result | exception rows | tracked codon cost | captured | | -----------: | --------------------------------------- | -------------: | -----------------: | ---------- | | 7/7 complete | 40 data rows match `truth/expected.csv` | 8 | $0.88303367 | 2026-09-06 | The current capture's `unified-records.csv` matches all 40 rows in the held-out truth, and `exceptions.csv` contains eight rows covering the eight hazard types: `DEDUP_CONFLICT`, `NO_BID`, `EXPIRED_VALIDITY`, `PAGE_SPLIT_LINE`, `UNRESOLVED_PRICE`, `LOW_CONFIDENCE`, `NOTE_ROUTED`, and `UNKNOWN_TEMPLATE`. The five structured native exports are parsed by `rigs/native-inputs.ts`, which preserves their source line or block identifiers, native annotations, TSV currency, and OCR warnings; it is ordinary code rather than a model-written extraction step. The survey begins incomplete and the agent inspects unmatched intake before the validation gate. The `$0.88303367` value is the tracked codon total for this one captured execution. Provider health checks and sentinel calls are separate. The current capture is not the historical 2026-09-02 run: that earlier run reached the same truth through four live iterations and cost about `$2.41`, so that amount is historical only. The ch4 and anchor sentinel configuration uses the full `anthropic/claude-haiku-4-5` registry ID, not the codon shortcut `haiku`. The anchor history records why: a short sentinel spelling produced `No LLM provider available`; budget aborts were logged as `aborted by user`. Those messages are historical diagnostics, not claims about the current tracked-codon total. Compare the current `unified-records.csv` with the held-out `truth/expected.csv` after a complete run: the contract is 40 data rows and eight exception rows, with GRN (Granite) quarantined rather than counted as a ninth quoting supplier. Related material: [Break, Resume & Inspect](/0.10.0/files/tutorial/5-break-resume-inspect) uses the anchor operations; [sentinels](/0.10.0/files/concepts/sentinels) covers the observer layer. ## Quickstart captures The smallest fixture on the page is also the first one most readers meet: the minimal-single-provider captures behind the quickstart's validation, run, expected-failure, completion, and example-output checks. The fixture is a one-codon hank named `summarize-notes`, using `haiku`, one prompt, and one checkpointed file (`checkpointedFiles` with one entry) alongside a fictional meeting-notes file in `data/`. Its five named captures record whether the output came from the actual service. | file | what it captures | actual\_service\_output | | --------------------- | ------------------------------------------------------------------- | ----------------------- | | `validate-output.txt` | `GOOD TO RUN!` validation box | true | | `run-transcript.txt` | startup banner, execution directory, hank structure, and server box | true | | `fail-no-key.txt` | expected failure when `ANTHROPIC_API_KEY` is unset | false; expected failure | | `final-events.txt` | `codon.completed` and shutdown events | true | | `summary-example.md` | one real codon output from the fictional notes | true | `validate-output.txt`, `run-transcript.txt`, `final-events.txt`, and `summary-example.md` are real 0.10.0 captures using `haiku`; the manifest records $0.01394590 in tracked codon cost for the run, while provider health checks and sentinel calls are separate. `fail-no-key.txt` is an expected-failure capture with `ANTHROPIC_API_KEY` unset. `--validate` checks configuration, paths, and the provider/credential catalog without running codons or provider health checks; it is not a connectivity proof and it is not a promise of being fully offline or read-only. Runtime startup separately performs provider health checks, which can be billable and are outside the tracked-codon total. The summary content is fictional because it comes from the fictional meeting-notes fixture. The captures below follow the order you will see them. For validation, look for the quickstart readiness box: *`hankweave@0.10.0` · `validate-output.txt`.* ```text ╭─ GOOD TO RUN! ─────────────────────────────────────────────────────╮ │ 1 codons • 1 prompts • 0 system prompts • 0 rigs • 1 checkpoints │ ╰────────────────────────────────────────────────────────────────────╯ ``` At startup, look for the version banner and server markers: ```text ╭────────────────────────────────────────────────────────────────────╮ │ Hankweave v0.10.0 │ │ darwin arm64 • node v23.8.0 │ ╰────────────────────────────────────────────────────────────────────╯ ``` ```text ══════════════════════════════════════════════════ Hankweave Server Started WebSocket: ws://localhost: ══════════════════════════════════════════════════ ``` With the key missing, expect this authentication failure: ```text [] [ERROR] Self-test completed: FAILED [] [ERROR] Self-test FAILED: Some checks failed [] [ERROR] - authentication: ✗ No authentication found (set ANTHROPIC_API_KEY) [ERROR] Server startup failed! ``` After the codon finishes, look for the completion and shutdown events: ```json {"id": "", "timestamp": "", "type": "codon.completed", "data": {"codonId": "summarize-notes", "success": true, "cost":"", "duration":"", "exitStatus": {"type": "success"}}} {"id": "", "timestamp": "", "type": "state.transition", "data": {"transitionType": "RunCompleted", "runId": "", "transition": {"type": "RunCompleted", "data": {"runId": ""}}, "resultingState": {"currentRunId": null, "runCount": 1, "totalCost":"", "currentRunCost":""}}} ``` Finally, the output example is fictional meeting-summary content from a real capture: ```markdown - **Decision:** Go with the Calloway quote for packaging line refit - **Owner:** Devon - **Deadline:** PO issued by Friday the 12th ``` To run this fixture yourself, follow the [Quickstart](/0.10.0/files/start/quickstart). For execution directories and checkpoints, see [the run model](/0.10.0/files/start/how-a-run-works). ## Licensing and regeneration Before reusing or regenerating the corpus, check its synthetic-data labels, service-output markers, and license caveat. Every manifest entry carries `data_class: "synthetic"`. Every hand-authored contract fixture in `digitized/` carries `actual_service_output: false`. The anchor and minimal-provider captures that make real API calls carry `actual_service_output: true`; the minimal-provider missing-key file is an expected failure. The merged provenance names `corpus-spec.md` as the specification, `generator/gen-corpus.ts` as the generator, and `generator/check-invariants.ts` as the checker; the final invariant state is 76/76 checks passed. The buyer is Northstar Components; its eight suppliers, `NC-100x` part numbers, USD-cent prices, and dates–rev-A 2026-01-03, rev-B 2026-01-05, quotes 2026-01-10, and award 2026-02-01–are invented. “Datalab” and “Reducto” are digitizer-output-shape tags, not attribution to real vendor output. The corpus license is CC0-1.0 pending project-counsel confirmation. Its `generator_commit` is `n/a -- working directory is not a git repository at generation time`. The notice below ships inside the corpus itself, so the synthetic-data label travels with the files. ```text FICTIONAL TRAINING FIXTURE — NOT CUSTOMER DATA Every document in this corpus is fictional. Buyer (Northstar Components), RFQ NC-RFQ-0042, all suppliers, part numbers, prices, and case details are invented for testing/tutorial purposes. No real customer, vendor, or transaction data is represented. data_class: synthetic. License: CC0-1.0 (pending project-counsel confirmation -- see forge-report.md OQ). "Datalab" and "Reducto" appear only as digitizer-output-shape tags on fixture filenames/adapters (matching corpus-spec.md's own file inventory), not as case-study attribution. ``` The generator and checker are deterministic–same inputs and the same generation steps reproduce the tree byte-for-byte. They do not use `Date.now()`, `Math.random()`, or filesystem-order-dependent iteration. A clean removal and rerun was verified by a recursive diff with no differences. The final checker state is 76/76 checks passed. The recorded regeneration invocation is: ```bash bun generator/gen-corpus.ts corpus/ bun generator/check-invariants.ts corpus/ ``` > **VersionNote:** All fixture captures were produced against the published `hankweave@0.10.0` artifact; if the runtime changes checkpoint format, event payloads, or cost reporting, the captures must be regenerated. Related material: [The examples index](/0.10.0/files/examples/index) explains how checked fixtures are used; [how the docs are generated](/0.10.0/files/contribute/documentation-pipeline) explains generated reference pages.