ARENA_JOIN_PACKAGE.md

systems/ARENA_JOIN_PACKAGE.md

THE ARENA JOIN PACKAGE — the arena-to-environment-feature join, emitted and adjudicable

CANON SUBORDINATION — this document is PROPOSAL-TIER: it serves canon and never outranks it.
The canon: the CVD · the T1 foundation docs · the T0 registries (registries/) · the spine
(docs/spine/CH_*.md) · the region pages (_source/02_Tier_2_Region_Pages/). Authority order:
docs/DOC_MAP.md § 0.
Canon served: _source/02_Tier_2_Region_Pages/flores_island.md § Zone Catalog (and the 14
sibling pages' Zone Catalogs) ·
registries/T0_Environment_Grammar_Registry [DRAFT v0.1] · registries/T0_Boss_Attack_Rail [DRAFT v0.1] ·
registries/T0_Region_Index [ACTIVE v1.2] ·
_source/01_Tier_1_Foundation/T1_Combat_System_Spec [ACTIVE v1.0] § "Nature-Derived Counter Classes" ·
docs/spine/CH_02.md
READ THAT CANON FIRST. **If this document disagrees with canon, CANON WINS and this document is
the defect.** Nothing here is applied until a director ratifies it.
THIS LANE MINTS NOTHING. No id was allocated, no registry row was written, no region page was
touched, no gate was run. The id-mint brief in §6 routes to the director (the A16 vetoable precedent).

Pipeline row: A13 arena-mutation framework (docs/PIPELINE_LEDGER.md L102 — next step

*"SCHEMA: the arena-to-env-feature join (the gate's named work order). THEN the Naga Padoha exemplar.

Rides A12"*). Work order source: docs/proposals/boss_rail_exemplar/BOSS_RAIL_EXEMPLAR_BE_0002.md

§8 (schema brief 2) and its S3/S5/S6/S7/S8 findings. Deliverable pair: this package and

harness/emit_zone_registry.pydocs/proposals/combat/zone_registry_proposed.csv

(113 proposed zone rows, 15 pages, 0 parse failures, 0 ids minted) — of which **29 rows derive

from three pages that are NOT at HEAD**; read the provenance disclosure below before acting on any

count in this document.

---

0. DERIVATION

0.0 PROVENANCE DISCLOSURE — three source pages are not at HEAD

**Three of the fifteen Zone Catalogs this package reads are UNTRACKED working-tree files, not

committed canon:** _source/02_Tier_2_Region_Pages/arabia_persia.md, levant.md and

mesopotamia.md. They are another lane's unlanded work. This package cites all three as canon

authority (§0 below, §2.2, §3.1, and finding F2), and that citation is only as good as their

landing.

Observed state, recorded with its timestamp because it can change under this document. Checked

2026-08-07T23:10Z against HEAD 924e0d09: git status --porcelain reports all three as

?? (untracked), and git cat-file -e HEAD:<path> fails for all three — they are ABSENT at HEAD,

not merely modified. The same state is re-verified mechanically on every emit and written to

docs/proposals/combat/zone_registry_proposed.manifest.json, so a later reader never has to trust

this paragraph's date.

What the three pages contribute, measured.

three 10-column pages that deliberately do not carry the T0.2 extension pack (§2.2). They

therefore add nothing whatever to the join this package exists to build — every one of the

253 EG tokens comes from the twelve pages that ARE at HEAD.

84 zones across 12 pages, and because mint_ordinal_proposed is a single alphabetical

sequence over all pages, 79 of those 84 HEAD zones take a different ordinal depending on

whether the three pages are present. The ordinal is the proposed allocation ORDER (§6), so

minting against the wrong state does not just add or remove 29 ids — it renumbers almost the

whole table.

The consequence for the mint is a named hard prerequisite; see §6. Nothing else in this package

changes: the schema, the arena_zone_ref recommendation and all five S-findings are derived from

the twelve HEAD pages and the registries, and none of them turns on a row from the three.

DERIVED FROM

*"A1 cover / trigger_interrupt DECLARED NOT-ARMED: their answer universes exist in

T0_Environment_Grammar_Registry (tactical_affordance_class COVER; attack_verbs / loaded_potential /

enemy_usable) but are answered PER ARENA, and no arena-to-env-feature join exists in the schema, so

both WARN and neither can pass clean. The join is the named work order."* This package is that work

order; L555-564 (A5d, A1 weak_point judged on the row) and L570-585 (the parry universe declared

UNREACHABLE) were read alongside it so the two briefs stay separable.

Classes" — L635 *"An arena-wide attack is answered by neither, and the response vocabulary

expands to meet it: take cover behind rock, pillar, or whatever else the arena affords; strike a

weak point; or trigger a reaction that stops the boss or the hazard before it lands."*; L647

Cover's data home (*"T0\_Environment\_Grammar\_Registry tactical\_affordance\_class, whose declared

enum already carries COVER"*); L649 Trigger interrupt's data home (*"attack\_verbs,

loaded\_potential, and enemy\_usable, which is the same affordance set the factory contract already

requires of every arena"*); L637 the move-fits-the-body-and-the-arena clause; L651 the seven data

tokens. The two arena-wide classes name a registry and a per-arena scope, and the scope has no key.

L40-47 the preamble that declares the column ownership split (*"Rows sourced from spine §3b

site_ids copy terrain / functions / ambient_threat / vril_density / climactic_affordance / protected

VERBATIM from the CH_02 and CH_03 site rows; the page-authored columns are the page-side geometry

… plus the T0.2 extension-column pack"*), L49 the 20-column table header, L50-60 the eleven

data rows. L52 kelimutu_crater_lakes environment_grammar_refs EG_0003;EG_0009;EG_0010;EG_0011

and L53 mount_inerie_cone_country EG_0003;EG_0004;EG_0005;EG_0012 — the two BE_0002 phase

arenas. This is the join, and it is a markdown table.

UNTRACKED, not at HEAD — §0.0):

angkor_khmer.md L59/L70 · arabia_persia.md L80/L100 · bali.md L39/L47 ·

central_africa_congo.md L41/L51 · ethiopia.md L41/L50 · levant.md L63/L74 ·

mesopotamia.md L52/L64 · rift_valley.md L52/L68 · south_africa.md L72/L88 ·

south_india.md L46/L54 · sri_lanka.md L42/L55 · sumatra_java.md L50/L61 ·

swahili_coast.md L41/L51 · west_africa.md L40/L50 (section header line / table header line).

Read in full at Zone Catalog grain: flores_island.md, bali.md, arabia_persia.md,

swahili_coast.md — the three live column variants plus the pilot. The input contract generalizes:

every one of the fifteen opens with the same ten base columns in the same order, and the

variants differ only by which extension columns follow (§2).

read and rows sampled at EG_0001/EG_0002/EG_0003 and across every tactical_affordance_class. The

join target column is env_feature_id; the answer columns the two arena-wide classes need are

tactical_affordance_class (COVER), attack_verbs, loaded_potential, enemy_usable, and the

care columns protected_care_ref / alteration_permanence_default (hard_blocked).

than carried from prose: phase 1 = 11 rows, phase 2 = 8; counter classes any 8 · dodge_only 8 ·

cover 1 (AT_0011, phase 1) · trigger_interrupt 1 (AT_0005, phase 1) · weak_point 1 (AT_0019,

phase 2) · parry_only 0 · neutralize 0. telegraph_shape values: 6 rows inside the proposed

closed key, 13 outside it. tell_shape_class 16 families (14 used once); tell_motion_class

19 families (19 of 19 used exactly once).

L141 CH02_B07 (site mount_inerie_cone_country · boss BE_0002.P1), L146 CH02_B08

(site kelimutu_crater_lakes · boss BE_0002.P2), and L85/L87 the two §3b site rows those zone rows

copy. The per-phase arena binding is canon; it is simply not data.

fifteen region-page slugs resolves to a region_id (verified, 15/15), which is what makes

region_id an FK rather than a label.

_note naming the answer homes (*"cover and trigger_interrupt = T0_Environment_Grammar_Registry

(tactical_affordance_class COVER, and attack_verbs / loaded_potential / enemy_usable)"*), the four

FKs, the composite-uniqueness tooth on (boss_id, attack_id), and the closed struct-mirror

exception on the first nine columns.

(the only specification of telegraph_shape's ten-member closed key at L1128, attack_kind's five

members, tell_shape_class / tell_motion_class as enums, and phase_index as an int); L1152-1156

the consumers.

the OUTCOME; the scale is ORDINAL and no number is ruled) and L1028-1031 (the ordinal mitigation

column *"mints with that rail's first authored moveset at window-plan rank 16 — a column with no

rows behind it is a promise, not a shape"*) — the S6 trigger, quoted because the recommendation

turns on its own words.

AUTHORSHIP OF THAT PARAGRAPH, verified because §5.3 rests on how much authority it carries.

It is loop/director landing prose, not Josh verbatim. §10 opens at L974 and carries exactly

one Josh-attributed block, L976-981, introduced *"Josh, verbatim:"* and quoting him on

the elemental parry and the mitigation scale — *"There's need to be a scale there. Not all

'parry's' … will negate 100% damage"*. **Josh's quoted words say nothing about a column, a

registry, a mint, or a trigger.** The L1028-1031 paragraph sits far below that quote, inside the

loop's own landing record — it follows L1020 *"Landing sites (all applied the same day):"*

and is headed *"One queued item, deliberately not minted:"*. The next Josh-verbatim marker in

the file is L1035, in the following section (§11). So the "first authored moveset" trigger is the

loop's own scheduling note recording how it chose to sequence a mint — binding as prior loop

discipline, and squarely a director-adjudicable call, not a Josh ruling that would have to go

back to him.

Head of the file read for prior rulings per contract §7: the 2026-08-04

board is RULED, including the standing derive-don't-board law and the care-does-not-ACCRETE law —

no care column is proposed here.

whole package serves: *"the W-SPACE affordance list per arena doubling as the boss's mutation

vocabulary (the environment the arena offers is the environment the boss can weaponize — one

authored list, two consumers)."* The authored list is environment_grammar_refs; the second

consumer is the rail.

L101 (A12), L250 (the wave-2 ordering), and L263-284 (the beyond-floor VETOABLE block, including

VETOABLE 4 — *"minting a registry is a canon-adjacent act and is named here rather than done

silently"* — the precedent this package's §6 follows).

harness/extract_zone_catalog.py L46-83 (snake, parse_zone_rows) — imported, never

re-implemented, so all four Zone Catalog tools agree byte for byte on where the block is.

ONLY for what it carries: Pillar-8 blended mode (*"every boss blends combat plus weapons plus

abilities plus puzzles plus character engagement. No boss is a pure DPS check"*), the Ch 17 Entu

Priestess three-phase template and its narrative-tentpole scope, and the monster/honored-adversary

exemption. The words "evolve" and "swap" do not appear in it. The exemplar dossier

(BOSS_RAIL_EXEMPLAR_BE_0002.md S5) attributes evolve-not-swap to this hard line; that

attribution is a mis-citation, corrected here — and it is the same class of defect

docs/FUN_REBUILD_PLAN.md L70 already caught and re-attributed once (*"NOT HL_0078, which is the

Pillar-8 blended-boss hard line — critic re-attribution"*).

docs/COMBAT_ENCOUNTER_SYSTEM.md L364 — the worked example's phase-2 step, *"P1's sweeps are

still live (evolve-not-swap)"* — and L609, which names it inside the RULED build target

(*"The per-chapter build target (2-4 thread-woven sub-bosses → one main boss, primary+secondary

verb, three-axis split, evolve-not-swap phases, ≥2 counters, Hades reward on win and death) is a

RULED work order"*). Corroborated on the spine at docs/spine/CH_02.md L97 — *"phase

escalation that evolves the moveset"* — which is the sentence BE_0002's own chapter states, and

which itself carries the [SRC: T0_Hard_Lines @ HL_0078] tag that propagated the mis-citation.

NOT DERIVED (authored judgment, and why it had no canon home)

1. The emitter's ten LEAD columns and two DIAG columns (mint_ordinal_proposed, zone_key,

region_id, source_page, source_line, spine_sourced, chapter_ids, source_site_ids,

source_site_ref_raw, diag_columns_absent_on_page, diag_eg_refs_unresolved). No zone registry

exists anywhere in the 76-registry corpus, so no schema shape was available to mirror. Eight of the

twelve are derivations of cells the pages already carry (the source cell splits into chapters and

site ids; the page path and line are the citation); four are emitter bookkeeping. Every one is

director-vetoable in isolation and none carries content the pages do not.

2. The ZONE_\d{4} id-space proposal and the sequential allocation scheme (§6). The corpus's

other id spaces are the evidence, not a rule anyone wrote.

3. The five S-finding recommendations (§5). These are schema readings over silences the canon

deliberately left — each is presented with its status quo, its alternatives, and the strongest

objection, for a director to adjudicate. None changes a canon number, name, hard line or §17 cell.

4. The arena_zone_ref column name. The dossier names the shape (§8, *"either arena_zone_ref

on T0_Boss_Attack_Rail … or a phase → zone_id map on the boss row"*); the spelling is this

lane's.

---

1. THE FINDING, RESTATED FROM CANON

Two of the seven counter classes name an answer universe that exists and a scope that does not.

(T1_Combat_System_Spec L647).

enemy_usable (L649).

arena. The gate therefore WARNs both and neither can pass clean (check_counter_class_coverage.py

L565-569).

The join is not missing. It is unreachable. It lives in the region pages' Zone Catalogs as the

environment_grammar_refs column — flores_island.md L52-53 is the whole BE_0002 fight's arena

grammar, in a markdown table. The chain from a boss row to that cell today is: boss row → chapter_id

→ spine beat prose → site_id → region-page table row → environment_grammar_refs → EG row. Four

hops, two of them prose.

The ruled direction this lane inherits: EMIT, do not hand-author. The pages are the authority and

stay it; the registry is a projection of them that can be regenerated when they change. That is the

same discipline regen_zone_catalog.py already enforces in the other direction.

---

2. THE EMITTER — harness/emit_zone_registry.py

What it does. Walks every .md under _source/02_Tier_2_Region_Pages/, parses each page's

## Zone Catalog table, and writes one proposed zone row per catalog row to

docs/proposals/combat/zone_registry_proposed.csv. Stdlib only. Deterministic: two runs are

byte-identical (asserted in the self-test and verified on the live corpus).

The guards, because a proposal tool that can touch canon is not a proposal tool.

if it lands inside the registry tree. The self-test exercises the refusal by trying to write

registries/T0_Zone_Registry/Sheet1.csv.

mint_ordinal_proposed is a proposed allocation ORDER, not an id, and is named as such on the

column and in §6.

| zone_id header, a table with no data rows, a header that is not the ten base columns, or an

unparseable source-site cell is reported by page name with its reason and makes the run exit

non-zero. A page with no ## Zone Catalog header (README.md) is reported as *no catalog*, which

is a different thing and is not a failure. A zone_key that collides across two pages is

treated as worse than a malformed page: a global key that is not unique cannot be an FK target at

all, so the run names both pages and emits zero rows rather than keeping the first and dropping

the second.

zone_registry_proposed.manifest.json carrying the git SHA the emit ran against and every source

page that was UNTRACKED or DIRTY at emit time (today: the three of §0.0). A row derived from an

unlanded page is a fact about the table, and the manifest is what makes it visible to a reader of

the CSV instead of something to be rediscovered. The manifest is a pure function of repo state —

no wall clock — so both artifacts stay byte-identical across two runs.

exists under registries/, the emitter hard-fails with exit 4 unless

(region_id, zone_key) → zone_id preservation is implemented, which it is not; --preserve-ids

is declared so the guard can name it and fails the same way. That is §6's id-stability prerequisite

made mechanical, so the second emit cannot silently renumber the table.

REFUSED failure raised BEFORE the write, so a rejected path leaves nothing on disk.

Exit codes. 0 clean · 2 a named parse failure or any hard fail · 3 --strict with an unresolved

EG token · 4 a minted zone registry exists and id preservation is not implemented.

The self-test (--self-test, run over both CRLF and LF fixtures — region pages are CRLF, and the

newline handling is inherited from regen_zone_catalog.py for exactly that reason):

on every row; the ordinal 1..N in page order; region_id = page slug; a CH_90 alpha_ruin source

cell split into chapter_ids + source_site_ids with spine_sourced TRUE; a region-ambient

source cell yielding spine_sourced FALSE with the raw cell preserved; a comma-bearing cell

surviving verbatim and CSV-quoted in the bytes; environment_grammar_refs copied verbatim and

typed populated; an unresolved EG_9999 diagnosed rather than dropped; source_line a real

1-based page line; byte-identical re-emission; LF terminators regardless of the page's newline.

diag_eg_refs_state values in one run — a page without the extension pack (absent), and a page

with it carrying a populated cell, an empty cell and a literal none cell. It asserts the four

states are typed in order AND that only the populated row contributes an EG token, so empty and

none can never be counted as refs.

wrong cell count, (b) a duplicate zone_id, (c) an unparseable source-site cell, (d) a

table whose header is not the ten base columns, (e) a page with no catalog at all (asserted to

be a *no-catalog* report, not a failure), (g) the same zone_id on two different pages

each page valid alone, so the emitter's own cross-page branch is what must catch it — and

(f) an attempted write under registries/. In (a)-(d) and (g) the assertion is both that the

failure is NAMED and that zero rows are emitted — a malformed page never contributes a

half-parsed row, and an unkeyable table contributes nothing at all.

EMIT_ZONE_REGISTRY SELF-TEST: PASS (47 assertions — 23 per newline mode, plus the write guard).

2.1 The live run — counts

measurevalue
pages scanned16
pages with a Zone Catalog15 (README.md is the sixteenth and carries none)
zones emitted113
parse failures0
environment_grammar_refs tokens253, 0 unresolved against the 225-row registry
join state, by rowpopulated 78 · absent 29 · empty 5 · none 1 (§7, F2)
columns emitted31 (28 proposed schema + 3 diagnostic)
ids minted0
git SHA at emit924e0d09
source pages untracked or dirty3 — arabia_persia, levant, mesopotamia (§0.0)

Per page: arabia_persia 11 · flores_island 11 · levant 9 · mesopotamia 9 ·

central_africa_congo 8 · rift_valley 8 · south_africa 8 · bali 7 · ethiopia 7 · south_india 7 ·

sri_lanka 7 · west_africa 7 · angkor_khmer 5 · swahili_coast 5 · sumatra_java 4.

† = not at HEAD (§0.0). Every count in this table is a WORKING-TREE count. **Against HEAD state

alone the same emitter yields 84 zones across 12 pages.** The 253 EG tokens, the 0 unresolved, and

the populated 78 / empty 5 / none 1 states are all unchanged — the 29 excluded rows carry no refs at

all, so absent simply falls from 29 to 0 and the join itself loses nothing. What DOES change is

the allocation order: 79 of the 84 surviving zones take a different mint_ordinal_proposed. Both

numbers are real; which one is correct is decided by whether the three pages have landed at apply

time (§6).

2.2 The input contract, proved rather than assumed

The generalization claim is the one that decides whether an emitter is the right tool, so it was

measured rather than asserted.

source site_id(s) (spine §3b), terrain, gameplay functions, ambient_threat, vril_density,

climactic_affordances, protected, area_bounds, build_priority. The emitter asserts this and

fails the page if it ever stops being true.

levant, mesopotamia — the three untracked pages of §0.0, which deliberately do not carry

the T0.2 extension pack, arabia_persia L85-87 stating the reason: *"only

harness/apply_zone_catalog_columns.py may write them"*);

19 columns (central_africa_congo, ethiopia, rift_valley, south_africa, south_india, sri_lanka,

swahili_coast, west_africa); 20 columns (angkor_khmer, bali, flores_island, sumatra_java — the 19

plus zone_space_class).

values are globally unique** across pages. Both were checked, not assumed; both are the properties

a registry key needs.

different facts**, and the emitter keeps all three distinguishable rather than collapsing them into

a blank: diag_columns_absent_on_page lists the union columns that page's table does not carry at

all, and diag_eg_refs_state types every row absent · empty · none · populated. The three

10-column pages carry zone_bounds_wgs84 … footfall_surface_secondary as absent-by-design;

angkor_khmer carries environment_grammar_refs as present-but-empty, a populate-empty gap for the

env-grammar lane; and flores_island's manggarai_village_edge (L55) carries the literal token

none, which is an AUTHORED assertion that the zone affords nothing — the opposite of an

unauthored blank. Each belongs to a different lane (§7, F2).

(93 rows) and region-ambient / region-ambient (page-authored) (20 rows). Both are parsed; a

third shape would be a named parse failure, not a silent blank.

---

3. THE PROPOSED ZONE-REGISTRY SCHEMA

Twenty-eight columns, of which eighteen are the Zone Catalog's own columns copied verbatim and ten

are the key/provenance layer that makes the table joinable. Three further diag_ columns are emitter

output and are dropped at apply.

3.1 Key and provenance (authored — see §0 NOT DERIVED 1)

columnvaluemirrors / cited to
zone_idZONE_XXXX today; ZONE_\d{4} after the mintthe corpus's own EG_\d{4} / AT_\d{4} / BE_\d{4} convention. PK
mint_ordinal_proposed1..113, emitter ordera proposed allocation ORDER, not an id (§6)
zone_keythe page's own zone_id cellflores_island.md L49 col 1. The NATURAL key; page authority. Globally unique across all 113 rows (verified)
region_idthe page slugFK → T0_Region_Index.region_id (15/15 resolve)
source_pagerepo-relative page paththe authority the row projects
source_line1-based line of the row in that pagethe citation anchor. kelimutu = L52, mount_inerie = L53, matching the dossier's own cites
spine_sourcedTRUE / FALSEderived from the source cell: TRUE where it names CH_NN sites, FALSE for region-ambient page-authored zones (arabia_persia L92-98 names those six and calls them a FEED to the spine's site pass, never an assertion the spine rowed them)
chapter_idsCH_02;CH_03derived from the source cell. FK candidate → T0_Chapter_Index.chapter_id
source_site_idsliang_bua_cavederived from the source cell — the spine §3b site_id the row copies
source_site_ref_rawthe source cell verbatimnothing is lost to the split

3.2 The Zone Catalog's own columns, copied verbatim

Ten base columns minus the two the key layer re-expresses (zone_idzone_key, the source cell →

the three derived columns), leaving eight; plus the ten T0.2 extension columns.

columnmirrorsnote
terrainZone Catalog col 3SPINE-OWNED — copied VERBATIM from the §3b site row (flores_island.md L40-41; regen_zone_catalog.py L9-11)
gameplay_functionscol 4SPINE-OWNED
ambient_threatcol 5SPINE-OWNED
vril_densitycol 6SPINE-OWNED
climactic_affordancescol 7SPINE-OWNED
protectedcol 8SPINE-OWNED
area_boundscol 9PAGE-AUTHORED geometry (flores_island.md L44-46 — *"page authority, not spine canon"*)
build_prioritycol 10PAGE-AUTHORED
zone_bounds_wgs84T0.2 packPAGE-AUTHORED; written only by apply_zone_catalog_columns.py
meters_per_vertexT0.2 packas above
worldcover_biomeT0.2 packas above
footfall_surfaceT0.2 packas above
care_tierT0.2 packas above. Mirrored, never widened — the 2026-08-04 care-does-not-ACCRETE law binds
asset_routingT0.2 packas above
environment_grammar_refsT0.2 packTHE JOIN. A ;-delimited FK list → T0_Environment_Grammar_Registry.env_feature_id. 253 tokens across 78 rows, 0 unresolved
zone_space_classT0.2 pack (4 pages)as above
ambient_population_bandT0.2 packas above
footfall_surface_secondaryT0.2 packas above

3.3 The declared FKs the mint would carry

the composite is the safe declaration because zone naming is page-local by construction.

which is correct rather than missing).

0 today because 35 of 113 rows carry no ref, in three distinct ways: the column ABSENT from

the page (29), PRESENT-BUT-EMPTY (5), and the literal token none (1) (§7, F2). A floor the table

cannot meet is a rusted tooth. Note that only two of the three are gaps: none is authored.

3.4 The regeneration contract, which is the whole point

The registry is a PROJECTION. emit_zone_registry.py must gain a --check mode at apply — the same

shape regen_zone_catalog.py --check already has — that re-emits and asserts the registry matches the

pages, so a page edit that is not carried into the registry is a reported finding rather than silent

drift. A hand-edit to the emitted registry is a defect by construction; the fix always lands on the

page. That mode is not written here because there is nothing to check against until the mint.

---

4. THE RAIL COLUMN — arena_zone_ref

**RECOMMENDATION: one new column on T0_Boss_Attack_Rail, arena_zone_ref, landing at position 28

after the three J5 elemental columns.** This is the dossier's own recommendation (§8: *"Recommend the

rail column: it is one column, it puts the answer beside the demand, and it lets A1 judge cover and

trigger_interrupt row by row instead of declaring them not-armed"*), and reading the 19 rows against

the two arenas confirms it rather than merely repeating it.

Which of the 27 columns it joins to.

CH_02.md L141 site mount_inerie_cone_country · boss BE_0002.P1, L146

site kelimutu_crater_lakes · boss BE_0002.P2 — and the two zones carry *different* affordances

(flores_island.md L53 vs L52). A per-boss binding would be wrong on this boss, which is the whole

evidence for per-row.

tactical_affordance_class = COVER, and trigger_interrupt against refs with enemy_usable = TRUE

and a non-none attack_verbs.

phase; the boss row does not need a second copy of it.

because *the rail has no column for it* (dossier §5). Those cells stay as the reasoning; the column

becomes the check.

Type. arena_zone_ref → FK T0_Zone_Registry.zone_id, min_tokens 0. Blank must stay legal —

the rail is header-only across the other 267 movesets, and a boss whose phase sites the spine has not

typed cannot be made to invent one; a floor the table cannot meet is a rusted tooth, which is the same

reasoning fk_spec.json already applies to every other rail FK. On BE_0002 all 19 rows bind,

because the spine types both phase sites (L141, L146). It is deliberately a single ref rather than a

list; see the S5 interaction below, which is the one case that argues otherwise and is answered there

by phase_live_through instead.

The migration for the 19 existing BE_0002 rows. Recomputed from BE_0002_rail.csv, never carried

from prose:

rowsphase_indexarena_zone_refauthority
AT_0001 … AT_0011 (11 rows)1the zone minted for mount_inerie_cone_countryCH_02.md L141 (CH02_B07 · BE_0002.P1) → flores_island.md L53
AT_0012 … AT_0019 (8 rows)2the zone minted for kelimutu_crater_lakesCH_02.md L146 (CH02_B08 · BE_0002.P2) → flores_island.md L52

That is a mechanical, fully derived migration: the phase index already carries the answer, and the

spine already binds the phase to the site. It cannot be applied until §6's ids exist, and this lane

does not apply it.

What it buys immediately, checkable on the day it lands.

in mount_inerie's refs. The row passes A1 by resolution instead of by warning.

is the canon that demoted AT_0014 from cover to dodge_only at re-derivation (dossier §3). The

column turns that hand-caught defect into a gate-caught one, which is the argument for the column

in a sentence.

env_feature_id, so even a perfect arena join leaves it unjudgeable. That is a real open item and

the dossier names it (§8): decide whether boss-placed hazards get env rows — which

COMBAT_PROGRAM_ADDENDUM §6 L98-110 implies they must, since it specifies *"spawn-hazard"* as a

first-class arena_mutation sub-kind and *"hazard actors that BOTH sides interact with"* — or

whether the class splits into arena-trigger and hazard-interrupt. **Recommendation: give boss-placed

hazards env rows.** The addendum's own one-authored-list-two-consumers principle says the boss's

mutation vocabulary IS the arena's affordance list; a hazard the boss places that no data describes

is a third list. The split-the-class alternative buys nothing the env row does not, and costs a

vocabulary change to a Josh-ruled seven-member set.

terrain names WHICH terrain"*) is today a critic's reading. With the column, a row whose

arena_zone_ref resolves to a zone containing a protected_care_ref / hard_blocked feature can

be REQUIRED to name its feature explicitly. 58 of the 113 zones contain at least one such feature,

so this is not a corner case. No new care column is proposed — the existing cells become reachable,

which is the opposite of accretion.

Not recommended: a phase → zone_id map on the boss row. It is one cell instead of 19, but it

puts the answer one hop from the demand, cannot express a row that is live in two arenas, and leaves

A1 parsing a packed object to judge a row. The rail column is the cheaper check.

---

5. THE FIVE FINDINGS, AS OPTIONS PACKAGES

Each is a SCHEMA reading over a canon silence. None changes a canon number, name, hard line or §17

cell, so each is the director's to adjudicate and none goes to Josh (contract §7; the 2026-08-04

derive-don't-board law).

5.1 S3 — attack_kind cannot type a no-strike move

The finding. The five members (melee · ranged · cast · grab · arena_mutation,

MINT_DESIGN_B L1140) type a strike. Three of BE_0002's 19 rows are pressure, reposition and listening

(AT_0001, AT_0002, AT_0006) and carry an EMPTY attack_kind rather than a falsified melee — against

a spec that marks the column required: yes. Every B4 kit in the corpus carries no-strike abilities,

so this recurs across the remaining 51 slice rows.

optionproscons
A. Status quo — five members, no-strike rows blank, semantics undeclaredzero changethe column is spec'd required and 16% of the first moveset violates it; a gate cannot tell a deliberate blank from an unauthored one
A′. Declare the column NULLABLE, blank = no-strikezero enum change; matches what the exemplar already didblank is still ambiguous with unauthored; the meaning lives in an fk_spec note rather than in the data
B. Add a sixth member no_strikeone token closes it; the engine's dispatch question (does this row need a hitbox?) is answered in the cella negation as an enum member; conflates pressure / reposition / listening
C. Add stance insteadreads as a kind rather than an absence; familiar registerimplies a persistent posture state, which a silent approach is not
D. Add both stance and repositionpreciseenum inflation decided from three examples

RECOMMENDATION: B. The enum's job is engine dispatch, and one token answers it. The finer taxonomy

is already carried by tell_shape_class, which is the read channel; damage = 0.00 is the

corroborating cell on all three rows. Land it with a precedence note in fk_spec.json: where a

no-strike move also mutates the arena, arena_mutation wins.

Strongest objection. Enums of negations rot — the day a no-strike move spawns a hazard, both

no_strike and arena_mutation apply and the row can carry only one. Answered by the precedence

note above, which is why it is part of the recommendation rather than a footnote to it.

5.2 S5 — phase_index is a scalar and cannot express evolve-not-swap

The finding. The corpus's boss doctrine is evolve-not-swap: phase-1 rows stay live in phase 2.

Duplicating 11 rows to say so would break the composite uniqueness on (boss_id, attack_id) that

fk_spec.json declares.

Where evolve-not-swap actually lives — a citation corrected. The exemplar dossier's S5 homes this

in HL_0078. It is not there: the hard line's full 550-character rule_text carries Pillar-8

blended mode, the Ch 17 Entu three-phase template and the monster/honored-adversary exemption, and

the words "evolve" and "swap" do not appear in it. The doctrine's real homes are

docs/COMBAT_ENCOUNTER_SYSTEM.md L364 (*"P1's sweeps are still live (evolve-not-swap)"*, the

worked example's phase-2 step) and L609 (the RULED per-chapter build target, which lists

*"evolve-not-swap phases"* among its terms), corroborated on the spine at docs/spine/CH_02.md

L97 (*"phase escalation that evolves the moveset"*) — BE_0002's own chapter, and the line whose

[SRC: T0_Hard_Lines @ HL_0078] tag propagated the mis-attribution. HL_0078 stays cited here for

what it does carry: the phase TEMPLATE. Nothing in the finding changes — the doctrine is real and

ruled either way — but a schema argument that rests on a hard line must rest on the right one.

BE_0002's own phase_breakdown_object is the second, unaffected leg of the evidence.

The interaction this package found, which changes the answer. Under the FIRST-LIVE reading the

exemplar applied, AT_0011 (cover, arena_mutation, phase 1) stays live in phase 2 — in an arena

that carries neither its answer (EG_0005 COVER is in mount_inerie's refs, flores_island.md L53, and

NOT in kelimutu's, L52) nor its ingredient (EG_0004, the scree slope it releases, likewise phase-1

only). The same reasoning that correctly demoted AT_0014 from cover condemns AT_0011's phase-2

liveness. This is invisible without the arena join and becomes a gate failure the day the column

lands, so the two findings must be adjudicated together.

optionproscons
A. Status quo — scalar, semantics undeclaredzero changethe next author guesses; the exemplar already had to state the reading on AT_0001's notes
B. Declare phase_index = FIRST-LIVE, monotoniczero schema change, one fk_spec note; matches the exemplarcannot express a row that RETIRES — and the AT_0011 case proves one must
C. B, plus a nullable phase_live_throughexpresses retirement; composite uniqueness untouched; AT_0011 takes phase_live_through = 1 and the contradiction disappearsa second column to keep consistent with the first
D. Make phase_index a token list (1;2)one columnbreaks the int type and the engine's per-phase filter; MINT_DESIGN_B L1138 specifies int
E. Derive liveness from arena_zone_ref alone (a row is live where its arena is)no new column at allsilent on the 16 rows with no arena binding, and makes an FK carry phase semantics

RECOMMENDATION: C. Declare FIRST-LIVE monotonic AND add phase_live_through (int, nullable, blank

= through the final phase), gated so the only sanctioned early retirement is the arena-bound one — a

phase_live_through earlier than the last phase is legal only where the row's arena_zone_ref names a

zone the later phase does not use. That keeps the hard line intact and fixes AT_0011 with a derivation

rather than a judgement call.

Strongest objection. Evolve-not-swap (COMBAT_ENCOUNTER_SYSTEM.md L364/L609) means the moveset

EVOLVES, and a retirement column invites authors to swap movesets by retiring rows — the exact thing

the ruled build target forbids. Answered: the doctrine forbids swapping the moveset, not retiring

a move whose ARENA is gone; the gate condition above makes that the only legal use, so the column

cannot become a swap mechanism. Note the objection is now weighed against a RULED work order rather

than a hard line — a real difference in force, and the honest one: the corrected citation makes this

doctrine, strongly ruled, rather than HL-severity canon, which slightly LOWERS the bar this option

must clear and is stated here rather than quietly enjoyed.

5.3 S6 — the ordinal mitigation column

The finding. DECISIONS_PENDING_JOSH L1028-1031 queues the column explicitly: it *"mints with

that rail's first authored moveset at window-plan rank 16 — a column with no rows behind it is a

promise, not a shape."* BE_0002 is that moveset. **That paragraph is loop/director landing prose, not

Josh verbatim** — §10's only Josh-attributed block is L976-981 and says nothing about a column, a

mint or a trigger (authorship verified in §0). So this is a director call in both directions, and

neither option below needs Josh.

The fact both sides argue from, recomputed from the CSV. BE_0002 authors **zero parry_only rows

and zero neutralize rows** — by canon, not by choice (the Ch-2 reduced scope,

T1_Combat_System_Spec L685; defender_element = none, dossier §4). The mitigation scale is the

outcome scale of a *parry or elemental answer* (DECISIONS L990-997). Minting the column against

this moveset therefore produces a column whose 19 cells are all blank. **The two options read that

same fact in opposite directions, and both readings are defensible:**

names — a column with no rows behind it is a promise, not a shape.

A blank cell on a column that is INAPPLICABLE to the row's counter_class is not an unfilled

promise — it is the semantically CORRECT value, exactly as a blank is correct rather than missing

for chapter_ids on the 20 region-ambient rows (§3.3) and for every rail FK spec'd min_tokens 0

(§4). A dodge_only row has no mitigation outcome to record; blank IS its answer. On that reading

the column is not empty-pending-authoring, it is fully authored at 19/19, and the queue's sentence

simply does not describe this case.

The internal contradiction, reconciled explicitly. This package cannot argue "a blank is correct,

not missing" for chapter_ids and min_tokens 0 in §3.3 and §4, and then treat 19 blanks as

self-evidently disqualifying here — that is the same fact scored two ways. The reconciliation is that

the two situations differ in ONE respect and the director should rule on that respect alone: for

chapter_ids, rows that DO populate the column exist in the same table, so the blank is legible by

contrast; for the mitigation column at this mint, no populated cell exists anywhere in the corpus, so

the blank has nothing to be read against. That is a real difference, and it is a difference of

LEGIBILITY, not of correctness — which is why this is a judgement call and not a derivation.

What is derivable today, and therefore not at risk either way. The column's SHAPE does not depend

on the mint: the ruling's own three landmarks (full negation exists; full negation is not guaranteed;

a much-stronger attack always leaves residual damage, DECISIONS L994-1001) yield the token ladder

full_negation · partial · residual regardless of when it lands. **The mint-now case's strongest

point is that this shape is available NOW**, and the 51 remaining slice rows will otherwise be

authored against the column's ABSENCE — after which every one of them is a migration rather than a

fill.

optionproscons
A. Status quo — the scale stays in prosezero changethe twenty-ninth sitting's ruling exists only as prose; the queue is unserved
B. Mint an ordinal token ladder NOW with this landinghonours the queue's letter; the shape is fully derivable today and lands BEFORE the 51 remaining slice rows author against its absence; on the inapplicable-blank reading the column is authored 19/19, not emptyall 19 cells blank — which, if blank is read as unfilled rather than inapplicable, is the queue's own stated objection, self-inflicted
B′. Mint the ladder with BE_0003's parry rail, alongside brief 1's defensive_classthe first moveset that can POPULATE it; honours the queue's reasonthe letter of "first authored moveset" is not followed, and the 51 intervening rows author against a column that is not there
C. Mint it as an int rank 1..Norders triviallyan int reads as a magnitude and invites tuning; L998-1001 rules the scale ordinal with no number ruled
D. Put it on T0_Element_Effectivenessthe grid already carries strengththe scale is attack-strength against answer-strength and the attack strength lives on the RAIL; a grid column expresses half of it

DIRECTOR ADJUDICATES — B AND B′ ARE BOTH LIVE. This lane declines to pre-decide it, because the

two options turn on a reading of one word ("blank") that this package uses in the opposite sense two

sections earlier. The shape is the deliverable and is identical under both: a token ladder over

the ruling's own three landmarks (full negation exists; full negation is not guaranteed; a

much-stronger attack always leaves residual damage), i.e. full_negation · partial · residual,

blank where the counter class admits no defence-with-an-outcome. This lane mints nothing either way.

§3.3 and §4 already apply to chapter_ids and to every min_tokens 0 rail FK. Cost: a column

whose first populated cell arrives with BE_0003. Benefit: the 51 remaining slice rows author WITH

the column instead of migrating onto it later.

can yet see exercised is not yet a shape. Cost: 51 rows author against the column's absence.

Benefit: the column's debut is also its proof.

The lane's lean, offered as a lean and not as a recommendation: B′, on the ground that the queue

sentence is prior loop discipline and the burden should sit on departing from it. **The strongest

objection to that lean, which the director should weigh first:** the queue names *"that rail's first

authored moveset"*, BE_0002 IS that moveset, and deferring reads the trigger's REASON over its LETTER

while the package simultaneously argues elsewhere that an inapplicable blank is correct rather than

missing — so B′ can only be right if blanks mean one thing on chapter_ids and another here. That

inconsistency is real, it is reconciled above only as a difference of legibility rather than of

correctness, and it is the reason this is presented as a fork rather than a recommendation.

5.4 S7 — the proposed closed telegraph_shape key rejects 13 of 19 rows

The finding, recomputed. MINT_DESIGN_B L1128 proposes promoting telegraph_shape from a free

string to a CLOSED ten-member key (whip_arc · low_sweep · high_feint · lunge · feint ·

grab · venom_spit · swipe · coil · disc). Against BE_0002's 19 rows: 6 rows inside the key

(lunge ×2, feint, swipe ×2, grab), 13 outside itsilent_close, break_cover,

throw_line, snare_lay, listening_hold, close_press, drop_fall, slope_release,

frenzy_commit, run_through_water, drain_state, unbraced_strike, arrest_stagger. The ten

members are inherited from two hand-coded movesets (a serpent and a caci champion) and cannot express

a human hunter's grammar. The promotion is not in fk_spec.json yet, so nothing breaks today.

optionproscons
A. Status quo — leave it a free string, promotion unlandednothing breaksthe promotion is on the board and will land; the problem is deferred, not answered
B. Widen the closed key with the 13 human-register shapes (→ 23 members)keeps closure, so the gate can check membership268 movesets ahead across aquatic, avian, constructed and materialized-argument registers — each will need another widening, and a key widened per-moveset is not closed in any useful sense
C. Land it OPEN and gate the READ instead — check tell_shape_class, not the animation keyno rejection; the thing gates actually partition (A3) is the class readfree strings drift into synonyms (lunge vs the_lunge) with no membership tooth
D. Two-level: closed telegraph_shape_family + open telegraph_shapeclosure where checkable, freedom where authoredtwo columns; telegraph_shape is the FHumanityAttackRow struct mirror and MINT_DESIGN_B L1122 warns a rename silently drops the column

RECOMMENDATION: C, with the S8 tooth attached. What must be closed is the player-facing READ

(tell_shape_class, which is what gate A3 partitions), not the animation content key. Content ids are

open everywhere else in this corpus; a ten-member list derived from two hand-coded bodies is a

rejection machine pointed at 268 movesets. If the director wants closure today, **B is the low-risk

fallback** and the 13 members above are the exact widening it needs.

Strongest objection. An open key is untestable, and the QA program's per-frame state record already

carries telegraph_shape (MINT_DESIGN_B L1152-1156), so QA loses the ability to assert a known shape.

Answered: QA asserts the CLASS read, which is the player-facing contract and the thing the fight

must teach; the animation key is a content id, and a QA assertion against a content id is a brittle

test of the artist's naming rather than of the fight.

5.5 S8 — tell_shape_class / tell_motion_class have no authored vocabulary

The finding. Both are specified as enums (MINT_DESIGN_B L1142-1143) with no vocabulary authored

anywhere in the corpus. Gate A3 partitions over a set that does not exist.

The measurement that decides it. BE_0002's 19 rows mint 16 shape families and 19 motion families.

14 of the 16 shape tokens are used exactly once, and 19 of 19 motion tokens are used exactly once.

A3's tooth is *"no tell_shape_class carries two counter classes"* — a COLLISION check. On a rail

where every token is a singleton, that check is trivially true and can never fire. The gate is

armed against a vocabulary that does not exist AND, as authored, against a distribution that cannot

violate it.

optionproscons
A. Status quo — enums with no memberszero changeA3 is armed and unsatisfiable-and-unviolatable at once
B. Ratify the exemplar's 16 + 19 as the corpus vocabularyit exists, it is derived move-by-move from the bestiary body-origin column, testable todaya one-body vocabulary (a human hunter) ratified corpus-wide; 268 movesets will break it immediately
C. Author a lane-owned vocabulary first (a design pass over the 57 kits), then re-derivedesigned rather than accretedblocks the 51-row volume pass behind a design pass the ledger has not scheduled
D. Declare both columns OPEN and let A3 check collisions over whatever is authoredmatches what A3 actually does; no false closuredrifts to 268 singleton tokens and the tooth degrades to trivially true — measurably, already

RECOMMENDATION: D as the schema, B as the SEED, plus the tooth D is missing. Declare both columns

open; publish the exemplar's 16 + 19 as the seed vocabulary authors must reuse-or-extend rather than

re-invent; and add to A3 a per-boss singleton-RATIO report — the share of a rail's tokens used

exactly once — because a per-token warning is noise at 19 rows and useless at 5,000. BE_0002's ratio

is 14/16 shape and 19/19 motion, which is the honest baseline the next rail is measured against.

Strongest objection. An open vocabulary with a warn-only ratio check will still drift, and a

report nobody fails is not a gate. Answered honestly: that is the real failure mode, and it is

why the recommendation specifies the ratio as the metric rather than leaving the check per-token — a

ratio can carry a threshold once two or three rails exist to calibrate it, and a per-token warn never

can. Setting that threshold from one rail would be inventing a number; it is named as owed at the

third authored moveset.

---

6. THE ID-MINT BRIEF — director-vetoable, per the A16 precedent

docs/PIPELINE_LEDGER.md L277-279 (VETOABLE 4) states the rule this brief follows: *"minting a

registry is a canon-adjacent act and is named here rather than done silently."* **This lane minted

nothing.**

MINT AGAINST HEAD STATE ONLY — the hard prerequisite, either way. Three of the fifteen source

pages are untracked and absent at HEAD (§0.0), and they account for 29 of the 113 rows. Because

mint_ordinal_proposed is one alphabetical sequence over all pages, minting against the wrong state

does not merely add or drop 29 ids — 79 of the 84 HEAD zones would take a different id. So:

113.** Re-run the emitter first and confirm the manifest reports zero untracked-or-dirty source

pages; the CSV in this package is then correct as it stands.

allocating only the new keys through the id-preservation pass below. Do NOT mint 113 against an

untracked working tree: the 29 rows would enter canon citing pages that do not exist at HEAD, and

a later --check against HEAD would report the whole table as drifted.

ambiguous about it: zone_registry_proposed.manifest.json carries the git SHA and the

untracked/dirty page list for the run that produced the CSV, so the minting agent verifies state

from the artifact rather than from this paragraph's timestamp.

Nothing else in the mint depends on which branch is taken — the schema, the FKs, the

arena_zone_ref design and all five S-findings are unchanged, and the 84-row table carries all 253

EG tokens and every populated join, because the three pages contribute none.

How many ids. 113 against the working tree today, 84 against HEAD (see above), one per

emitted row. The corpus will grow: T0_Region_Index carries 76 region rows and only 15 have a

Zone Catalog (12 at HEAD), so 61 regions are unwritten. At today's mean of 7.5 zones per page, the

finished corpus lands near 570 zones.

The id space. ZONE_\d{4}. Four digits matches every neighbouring space in this corpus

(EG_\d{4} at 225 rows, AT_\d{4}, BE_\d{4}) and leaves ~17× headroom over the 570 projection.

Three digits would fit the projection and leave none.

The allocation scheme.

optionproscons
A. Sequential in emitter order (page slug alphabetical, then page row order) — mint_ordinal_proposed as emittedthe only scheme the emitter can REGENERATE byte-identically, which is what makes drift detectable; matches every other flat id space in the corpusthe id carries no meaning; flores (CH_02) lands at 38-48 rather than at the front
B. Chapter-ordered (CH_02 first)reads in story orderthe 20 region-ambient rows have no chapter, and a page serving two chapters (flores CH_02+CH_03) has no single position
C. Region-blocked (100 ids per region)the id names its regionwastes the space and breaks the day a region exceeds its block; region_id already names the region as data

RECOMMENDATION: A. An id is a key, not a description, and the emitter's reproducibility is the

property that keeps this table honest.

What the mint costs, so it can be approved in full.

ruling above.

exist, emit_zone_registry.py must read the live registry's (region_id, zone_key) → zone_id

map and PRESERVE it, allocating only for new keys. Today it cannot, because there are no ids to

preserve. Without that pass the second emit renumbers the table and every arena_zone_ref on the

rail silently re-points. Named as a blocking prerequisite of the second emit, not of the first

— and no longer only named: the emitter now hard-fails with exit 4 the moment a

T0_Zone_Registry* directory exists under registries/, whether or not --preserve-ids is

passed, because the flag is declared but not implemented. The prose prerequisite and the machine

guard say the same thing, and the guard is the one that cannot be forgotten. Implementing

preservation is what lifts it.

What it unblocks. arena_zone_ref (§4) and with it A1's two permanently-warning classes; the A13

arena-mutation framework, whose ledger row says outright that it rides this join; the 52-row volume

pass's arena resolution step; and the care-boundary check on the 58 zones that contain a protected or

hard-blocked feature.

---

7. FINDINGS FOR THE DIRECTOR (flagged, not edited)

idfindingwhy it matters
F1The join covers 15 of 76 regions — and only 12 of them at HEAD. 15 region pages carry a Zone Catalog; T0_Region_Index has 76 region rows, so 61 regions have no zone data at all. Of the 15, three (arabia_persia.md, levant.md, mesopotamia.md) are UNTRACKED and absent at HEAD — another lane's unlanded work, contributing 29 of the 113 rows and zero join refs (§0.0, checked 2026-08-07T23:10Z at HEAD 924e0d09)the emitted registry is complete against what the pages say and incomplete against the world — and, today, complete against a WORKING TREE rather than against canon. Any gate reading it must treat an absent region as unwritten, never as empty; and the mint must resolve the HEAD question first (§6), because 79 of the 84 HEAD zones change ordinal depending on it
F235 of 113 zones carry no environment_grammar_refs, in THREE different ways — not 34 in two. (i) The column is ABSENT from the page for 29 zones: arabia_persia (11), levant (9) and mesopotamia (9) do not carry the extension pack at all, by their own declared design — and are also the three untracked pages of F1. (ii) It is PRESENT-BUT-EMPTY for 5: angkor_khmer carries the full 20-column pack with the refs cell blank. (iii) It is the literal token none for 1: flores_island.md L55 manggarai_village_edgecover and trigger_interrupt remain unanswerable in those zones after the join lands. The three causes need three different lanes, and only one of them is a defect: (i) is a page-design decision, (ii) is a populate-empty gap for the env-grammar lane, and (iii) is an AUTHORED assertion that the zone affords nothing — a none is answered, not missing, and a lane that "fixes" it would be overwriting canon. The emitter types all three in diag_eg_refs_state (absent/empty/none/populated) so no consumer has to re-derive the distinction from a blank
F3The reverse orphan set is three rows. 222 of 225 EG features are referenced by at least one zone. The unreferenced three: EG_0001 Lava Vent (HAZARD_VOLUME), EG_0002 Sieidi Stone (protected, NONE), and EG_0225 The Broker's Hauling Yard on the Open Valley Ground (COVER)EG_0225 is a live COVER answer that no arena can reach — a cover row authored against it would resolve to nothing. Finding for the env-grammar / region-page lane
F4AT_0011 outlives its arena under the FIRST-LIVE phase reading (§5.2). A cover row whose answer and whose ingredient both exist only in the phase-1 zone stays live in phase 2the arena join and the phase semantics must be adjudicated together or the column lands red on the exemplar it was built for
F5The S6 mint trigger names a moveset that cannot populate the column (§5.3) — 19 blank cells by canon. The queue paragraph is loop/director landing prose, NOT Josh verbatim (verified in §0)DIRECTOR ADJUDICATES; both options live. Deferring reads the trigger's reason over its letter, but minting now is equally defensible because a blank on an inapplicable row is the same correct-blank this package argues for chapter_ids (§3.3) and every min_tokens 0 FK (§4). The lane declines to pre-decide it and states the contradiction rather than resolving it silently
F6Arena answerability, measured. Of 113 zones: 17 contain a COVER-class feature; 24 contain a feature with enemy_usable TRUE and non-none attack_verbs; 58 contain a protected_care_ref or hard_blocked featurea cover row authored in any of the other 96 zones is unanswerable — and, for the first time, checkable. The 58 is the care-boundary surface dossier gate 11 currently checks by reading
F7Citation drift in the exemplar dossier. §0 cites CH_02.md L142 / L147 for CH02_B07 / CH02_B08; the typed beat rows are at L141 / L146 (L142 / L147 are their objective lines)minor, recorded so a later reader is not sent one line past the join. No content is wrong
F8harness/extract_zone_catalog.py already exists and projects ONE page to build/zones/<slug>.csv with a clean snake_case header. The new emitter imports its parser rather than duplicating it, and differs in scope (all pages, one registry-shaped table, keys and provenance, EG resolution, the registry write-guard)if the director prefers one tool, the merge is small — but the two have different outputs and different consumers today, and neither writes canon
F9The Zone Catalog preambles say "seven" T0.2 extension columns; the live pack is TEN. flores_island.md L43-44 (*"the T0.2 extension-column pack (the seven per-zone build columns…)"*, in a preamble whose own bracketed note at L46-47 says it was aligned to the live column set on 2026-07-27) and arabia_persia.md L85 (*"The seven declared T0.2 extension columns are deliberately absent"*). The live extension set is zone_bounds_wgs84 · meters_per_vertex · worldcover_biome · footfall_surface · care_tier · asset_routing · environment_grammar_refs · zone_space_class · ambient_population_band · footfall_surface_secondarya stale count in a living-source preamble is exactly the thing CLAUDE.md's living-source rule exists to prevent — the next agent reads "seven" and builds against the wrong pack. Region-page lane item; NOT edited here (the pages are canon and this lane may not change them)
F9bA second preamble-vs-rows staleness, in the same class and on the join column itself. swahili_coast.md L48-49 declares *"worldcover_biome, asset_routing and environment_grammar_refs are deliberately blank pending their own passes, exactly as on the pilot page"* — while that page's own rows carry environment_grammar_refs FULLY POPULATED (L53 kilwa_kisiwaniEG_0094;EG_0095;EG_0096;EG_0097;EG_0098;EG_0099;EG_0100;EG_0101, and every other row likewise). The refs pass evidently ran and the preamble was never updated; worldcover_biome and asset_routing ARE still blank, so only the third clause of the sentence is staleworse than F9's stale count, because this one is about the join column this whole package is built on: an agent reading the preamble concludes swahili_coast contributes nothing to the arena join and skips 5 populated zones. Same region-page lane, same living-source rule, same NOT-edited-here boundary. The emitted CSV is unaffected — the emitter reads rows, never preambles, which is itself the argument for projecting the pages rather than summarizing them

---

8. WHAT THIS LANE DID NOT DO

No canon was changed: not a region page, not the spine, not a registry row, not the CVD, not a

numerical, naming, hard-line or §17 cell. No id was minted — every emitted zone_id is the literal

ZONE_XXXX, and §6 routes the allocation to the director. No arena_zone_ref cell was written on the

19 BE_0002 rows; the migration is specified and left unapplied. harness/run_gates.py was not run and

docs/DOC_MAP.md was not edited, per the wave override. No question is put to Josh: every one of the

five findings is a schema reading, presented with its status quo, its alternatives and the strongest

objection, for a director to adjudicate — four carry a recommendation, and **S6 (§5.3) deliberately

carries a FORK instead**, because the lane found its own reasoning inconsistent across §3.3/§4 and

declined to resolve that silently in its own favour. No care column, flag or protection was

proposed — the 2026-08-04 care-does-not-ACCRETE law binds, and §4's care benefit is reaching cells

that already exist.

Three source pages were READ but not landed, and this lane did not land them.

arabia_persia.md, levant.md and mesopotamia.md are another lane's untracked work (§0.0); this

lane disclosed their state, measured their contribution, made the mint conditional on it (§6) and

made every future emit stamp it (the manifest) — but did not commit them, edit them, or treat their

absence from HEAD as this lane's to resolve. Two region-page defects were likewise flagged and left

unedited (F9, F9b), and one exemplar-dossier mis-citation was corrected in this document only

(§0, §5.2 — HL_0078 does not carry evolve-not-swap); the dossier and docs/spine/CH_02.md L97 still

carry the mis-attributed [SRC:] tag and are named for their owning lanes rather than edited here.

Generated by harness/site/structure_site.py — the URL path is the repo path. review root