Production
What it cost to build this dataset — recorded as the work happened, with unmeasured distinguished from zero.
A dataset with opinions about numbers that arrive without a method owes the same scrutiny to its own. So this page records what it cost to build what you are reading, batch by batch, written down as the work happened rather than reconstructed afterwards.
The rule this file is built around: null means NOT MEASURED. It never means
zero. A genuine zero — a deterministic script that makes no model call — is
written as 0 with an explicit basis for how that was verified. An unmeasured
cost is never written as a figure and least of all as 0, and CI rejects a
batch that tries. That guard exists because a sibling studio tool once estimated
every agent run at $0 and duly reported a budget that could never be breached.
Batches
| Batch | Method | Produced | Model cost | Cells closed |
|---|---|---|---|---|
founding-seed2026-07-21 |
console | 13 records, 4 signals, 13 claims, 13 registers, 6 definitions, 20 cells | — not measured |
none |
cadw-castles-import2026-07-21 |
importer | 104 signals, 104 records, 1 cells_closed | $0 measured |
fortified_residence/GB-WLS |
cadw-wikidata-disagreements2026-07-21 |
importer | 359 disagreements, 2 records_corrected | $0 measured |
none |
ie-smr-castles-import2026-07-21 |
importer | 4552 signals, 4551 records, 1 cells_closed, 1 records_corrected | $0 measured |
fortified_residence/IE |
ie-corroboration2026-07-21 |
importer | 321 disagreements, 317 records_corroborated, 3 records_corrected, 1690 records_renamed | $0 measured |
none |
founding-seed
The founding: six definition bands, thirteen structure records chosen to stress the band boundaries, thirteen graded count claims, thirteen registers with their queries, and the twenty-cell coverage grid. Hand research and hand authoring throughout — no research agent has run against this repo.
Cost basis. NOT MEASURED, and the gap is structural rather than an oversight. The studio cost ledger journals gnome runs by run_uid; this batch was authored in an interactive console session, which the ledger does not see at all. There is no per-session token accounting to read after the fact, so any figure here would be a reconstruction. run_ref is null for the same reason — there is no run to point at. This is the most expensive batch in the file per artefact produced, by a wide margin, and it is the one with no number. That asymmetry is worth keeping visible rather than quietly filling in.
cadw-castles-import
Stage 1 + 2. The 104 scheduled monuments Cadw classes SiteType=Castle, imported as one signal each and resolved into one record each, closing the first coverage cell in the dataset. Every verdict from this batch is marked assessment: register-derived and carries confidence: low — the register asserted its own typology, nobody assessed these structures against this project’s criterion.
Cost basis. A genuine zero, not an unmeasured one. scripts/import_register.py is a deterministic transform that makes no model API call — verifiable by reading it, and by the fact that it runs in CI against a committed snapshot with no credentials of any kind in scope. The zero is a property of the design, not an estimate. actions_minutes is null rather than 0: the transform does consume CI time, and that time has simply not been attributed to this batch yet. Reconcilable later against the studio’s monthly Actions usage report via the workflow run id.
cadw-wikidata-disagreements
Stage 4. Cadw joined to Wikidata on P3007 (Cadw Monument ID) — an identifier join, never names. 359 disagreements: 258 granularity, 89 band-conflict, 12 category-error. Two records inside the closed Welsh cell were corrected from register-derived yes to contested, which reduced the fortified_residence register-derived count from 104 to 102.
Cost basis. A genuine zero. scripts/analyse_disagreements.py is a deterministic join over two committed snapshots and makes no model call. The expensive part of this batch was not compute at all — it was the four rounds of correcting the band mapping when the first passes produced accusations the evidence did not support, and that cost sits in the unmeasured console column like all judgement does.
ie-smr-castles-import
Stage 3a. All 4,552 SMR records under MONUMENT_CLASS LIKE ‘Castle%’, closing the Irish fortified_residence cell — the second complete cell and the largest closable population attempted so far.
The import also CORRECTED the dataset. Trim Castle was hand-authored at founding with SMR ref ME036-021; the register’s actual ref is ME036-048004-, and because the ref did not match, the importer created a second record for the same castle under its register townland (Manorland) and pushed the cell one over the register total. Fixed by making adoption REF-BASED rather than path-based — identifiers, never names, the same discipline the disagreement ledger uses. The founding caveat that hand-entered register refs needed verification was justified on the first one checked.
Cost basis. A genuine zero: scripts/import_register.py makes no model call. Fetch was 3 paginated requests against a public CC-BY service (the endpoint caps a response at 2,000 features); transform took ~5s and the full Jekyll build 16s at 4,668 records, which is what settled the open question about whether this scale is renderable at all.
ie-corroboration
Depth rather than breadth. Ireland joined to Wikidata on P4057 (Irish Sites and Monuments Record ID), adding 321 comparison rows and corroborating 317 records against a second independent register — confidence low -> medium, with the verdict left register-derived because corroboration is evidence, not assessment.
Three defects in the previous batch were found and fixed:
- ~1,690 Irish records (37%) were named after Ordnance Survey ANNOTATIONS rather than names — ‘Not indicated’ (949), ‘Castle’ (443), the literal string ‘NULL’ (165), ‘Hachured’ (130) — and because ids derive from names, identifiers like ie-calverstown-demesne-indicated were baked in. Now falls back to ‘Castle at
', which claims nothing it does not know. - The importer only ever wrote files, so changing the id rule left thousands of orphans and the register appeared to hold more structures than it does. It now owns and removes its own residue.
- That orphan sweep deleted a hand-authored record on its first run (Dun Aonghasa), because an ABSENT assessment field was read as not-adopted. The schema defines absent as assessed. Deletion now requires a positive register-derived marker, never the lack of one.
Cost basis. Deterministic; no model call. As with the Welsh comparison, the real cost was judgement rather than compute — this batch found and fixed three defects in work shipped hours earlier, and that debugging sits in the unmeasured console column.
What this is for
The comparison worth making is cost per artefact by method, and it is stark enough that it changes how the rest of the dataset should be built.
The founding batch produced 13 records by hand, in an interactive session, and its cost is unmeasured — there is no per-session token accounting to read after the fact, so any figure would be invented. The Cadw import produced 104 records and 104 signals for a measured $0, because a register row is a mechanical transform and mechanical transforms are code, not agents.
That is the argument for the whole import pipeline. Ireland’s two open cells hold 4,552 and 31,431 entries between them. Pushing 36,000 records through a language model would cost more than the studio’s entire monthly budget to produce something a script produces for nothing — and would produce it worse, because a model asked to transcribe a register row will occasionally decide to be helpful about it.
What the numbers here cannot tell you
Three honest gaps, stated rather than papered over:
- The expensive batch is the one with no number. Console authoring is by far
the most costly work per artefact and it is the one this ledger cannot price.
The studio’s cost ledger journals agent runs by
run_uid; an interactive session is invisible to it.run_refis null for that batch because there is genuinely no run to point at. - Actions minutes are not yet attributed. The import consumes CI time and
that time is real. It is recorded as
nullrather than0— reconcilable later against the studio’s monthly Actions usage report via the workflow run id, which is exactly whyrun_refexists as a field. - Cost is not value. The $0 batch produced 104 register-derived verdicts at
confidence: low. The unmeasured batch produced the six definition bands, the claims ledger, and every contested verdict on the site. Cheap and valuable are different axes, and the cheap batch is not the one doing the intellectual work.
The raw ledger is production.yml; its schema is
production.schema.json.