pipelines/V3_CONVERSION_RUNBOOK.md
Status: ACTIVE (2026-07-14, Fable-5 v3 rewrite). The operational brief for converting one live spine entry
(docs/spine/CH_NN.md) from the v2.5 twenty-block form to the ratified SPINE_SCHEMA_v3.md v3.1
beat→fork→state event graph, in place. Proven on the CH_02 pilot (commit c6840cd, tag spine/v3-ch-02,
gates 14/14, fresh-context adversarial critic GO-WITH-FIXES → all findings applied). Read this WITH:
docs/SPINE_SCHEMA_v3.md (the ratified spec), the class-matching gold exemplar
(docs/spine/v3_exemplars/CH_12_v3.md early/assimilation · CH_39_v3.md modern · CH_76_v3.md
finale/path_dispatch), and docs/spine/CH_02.md (the live-file layout precedent — the exemplars are
delta docs; CH_02 shows the in-place form).
JOIN AND TYPE — never author new canon. Every typed row must trace to content already in the v2.5 entry
(or its cited registry/personas sources). Placement judgment calls (which beat carries a chapter-level
fact) are allowed; new canon claims are not. Anything the v2.5 entry asserts that the conversion re-types
differently (a classification, a zone, a vocabulary label) gets a Decisions-block entry recording the
resolution (the CH_02 bargain-refusal precedent). Load-bearing v2.5 content must survive SOMEWHERE
(a beat objective, a thin-index note, an env line, a kept block) — dropping canon is a MAJOR.
Continuity anchor, Body prose, Threads advancing, Civilizational marks, Everything-woven, Key ally
NPCs, Protected-chapter combat framing, Anti-fringe, Three-layer, Asset anchors, Decisions surfaced.
travel line; per-site env sub-line preserves the environmental_params + hosted-beat list).
beats; the narrative lives in the beat graph)"). Keep the Pillar-8 intro line. One row per boss:
BE_xxxx "name" · primary VERB · secondary VERB · axis n/n/n · phases [Pn→CHNN_Bnn, …] · win {ws_writes} · death {…}.
Sub-bosses one compact line each → their beat. Ambient threats (no registry row) noted as such.
A reveal-binding line where the chapter has one.
table + the intent-trio deferral note.
the v3 vocabulary (point to the fork graph + §18; CH_02 shows the wording) and reconcile any
zone/site line the beat graph resolves.
re-key its path_states line to the v3 vocabulary.
keys; the prose bridge stays in the transitions file)" — both seams (prev→this, this→next).
Beat (id convention CHNN_Bnn; prologue CHPRO_Bnn; epilogue CHEPI_Bnn):
Fork (### FORK_CHNN_A — name (anchor CHNN_Bnn), then):
option and direction columns (or path_bucket (LOCKED) forpath_dispatch). Bands NEVER appear as option labels — actions + direction only; bands are derived (§18).
Site row: - {site_id}: terrain {enum} · functions [{modes}] · ambient_threat {…} · vril_density {…} · climactic_affordance [{…}]|none · protected {true|false} · [SRC: …] + an indented - env: … line.
SQ row: - SQn · questline {slug} · stage {SEED|ADVANCE|GATE|COMPLETE} · gate {expr|none} · beats [CHNN_Bnn, …] · reward {…}.
Scene row (table): | scene_anchor_id | beat_ref | scene_type | path_bucket | anchor_type | participant_refs | hard_line_relevance | — SC_CHNN_slug ids; scene_type from the §5.5 eleven VERBATIM.
Seam row: - assert ws.key: value · … — plain dashes, both seams as separate H3-less lists under one H2
(intro sentence per seam, as in CH_02).
dialogue, stealth, vril_management, discovery, trade. ("exploration" is NOT a mode — map to
discovery/traversal.)
exploration_interaction, path_dispatch. direction: generative, neutral, corrosive.
TRULY_GOOD/GOOD_ENOUGH/EVIL (per-variant rows), ALL (post-lock path-invariant rows).
boss_encounter_phase_transition, boss_encounter_resolution, convergence_node, per_chapter_cutscene,
architect_appearance, ambient_cinematic, canonical_set_piece, prologue_cinematic, epilogue_cinematic,
branch_decision_point.
wilderness, cave_system, water_body. climactic_affordance: vista, threshold, sacred,
climactic_geometry, weather_dramatic (only where the v2.5 text supports it — no decoration).
in their registries); format-only: object: decode: inscription: familiar: journal: gate: verb:
agility_course: thread:. Do NOT use the reveal: prefix in systems (the checker's beat parser claims
any "reveal:" token as the reveal-state field and errors) — use inscription:/object: instead.
world_state_current, path_bucket, path_lock_in_state, appearance_score, age_stage,
relationship_history, journal_status, journal_entries_unlocked, journal_voice_texture,
familiar_bond_state, cassius_velheim_state, maatherion_negotiation_outcome, atlantis_passage_decision,
vimana_5th_mode_access, father_encounter_variant, six_option_cumulative_record,
community_state_per_region, antagonist_operational_state_per_region, faction_standing_per_faction,
convergence_node_state, vril_polarity_signature, atmospheric_vril_density_modifier,
identity_hiding_status, reputation_biography_propagation, companion_roster_state,
companion_loyalty_transition_events, trade_sovereignty_valence, hearthway_network_state,
dwelling_home_ledger, reputation_tier_per_faction, prestige_tier, nemesis_memory_per_boss,
spellcraft_authored_spells, worn_rune_loadout, husbandry_menagerie_state, husbandry_extinction_flag,
hollow_containment_fork_last. Anything chapter-scoped is local.* (produce-before-consume enforced).
SQ3 archaeology_inscription_occult · SQ4 mystery_detective · SQ5 astrology_psychology ·
SQ6 pirate_naval · SQ7 sorcery_music_theory · SQ8 trickery_gambling · SQ9 cryptids ·
SQ10 anomalous_phenomena · SQ11 lost_civilizations · SQ12 secret_societies.
1. python harness/enrich.py chapter CH_NN --json — the grounded pack (registry rows, hard lines,
threads, personas pointer). Boss ids: grep the pack or
registries/T0_Boss_Encounter_Registry [DRAFT v0.1]/Sheet1.csv for chapter_id CH_NN.
2. The live docs/spine/CH_NN.md — the SOURCE OF TRUTH being typed. Also read the prev/next chapters'
End-state + header blocks (the seam material) and the relevant docs/spine/transitions/ section.
3. grep -n "CH_NN\|Ch NN\b\|Ch-NN\b" docs/proposals/WHOLE_ARC_CONNECTIVE_WEB_INVENTORY.md — the
connective-web links touching this chapter; any link the v2.5 entry carries MUST become an explicit
fork option / mark_write / ws write / seam item.
4. python harness/rag/query.py "<question>" --top-k 8 for any governing-rule doubt (rulings,
precedents); the deterministic pack wins on FK facts.
5. BOSS_PERSONAS: grep ## boss Ch NN in docs/proposals/BOSS_PERSONAS.md directly (enrich misses the
Ch 59-65 counter-campaign cast — known gap).
python harness/check_spine_graph.py --registries registries --out <YOUR-SCRATCH-DIR>/sg_CH_NN docs/spine/CH_NN.md
ALWAYS pass --out to your own scratch path (the default writes harness/spine_graph_scorecard — parallel
agents must not race it). Zero errors required; the only acceptable WARNs are the cross-file classes
(mark forward_track / FOUNDATIONAL catalogue / seam equality). Also run
python harness/lint_canon_format.py docs/spine/CH_NN.md (no --out) — zero FAILs required.
1. mark_write is keyed by COMMUNITY id, not object id: {manggarai: valence via <object>, persistence,
forward_track [CH_NN…]}. forward_track lists ONLY chapters that actually READ the mark (the gate
upgrades this to ERROR at full corpus) — influence-into-a-later-read is carried by the
relationship/opportunity columns, not forward_track.
2. Site functions must cover the modes of every beat hosted at that site; derive site_ids
(lowercase_snake) from the v2.5 key-site names; enum-forced attribute changes keep their lost texture
in the env line ("low-rising" → low + env note).
3. Threads: join a thread to a beat ONLY where that beat's content actually advances it. An
event-claiming thread (the Thread_Grid cell names an in-chapter event) needs a carrier beat;
chapter-ambient threads stay in the preserved Threads block with an explicit thread-join note under
the mode-variety fold. NEVER guess thread numbers — verify each THREAD_NN against the chapter's own
Threads block + T0_Thread_Grid (wrong numbers are the recurring gate-invisible MAJOR).
4. Registry-drift protocol: the FK join WILL surface spine-vs-registry contradictions (verbs, axis
splits, names). Adjudicate against BOSS_PERSONAS + both spine versions. Spine+personas agree →
QUEUE the correction: record it in the Decisions block ("queued for the orchestrator's serialized
landing") and REPORT it in your return payload with cell = "<row_id>.<column>" + old/new/grounding.
Do NOT write any registry CSV yourself — parallel whole-file read-modify-writes clobber each other
(a proven batch-3 race); the ORCHESTRATOR applies all corrections serially at landing and refreshes
docs/fidelity_baseline.json in the same commit. Genuinely ambiguous → in-file note, report, do not
propagate either value into new text.
5. Prose hygiene in NEW text: [SRC:] anchors use the doc BASE name only — never a path, never a .md
suffix, section via " # " (e.g. [SRC: WHOLE_ARC_CONNECTIVE_WEB_INVENTORY # ECV-11]; a path form
fails the anchors gate as "doc base 'docs' not found"); never write the literal "[SRC:]" outside a real anchor;
no asterisk in any heading (ws state keys, not ws.*, in headers); no bare B-number tokens (B12) in
prose — always full CHNN_Bnn; no middots inside reveal(...) parentheticals; no commas inside {}
values in in:/out: maps; nested bullets ONLY the five sub-fields (objective/actors/in/layers/env).
6. Reveal ladder on NEW text (objectives/reveal lines are new prose — the who-frame discipline applies):
pre-Ch-38 no House-of-Velheim name/family/pattern and NO agent-noun who-frame constructions (not even
invoked-and-negated); Cassius named at Ch 76 B01 only (the beat's reveal must literally carry
"Cassius NAMED"); thesis/Grand-Sage only Ch 77; Corr unattributed before Ch 63 (grep \bCorr\b = 0
pre-63); no tier-6 substrate reads before Ch 15 (HL_0028 — Neophyte vril-trace register); D-14
ceiling: Ch 28-37 may carry "an organized power exists (unnamed)" but the five pattern-components
stay dark until Ch 38.
7. Care: care_band per the chapter's tier (standard → open); protected communities never combat-routed —
carry the apparatus-only routing inside the combat beats' reveal(care: …) and the fork care_note;
protected sites flagged true. Never sanitize: monsters/oppressor-apparatus stay fought.
8. Ability/chapter-level fact placement: attach to the most-fitting beat (fire ability → the fire
puzzle beat); placement must not ASSERT new canon. Win/loss reward specifics may live in the registry
row the thin index FK-binds — verify the row carries them before dropping from the file.
9. Endgame (Ch 66+, esp. 74-77): the SPINE is the authoritative endgame topology (Ch 74 Yggdrasil ·
Ch 76 Two Courts · Ch 77 Grand Sage/Waterfall). T0_Quest_Definition_Registry, T0_Scene_Spec_Registry,
and the RCM endgame structural block still carry the OLD topology — do NOT propagate them.
10. Vocabulary re-key (schema §1): wherever the v2.5 entry uses truly_good/good_enough/neutral/evil as
path/ending/option labels, re-key — options action-keyed + direction; bands only in §18 derived
axes; "Neutral" only as the WS3 world-state name; "Truly Good path" as an ending-path name is fine.
integrity deltas write ws.integrity_score (not ws.integrity_level — the level is derived).
11. §18 must contain the literal tokens integrity_level, path_bucket, reveal_state (the checker warns
otherwise) plus identity_hiding_status and age_stage where the chapter tracks them.
12. ENTRY SEAM FIRST (a batch-2 MAJOR): before writing any beat, pin your entry state = the previous
chapter's exit seam VERBATIM — especially age_stage at a D-06 boundary (the stage crosses AT the
chapter boundary, never inside a beat; a mid-chapter ws.age_stage write is wrong unless the v2.5
entry itself stages a crossing there). age_stage values are Title-case (Childhood/Adolescence).
13. Fork-option delta symmetry (a batch-2 MAJOR): EVERY option row carries its class-bounded
ws.integrity_score delta — corrosive rows mirror the generative side; a missing delta on one arm
silently unbalances the whole fork.
14. Beat thread STAGES come verbatim from the chapter's own Threads block / Thread_Grid row (a
batch-2 MAJOR): never escalate a stage (ANCHOR → ESCALATION/CONFRONTATION) by feel — the number
AND the stage are both canon.
15. Multi-phase-over-fewer-beats bosses: a beat's boss ref cites the FIRST phase it hosts; the §9
thin-index phase→beat map is the authoritative assignment (BE_xxxx.P1/P3 on the beats, all four
phases in the index).
16. care_band mapping: standard tier → open; elevated faith/culture tier → elevated; protected-people
chapter (its own protected-combat-framing block) → protected-elevated; maximum-care → maximum;
the D-08 chapter class → antisemitism-guardrail.
17. Enum/key hygiene: vril_density ∈ {baseline, low, moderate, high, anchor} (never mid/null); seam
integrity asserts use ws.integrity_score (integrity_level is DERIVED — never a seam key);
ws.identity_hiding_status values are the bare WS_025 enum (pressure rides a note, never a
compound token).
ws.journal_status values are the bare WS_009 enum, written only at the five WRITE-anchors of §8.4
(Ch 13 ACTIVE_HEALERS_CHILD, Ch 38 TRANSFERRED_TO_PROTAGONIST, Ch 56 DECISION_TO_PUBLISH, Ch 57 the
public-release register, Ch 58 SHARED_POST_CH58); the Ch-57 register's own value-set is under
adjudication (O-5) and is NOT settled — do not type it from this line. §8.4's remaining two bullets
(Ch 59-65 continental revisits, Ch 77 Epilogue) are state-machine READ nodes, matching WS_009's own
Ch59_65_continental_revisit_dispatcher and Ch77_epilogue_renderer consumers — a read node still carries
journal content (e.g. CH_62:108), which rides ws.journal_entries_unlocked (WS_010) or a beat note, never
a +token on the enum. There is no journal_status WRITE before Ch 13; CH_03:161's precursor token is
pre-journal texture, not a NOT_BEGUN write.
18. SQ gates use the §5.3 expression grammar with keys a prior beat's out actually produces —
has(local.k) / at(site_id with the site row's exact id) / flag() / ws.key ops — never prose
inside braces.
19. ws.six_option_cumulative_record (WS_018) is RESERVED for dialogue_six_option forks (the
canonical six enum selections). Never write it from combat_resolution / exploration /
assimilation forks — carry corrosive-pattern texture via ws.integrity_score +
ws.reputation_biography_propagation instead (this defect recurred three times: CH_05, CH_32).
{"chapter": "CH_NN", "checker": "PASS|FAIL", "lint": "PASS|FAIL", "beats": n, "forks": n,
"registry_corrections": [{"registry": "...", "cell": "...", "old": "...", "new": "...", "grounding": "..."}],
"decisions_recorded": ["one line each"], "notes": ["anything the verify pass must know"],
"connective_links_carried": ["IR/LINK ids typed into forks/marks/seams"]}
1. gates_config.json: append the converted files to spine_graph targets.
2. If any agent reported registry corrections: refresh docs/fidelity_baseline.json
(registry_fidelity.py … --emit-baseline docs/fidelity_baseline.json) in the SAME commit.
3. python harness/rag/index.py --scope canon (LAST content step), then python harness/run_gates.py
UNPIPED — 14/14 exit 0.
4. Fresh-context adversarial verify workflow over the batch (fidelity/reveal/care/machine-semantics
lenses per chapter + a cross-chapter seam sweep), fix-forward, re-gate.
5. Commit + tag spine/v3-bN; update the ledger docs at milestones.
20. ws-key ENUM-DOMAIN discipline (a batch-6 MAJOR — the number-coincidence trap): a ws.* key is
bound to its registry-defined DOMAIN, not its name's surface reading. ws.vimana_5th_mode_access
is the ENDGAME fifth-operational-MODE enum (UNAVAILABLE/FULL_ACCESS_TGP/PARTIAL_GE/
FRAGMENT_RESIDUE_EVIL, consumed by the Ch66-77 resolver) — NOT the modern-arc coordinate hunt
(Coordinate 5 of 6 is chapter-scoped local./prose tracking). Before writing any ws key, read its
WS_NNN row's domain/consumers; if the value you want is not in the enum's world, the key is wrong.