pipelines/STORYDEPTH_ARC_ARCHITECTURE_2026-07-27.md
Read-only design-research analysis. Axis: what ARCS exist in the corpus, what tracks each,
where the DATA HOME and the DEPTH PASS are missing, and the machine-checkable form of
"every relationship holds depth and flows end to end."
Analyst note on evidence tiers used below:
sibling token), per the standing a-search-that-cannot-match rule.
---
Everything in the factory is keyed on a NODE or a ROW. Nothing is keyed on an ARC.
arc_id appears 0 times across registries/, docs/, and harness/
(POSITIVE-CONTROLLED: the identical grep for thread_id returns hits in registries/).
There is exactly one arc-shaped data structure in the entire corpus — T0_Thread_Grid,
664 rows of (thread_id × chapter_id → progression_stage) — and **no gate, critic, skill, or
enrich pack ever reads it as a sequence.** It is written per-node and never graded end-to-end.
That is why Josh can author a Prologue/Ch-1 emotional spine as good as the amulet chain and
still be right to worry: the machine has no place to put "this arc" and no pass that walks it.
---
Five wiring vectors exist. All five are node-scoped or row-scoped.
| # | Vector | What it is | Scope | Arc-aware? |
|---|---|---|---|---|
| 1 | The spine node | 79 docs/spine/CH_*.md at schema v3.1 — the beat → fork → state graph (beat_id permanence, typed site rows, action-keyed fork tables, mark_write with forward_track, seam diffs) | ONE node | No |
| 2 | The registries | 56 registries/T0_* dirs; the cascade's step-9 scatter writes structured fields out of the node into rows | ONE row | Thread_Grid only |
| 3 | The gates | 29 in harness/gates_config.json | 27 node/row-local; 2 sequence-aware (below) | Barely |
| 4 | The skills | /spine-chapter (12-step cascade, Step-3a significance-lens pass) + normalize-doc (fresh-context critic rubric) | ONE node | No |
| 5 | The docs tier + DOC_MAP | proposals/design docs + the anti-orphan master index | Human/agent-read | N/A |
The two gates that already read a SEQUENCE — these are the proof the pattern works, and
they are the template to generalize:
harness/slice_coherence.py — reads region pages as a chapter-ordered sequence and emitstwo manifests: the CARRIED-FAMILIAR manifest (a familiar asserted PRESENT at page N+1 that
page N neither carries nor acquires is a finding) and the LINK-RECIPROCATION manifest. It even
gets the hard part right: out-of-slice acquisitions are recorded, not flagged. (CITED:
file docstring.) This is a working arc-continuity gate that happens to be scoped to region
pages instead of arcs.
harness/check_spine_graph.py §6 cross-file ERROR tier — mark_write.forward_track consumercontinuity (does the named later chapter actually READ the mark?), pre/post-Ch-65
path_bucket consistency, and seam cross-file equality. **Fires only on full-79-node
invocations.** (CITED: docs/SPINE_SCHEMA_v3.md §6.)
The gap this map exposes: forward_track is the corpus's ONE real end-to-end promise→payoff
tooth, and it is scoped to a single mechanic (the community mark). MEASURED: 338 mark_write/
forward_track lines across 51 of 80 spine files. The same tooth, generalized to every arc
class, is most of the answer.
Also relevant and often mis-stated: docs/WIRING_AUDIT.md still lists the 33 significance
lenses as [ORPHAN]. That is STALE. MEASURED: .claude/skills/spine-chapter/SKILL.md
carries 10 significance hits including a dedicated Step 3a — the significance-lens pass
(the 33 lenses in seven groups + the §4 control-for-relevance filter, with `[SRC:
SIGNIFICANCE_LENSES]` anchor guidance for blocks 6/7/8) and normalize-doc rubric lines 151-152.
So the lenses ARE wired — author-side, per node. What does NOT exist is any lens column in
any registry (significance_lens = 0 registry hits) and any application of a lens **to an
arc**. A region gets lensed; a relationship never does.
---
Twelve classes. For each: DATA HOME (is there a per-arc × per-node anchor grid?), DEPTH PASS
(who walks it end to end?), and the cost of the gap.
three-path integrity model; WS_004 path_bucket locking at Ch 65; seam diffs between nodes.
(docs/proposals/WHOLE_ARC_CONNECTIVE_WEB.md) + check_spine_graph's cross-file ERROR tier.
workflow whose output is proposal-tier**, and its own headline finding is that the endgame
renders path-flat: CH_75/76/77 "currently list the found-family present path-flat (the
largest relationship gap)" and CH_75's coalition is "currently path-flat" (CITED:
WHOLE_ARC_CONNECTIVE_WEB_INVENTORY.md ECV-01/ECV-05/ECV-07). A per-node gate cannot see
path-flatness; only an arc pass can.
documented, ranked, and unbuilt, with no standing consumer to re-check it.
T0_Thread_Grid 664 rows, schema`thread_id | chapter_id | progression_stage | content_summary |
authoritative_paragraph_anchor | extensions`. This is the model to generalize.
| Finding | Value |
|---|---|
| Stage distribution | ANCHOR 441 · ESCALATION 106 · NOT_PRESENT 49 · CONFRONTATION 45 · RESOLUTION_FINAL 15 · RESOLUTION_PARTIAL 4 · CONVERGENCE 2 · CONFRONTATION_DIRECT 1 · CAPSTONE 1 |
| Threads with no resolution/capstone stage anywhere | 15 of 22 (T07-T19, T21, T22) |
| Threads that are MONOTONE (only ANCHOR/NOT_PRESENT, zero escalation) | 1 — THREAD_19 End-of-World/Eschaton, 10 appearances, all flat |
| Last appearance of every minor thread except T20 | between Ch 46 and Ch 69 — none reaches Ch 77 |
T0_Thread_Registry.resolution_chapter populated | 0 of 22 (also anchor_count, first/final_anchor_chapter, weaving_count all empty) |
66% of every cell in the one arc-tracking structure carries a single value (ANCHOR). The six
MAJOR threads run Prologue→Ch 77 and land RESOLUTION_FINAL; **all sixteen minor threads stop
mid-arc and end on ANCHOR / ESCALATION / NOT_PRESENT.**
*Honest caveat (INFERRED):* ANCHOR may be being used as "present/tracked" rather than "the
arc's anchor beat," in which case the defect is that the grid's vocabulary has collapsed and
no tooth forces the distinction. Either reading gives the same conclusion: **the corpus's one
arc tracker cannot currently distinguish a thread that is building from a thread that is
merely being mentioned.** A prose read-verify per thread is the correct confirmation step and
is exactly what the arc pass in §5 performs.
from Thread_Grid's 664 rows", zero-token) is filed as bookkeeping. It is not. Running it
*is* the shape diagnostic — it surfaces the 15-thread no-resolution finding automatically.
T0_Questline_Index 23 rows (SQ1-12 + TRADE_01-10 + LEG_WPN_036) with chapter_span as a prose string, not a grid. The real per-node data lives in spine Block 11
as `- SQ4 · questline mystery_detective · stage ADVANCE · gate has(local.trace_started) ·
beats [...] · reward ...`. It is never scattered into an arc grid.
SEED 23 / ADVANCE 336 / COMPLETE 11, so a GATE hit would have been found):**
| Questline | nodes | SEED | ADVANCE | GATE | COMPLETE |
|---|---|---|---|---|---|
| archaeology_inscription_occult | 59 | 2 | 56 | 0 | 1 |
| lost_civilizations | 47 | 3 | 44 | 0 | 0 |
| mystery_detective | 47 | 2 | 42 | 0 | 3 |
| secret_societies | 46 | 2 | 43 | 0 | 1 |
| astrology_psychology | 40 | 3 | 36 | 0 | 1 |
| fairy_tale_folklore | 39 | 5 | 32 | 0 | 2 |
| anomalous_phenomena | 25 | 3 | 20 | 0 | 2 |
| military_history | 21 | 1 | 20 | 0 | 0 |
| sorcery_music_theory | 21 | 1 | 19 | 0 | 1 |
| cryptids | 17 | 1 | 16 | 0 | 0 |
| pirate_naval | 6 | 0 | 6 | 0 | 0 |
| trickery_gambling | 2 | 0 | 2 | 0 | 0 |
GATE is authored ZERO times corpus-wide. The sq_stage enum is {SEED, ADVANCE, GATE, COMPLETE} and the schema says "twelve_tier_gate where it binds"
(CITED: SPINE_SCHEMA_v3 §3d/§4). No side questline has a single machine-visible gating
milestone. The enum value exists and has never been used.
trickery_gambling has 2 beats across 79 nodes against archaeology's 59.
and none has a mastery gate. This is the single most legible "does not flow end to end"
defect in the corpus, and it is invisible to all 29 gates because every one of them is
node-local.
T0_Trade_Registry (10 rows) packs the wholeladder into ONE string column: `twelve_tier_quest_gates =
"gate_1_neophyte:Q_TR1_NEO; gate_2_zelator:Q_TR1_ZEL; …"`. MEASURED/POSITIVE-CONTROLLED:
Q_TR appears 0 times in T0_Quest_Definition_Registry (16 rows; the same file matches
quest_id). Neither registry is enrolled in fk_spec (CITED: register #38).
corpus — dangling as substrings. Window-plan rank 23.
T0_Questline_Index.questline_class ∈ {side, trade, legendary} — zerocompanion rows, no companion class. `T0_Quest_Definition_Registry.quest_type ∈
{canonical_hard_line ×12, epilogue_resolution ×3, prologue_baseline ×1}` — no companion type.
22 buckets is LOCKED numerical canon, so a 23rd bucket is not the answer (CITED:
docs/pipeline_review/LENS_BG3_2026-07-27.md BG3-3, with its own positive control).
docs/spine/companion_cast_designs/(PARTY_STRUCTURE, COMPANION_MECHANICS_CONTRACT, CAST_INVENTORY, per-companion files) — all
Status: RECOMMENDATION for Josh, none machine-consumed.
CAST_INVENTORY.md FILTER-3 = ids appearing as actors: in 2+distinct chapters): the entire recurring on-screen cast is seven ids** — Ntala CHAR_0002
(191 actor-beats / 55 nodes), Ana CHAR_0017 (44 / 22), the Elven King CHAR_0005 (5 nodes),
Kxao CHAR_0071 (3), plus three more.
T0_Character_Index (163 rows): loyalty_model filled on 6; loyalty_belief_axis filled on 4. chapters_present is filled 163/163 but is a **prose
string**, not a stage grid.
companion reacting to the player's choices* — the departure system's own surface. A loyalty
arc is the inverse: the player serving the companion's goal. PARTY_STRUCTURE §3 Tier-1
names it as a requirement; nothing contains it. Zero exemplars on the human axis (the only
paid loyalty arc, CL-01, is the childhood familiar — a firewalled different axis).
whole game is built around is tracked as attendance.
T0_Familiar_Registry 22 rows carry chapter_first_encounter, chapter_bonding_window, bonding_quest_id,
bond_formation_beat_ref, loyalty_condition. That is an acquisition record, not an arc:
it names where the bond FORMS and nothing about where it deepens, is tested, or pays.
slice_coherence.py's carried-familiar manifest isreal continuity checking — but it runs over region pages (4 cut so far), not the 79 nodes.
Ch 58 reunion (Truly-Good only) → Ch 65 three-way 22nd-slot lock → Ch 75 timed-assist window
(CITED: connective-web Lens C / ECV-02). It has promise, escalation, a band-gated payoff, and
a terminal consequence. It is the exemplar the arc registry should be shaped to hold — and
it lives in a proposal doc, not a registry.
T0_Antagonist_Network_Registry is 64 rows keyed (operative_id, chapter_id) — MEASURED: 62 distinct chapters covered. Structurally
this is already a grid. Plus WS_020 antagonist_operational_state_per_region and
WS_013 cassius_velheim_state.
progression_stage column — the rows say *who is present where*, not*where the pattern escalates*. Reveal discipline is enforced separately and well
(check_reveal_discipline + check_grand_sage_silence, gate #25 PASSing).
not a new home.
WS_019 community_state_per_region ("cross-chapter accumulation … RATIFIED"), T0_Region_Index (76 rows / 79 nodes), and the strongest existing
tooth: mark_write {community_id, valence, persistence, forward_track:[CH_NN]} with
check_spine_graph verifying every forward_track target actually reads the mark (ERROR
tier, cross-file). MEASURED: 338 mark/forward_track lines across 51 nodes.
shape*.
at doctrine level (§4.9 / §8.3 / §5.5.4) but the two flagship revisits — Ch 40 "the same Ch 11
forest" and Ch 42 "the Ch-12 serpent corridor" — **read identically regardless of how the
player treated those communities centuries earlier.** Also IR-6: the Ch-2 Kelimutu carved mark
is authored as "the Ch-39 revisit anchor" and Ch 39 is West Africa — a **dangling
forward_track**.
world) is data-present and texture-absent at the two chapters that were built to carry it.
marriage|betroth|spouse across registries/ returns exactly one hit, and it is a book title in T0_Source_Material_Registry. The
recovered Marriage & Partnership system's named home (T1_Personal_Dimension_Spec) is a
byte-level empty stub (CITED: register #22/#23/#43; window-plan rank 24).
are WS_009/010/011 (journal status / entries / voice texture), WS_007 age_stage,
WS_025 identity_hiding_status, WS_018 six_option_cumulative_record, and spine Block 4
(body prose, "close-third personal-arc lens"). Block 4 is **prose, deliberately not the event
spec** (CITED: SPINE_SCHEMA_v3 §2/§6 — the schema explicitly says Block 4 "was never the event
spec").
with anchors, escalations, and a payoff.
amulet, her death during the rift-spawn while the King served the realm, the run-back, the
King's never-resentment, the townspeople's grudge, the friend's constancy, the dumb fight, the
fall (CITED: PRE_5090 progress ledger 2026-07-27i). The integration of that is an 18-file
spine plan in AMULET_PROVENANCE_BRIEF.md — i.e. it will be applied node by node, and
after it lands **nothing in the machine will hold "the grief arc" as a thing that can be
graded, re-checked, or deepened.** The next enrichment wave will not know it exists except as
prose scattered across 18 files.
arc with no container at all.
WHOLE_ARC_CONNECTIVE_WEB.md §1 (proposal-tier).
WS_009-011, anchors Ch 13→38→56→57→58→77) and is exactlythe shape an arc row should hold. ECV-06 wants it mechanized as an accumulated record
(the number of Cassius's arguments you can rebut = the atrocities you documented) — currently
scripted, not accumulated.
(SYS-3/TL-14 → Ch 55 Vimana): the capstone "debuts cold" because the feeder rungs were never
authored as a ladder.
across 6 connection types (5 recurring-beast spines, 6 deity-patron chains, 9 era-rhymes,
11 L3-literal chains, 27 callback pairs, 7 system spines) and **9 true orphan / unpaid /
seed-debt callbacks**.
next cascade wave cannot see them.
| Arc class | Instances | Data home | Depth pass | Grade |
|---|---|---|---|---|
| Main story | 1 | STRONG (v3.1 graph) | PARTIAL (RRs, one-time web pass) | B |
| Threads | 22 | EXISTS (Thread_Grid) | NONE | C |
| Side questlines | 12 | PARTIAL (prose span + node rows) | NONE | D |
| Trade questlines | 10 (120 gates) | NONE (packed string) | NONE | F |
| Companion personal arcs | ~7 recurring | NONE | NONE | F |
| Familiar bonds | 22 | PARTIAL (acquisition only) | ACCIDENTAL (slice_coherence, region pages) | D |
| Antagonist web | 64 operatives | GOOD (chapter-keyed grid) | PARTIAL (reveal gates) | B− |
| Region / community | 76 regions | GOOD (mark_write.forward_track + WS_019) | PARTIAL (link-exists tooth) | B− |
| Romance / partnership | 0 | NONE (spec is an empty stub) | NONE | F |
| Protagonist interior | 1 (+sub-arcs) | NONE | NONE | F |
| Object / system spines | ~7 | NONE (proposal only) | NONE | F |
| Beast / deity / rhyme chains | 65 | NONE (proposal only) | NONE | F |
Total arc population if registered: ~290. Tractable — smaller than Thread_Grid's 664 rows.
---
Design principle, per the brief: honor the proven pattern; extend, never duplicate.
T0_Thread_Grid already works structurally. The arc registry is that same shape with the
thread-specific assumptions lifted out — and Thread_Grid becomes a view of it (or is
migrated wholesale; see §3.4). No arc class gets a bespoke tracker.
T0_Arc_Index — one row per arc (the "what is promised" layer)| Column | Type | Notes |
|---|---|---|
arc_id | ARC_NNNN | permanent, never renumbered (the beat_id permanence rule) |
arc_class | closed enum | main · thread · side_questline · trade_questline · companion · familiar_bond · antagonist · community · partnership · interior · object_spine · chain |
arc_name | text | player-facing where one exists, else the corpus slug |
participants | FK array | CHAR_/FAM_/community_id/faction/NW_/region_id/BE_ — FK-checked like systems: prefixes |
owning_doc | anchor | the T1/T3 doc with authority (the authoritative_paragraph_anchor convention) |
first_anchor_node · last_anchor_node · resolution_node | node ids | DERIVED from the grid, never hand-typed (the rank-28 lesson) |
promised_beats | text array | what the arc's setup PROMISES (the machine form of "the amulet chain") |
payoff_nodes | node array | where each promise lands; every entry must be grid-present |
layer_span | L1/L1.5/L2/L3 set | an all-L2 relationship arc is a codex entry, not a relationship |
lens_set | lens ids | which of the 33 significance lenses / craft lenses the arc registers on |
care_band · reveal_window | enums | inherited from the existing vocabularies, arc-scoped |
variance_axis | enum set | which of {integrity, relationship, faction, mark, path_bucket, none} alters this arc's later texture — none is the path-flat detector |
open_by_design | bool + reason | the honest escape hatch: an arc with no resolution must SAY so and why |
depth_grade | A-F, DERIVED | computed by the gate from §4's rules; never authored |
T0_Arc_Grid — one row per (arc × node) (the "where it lives" layer)Identical in spirit to Thread_Grid's six columns, plus the v3.1 join:
| Column | Notes |
|---|---|
arc_id | FK → Arc_Index |
node_id | CH_NN / CH_PROLOGUE / CH_EPILOGUE |
progression_stage | ONE unified closed enum across all classes (§3.3) |
beat_refs | [CH40_B04, …] — the join Thread_Grid lacks. Ties the arc to the v3.1 beat graph, so an arc stage is addressable at beat granularity and inherits the beat's in:/out:, reveal, layers, and [SRC:] |
content_summary | as today |
authoritative_paragraph_anchor | as today |
state_reads / state_writes | ws.* / local.* keys — makes promise→payoff machine-visible the way forward_track already is |
extensions | as today |
progression_stage enum (reconciling three existing vocabularies)Today: threads use ANCHOR/ESCALATION/CONFRONTATION/CONVERGENCE/RESOLUTION_*/CAPSTONE/NOT_PRESENT;
side questlines use SEED/ADVANCE/GATE/COMPLETE; familiars use an implicit
first_encounter/bonding_window. Three vocabularies for one concept is why nothing composes.
Proposed single enum (a superset that maps both existing ones losslessly):
SEED (the promise is planted) · PRESENT (tracked, no movement — the honest home for the 441
degenerate ANCHORs) · ESCALATE · TEST (the gate/confrontation — absorbs both GATE and
CONFRONTATION) · TURN (the reversal/cost beat — **new, and the arc-scale hook for the rank-9
narrative-craft gate**) · PAYOFF · RESOLVE · DORMANT (explicitly asleep, with a wake node) ·
NOT_PRESENT.
Mapping: ANCHOR→SEED|PRESENT (the disambiguation the corpus currently cannot make and which
the arc pass performs once per thread), ADVANCE→ESCALATE, GATE|CONFRONTATION*→TEST,
COMPLETE|RESOLUTION_*|CAPSTONE→RESOLVE, CONVERGENCE→PAYOFF.
1. Thread_Grid is the seed data. Its 664 rows import as 22 arc_class=thread arcs. Keep
T0_Thread_Grid as a generated VIEW for one release so every existing consumer
(enrich.py:thread_rows, check_spine_graph's THREAD_NN roster check) keeps working, then
retire it. Never two writable homes for one fact (the living-source rule).
2. Antagonist_Network_Registry needs one added column (progression_stage) and an
arc_id; its 64 (operative, chapter) rows import directly.
3. Familiar_Registry / Character_Index / Questline_Index / Trade_Registry keep their entity
rows and gain an arc_id FK. The arc grid holds the per-node stages; the entity registries
stay the identity layer. No entity data moves.
4. Companion arcs take the ruled reuse-first route (CITED, BG3-3 recommendation): a
companion_arc value on T0_Quest_Definition_Registry.quest_type + a companion_ref FK to
T0_Character_Index, riding the existing DT_Beat/DT_Fork spine, gated on the BOND band,
writing the same WS_027/WS_028 the departure system reads. No 23rd bucket — the
locked 22 is untouched because an arc is not a questline bucket.
5. docs/fidelity_baseline.json refresh via --emit-baseline in the same commit (standing rule).
6. DOC_MAP row + gates_config.json entry at creation, or it is an orphan by definition.
---
The per-node critic checks the node. Nothing checks the arc. The answer is two things: a
deterministic gate that grades SHAPE, and a fresh-context critic fan-out that grades DEPTH.
Neither replaces the other — the gate is cheap and always-on; the critic is the judgement.
harness/check_arc_continuity.py — the deterministic shape gateBuilt on the established scaffold pattern (PASS-on-empty, LOUDLY DECLARED NOT-ARMED for every
unarmed assertion in its own scorecard every run, must-fire/must-not-fire fixtures via
--self-test exiting 2 if a ruler rotted) — the exact discipline gates 26-29 already use.
Corpus-wide, so like check_spine_graph's cross-file tier it fires on full invocations.
Eight teeth, each of which catches a defect measured above:
| Tooth | Rule | Catches today |
|---|---|---|
| T-1 SHAPE | every arc has SEED → ≥1 ESCALATE/TEST → RESOLVE, or open_by_design=true with a reason | 15/22 threads · 5/12 side questlines · 2 no-seed questlines |
| T-2 GATE-PRESENCE | any arc whose class declares gates (trade_questline, side_questline with a twelve_tier_gate) has ≥1 TEST stage | GATE = 0 corpus-wide |
| T-3 DORMANCY | node-gap between consecutive stages ≤ the class's cap, or the row is explicitly DORMANT with a wake node | seed-debt (TL-13 contest ladder, SYS-3 vehicle line); minor threads dying at Ch 46-69 |
| T-4 PROMISE→PAYOFF CLOSURE | every promised_beats entry has a payoff_node that machine-READS it — the generalization of the proven forward_track tooth to every arc class | the dangling Ch-2 Kelimutu mark (IR-6); the 120 dangling Q_TR* gates |
| T-5 VARIANCE | variance_axis ≠ none for any arc of class companion/community/familiar/partnership: ≥1 fork whose options alter this arc's later texture | the path-flat CH_75/76/77 found-family; the integrity-invariant Ch 40 / Ch 42 revisits |
| T-6 MONOTONY | no arc may be >80% one stage value | Thread_Grid at 66% ANCHOR; SQ rows at 89% ADVANCE; THREAD_19 at 100% |
| T-7 NON-GATING | no arc stage is progression-critical — the check_no_dead_end §3.5 invariant lifted from nodes to arcs | (already clean; keeps it clean as arcs mint) |
| T-8 DENSITY FLOOR | an arc's node count ≥ the class floor, or it is declared a cameo | trickery_gambling at 2 nodes; pirate_naval at 6 |
Every tooth is computable from T0_Arc_Grid + T0_Arc_Index alone. No new authoring is needed
for the gate to be honest on day one — it will report DECLARED NOT-ARMED for classes with no rows
yet, which is itself the visible backlog.
The standing whole-arc directive ("you're missing a LOT") was executed once, as a workflow, and
its output is a proposal file. That is a heroic pass, not a factory. The factory form:
own grid slice, the anchor nodes named in it, the arc's owning_doc, and the runbook. Not
the full reference stack — the standing trim-shared-reading rule.
depth_grade, a ranked defect list against the §4.3 rubric, and **proposed beatswith node targets** (arc-scoped seeds, not prose).
every node), calibrated with a devil's-advocate pass against over-conservatism.
is unchanged.
arc_id, so after any node rebuild the affected arcs are a git diff-derivable worklist (script-emitted, never hand-typed).
This is the piece that answers "how do we GUARANTEE the amulet-class depth everywhere": the arc
pass is the amulet conversation, automated, once per arc, forever.
The gate proves an arc has a shape. This proves it has weight. Six criteria, drawn from what
the corpus already ruled rather than invented:
1. PROMISE — the arc's setup makes a specific promise a player can feel, not a topic.
2. TURN — there is a reversal, a cost, and a moral residue. This is **window-plan rank 9's
narrative-craft seed gate (reversal / cost / residue), lifted from the seed to the ARC** —
which is where it actually belongs, and it should be authored at both scopes at once.
3. VARIANCE — the arc reads differently depending on who the player has been (integrity /
relationship / faction / mark). The path-flat finding is a rubric-3 failure at scale.
4. RUNWAY — the capstone was pre-taught. Seed debt is a rubric-4 failure.
5. LAYER FIT — L1 playable, L1.5 ambient, L2 completionist, L3 connective; a relationship arc
that never touches L1 is not a relationship.
6. VOICE — arc-scoped natural-voice: the same person sounds like the same person across 55
nodes, culturally registered. Node-scoped voice checking structurally cannot verify this.
| Surface | Change | Why |
|---|---|---|
harness/enrich.py | add --arc ARC_NNNN mode; and in the CHAPTER pack, add an arc-context section: for every arc touching this node, its stage here, its previous stage + node, and its next promised payoff | Today thread_rows(cid) gives the author *this chapter's* thread cells and nothing else. The author literally cannot see arc shape. This is the single highest-leverage wiring change. |
.claude/skills/spine-chapter/SKILL.md | Step 3a gains an arc-continuity sub-step: the node declares which arcs it advances, to which stage, and which promise it pays | The lens pass proved this insertion point works |
.claude/skills/normalize-doc/SKILL.md | one rubric item: arc declarations present, stages legal, promises paid or explicitly carried | The critic gate is where node-level arc hygiene lands |
new .claude/skills/arc-pass/SKILL.md | the sibling of /spine-chapter, keyed on arc_id instead of CH_NN | Makes the arc pass a first-class, repeatable procedure |
harness/gates_config.json | register arc_continuity | Or the gate never runs |
docs/DOC_MAP.md | rows for the registry, the gate, the skill | Anti-orphan doctrine: not done until listed |
---
The pre-5090 window plan is 30 ranked items. The arc architecture should ride items already
queued rather than add a 31st, and three queued items are **arc work that is currently
mis-filed as bookkeeping**:
1. Rank 28 (zero-token) — "derive Thread_Registry's 5 empty columns from Thread_Grid's 664
rows." This is the pilot. Running the derivation produces the shape diagnostic and proves
T-1/T-6 against real data at zero model cost. Do it first, today, as the proof-of-concept for
the whole registry. It also fills resolution_chapter (0/22 today).
2. Rank 9 — the narrative-craft seed gate (reversal/cost/residue). **Author it at ARC scope
as well as seed scope** (§4.3 rubric 2). It is already scheduled BEFORE rank 10's typing pass;
the arc scope costs almost nothing extra at authoring time and is where the criterion bites.
3. Rank 10 — the 264-seed housing typing pass. Assign arc_id at typing time. Seeds
typed only by region become 264 orphans-with-a-home-address; seeds typed by arc become the
ADVANCE/TEST rows the twelve side questlines are missing. This single change is what turns
the hub-and-spoke gap (register #3) and the flat-SQ finding into the same fix.
4. Rank 11 (Persona_Index) — carries the companion_ref FK and the arc participants.
5. Ranks 15 / 23 / 24 mint the missing homes (Quest_Definition execution columns; the 120
trade-gate rows; T1_Personal_Dimension_Spec for partnership). Each should mint **with
arc_id present**, not retrofitted.
6. The interior arc (§2.10) should be minted as ARC_0001 **as part of the amulet
integration**, not after it — while the 18-file plan is live and its beats are known. This is
the one recommendation with a closing window.
Ordering rationale: the registry needs no new authoring to start (Thread_Grid + Antagonist +
familiar rows import), the gate is honest on day one via the declared-not-armed pattern, and
every subsequent queued item then lands INTO a home instead of beside one.
---
**"This is a second bookkeeping layer over data that already exists in the spine nodes. The v3.1
beat graph is the truth; an arc registry duplicates it and will drift."**
This is the right objection and it has real teeth — the corpus has already been burned by
registries that drift from their source (13 C++ row structs drifted from CSVs, register #21).
The answer is that the arc grid must be DERIVED, not authored in parallel. The spine node is
and remains the single writable source: the node's Block 11 SQ rows, its mark_write blocks, its
actors: lines, and its thread cells are already the arc data — they are just never assembled.
So T0_Arc_Grid is emitted by a script from the 79 nodes (exactly as slice_coherence derives
its manifests, and as rank 28 derives Thread_Registry from Thread_Grid), and the freshness of
that derivation is itself a gate assertion — the check_index_freshness / check_seed_housing
pattern, where the gate is the consumer that makes the artifact non-orphan.
Only T0_Arc_Index's judgement columns are authored: promised_beats, open_by_design,
layer_span, lens_set, variance_axis, care_band. Everything derivable is derived. That
keeps one writable home per fact (the living-source rule) and makes drift structurally impossible
rather than policed.
Residual honest risk (INFERRED): the ANCHOR → SEED|PRESENT disambiguation cannot be
derived — it needs a read. That is ~22 thread judgements, one arc pass, once. It is the cost of
having let one enum value absorb 441 cells, and it is small.
---
Everything above is execution within the locked vision — no pillar, no numerical canon, no
naming, no §17 surface is touched, and the locked 22 questline buckets are explicitly preserved.
Per the standing protocol this is apply-and-show, not ask. Two items are worth a brief (not a
bare question) because they touch vocabulary that other docs cite:
progression_stage enum. Reconciling three live vocabularies into one changes tokens that check_spine_graph and the v3.1 schema enumerate. Recommendation: adopt
§3.3's superset with the lossless mapping table, migrate Thread_Grid as a view, retire after
one release. Strongest objection: churn in a schema that was just stabilized at v3.1 — answered
by the view-then-retire path, which makes the migration reversible.
trickery_gambling (2 nodes) and pirate_naval (6 nodes, no SEED) are under-built or
deliberately minor is a design call about the twelve-questline promise, and it is the kind
of call the open_by_design column exists to record either way. Recommendation: build them
up — twelve promised side stories where one has two beats reads as an unfinished list, not a
deliberate asymmetry. Strongest objection: not every questline needs equal weight; the counter
is that open_by_design makes the asymmetry a declared choice instead of an accident, which is
the actual requirement.
---
| Claim | Method | Result |
|---|---|---|
arc_id absent corpus-wide | grep -rl arc_id registries/ docs/ harness/; positive control thread_id | 0 hits; control returns hits |
| Thread_Grid stage distribution | script over 664 rows | ANCHOR 441 / ESC 106 / NOT_PRESENT 49 / CONF 45 / RES_FINAL 15 / RES_PARTIAL 4 / CONV 2 / CONF_DIRECT 1 / CAPSTONE 1 |
| 15/22 threads no resolution | script; stage-set test per thread | T07-T19, T21, T22 |
| THREAD_19 monotone | script | 10 appearances, stage-set = {ANCHOR} |
| Thread_Registry derived cols empty | CSV read, 22 rows | resolution_chapter 0/22 filled |
| SQ stage counts | grep -h "^- SQ" docs/spine/CH_*.md (376 rows) | SEED 23 / ADVANCE 336 / GATE 0 / COMPLETE 11 |
| GATE zero is real, not a bad filter | same filter returns SEED/ADVANCE/COMPLETE hits | POSITIVE-CONTROLLED |
| 5 SQs never COMPLETE | per-questline stage counter | cryptids, lost_civilizations, military_history, pirate_naval, trickery_gambling |
| Trade gate ids dangling | grep -c Q_TR in Quest_Definition_Registry; control quest_id | 0 hits; control returns 1 |
| Companion loyalty data density | CSV read, 163 rows | loyalty_model 6 · loyalty_belief_axis 4 |
| Companion arc has no bucket/class/FK | CITED docs/pipeline_review/LENS_BG3_2026-07-27.md BG3-3 (carries its own positive control + 3 self-refutations) | WEAKER, survives |
| Marriage/partnership zero | grep -rli marriage registries/ | 1 hit = a book title in Source_Material_Registry |
| Antagonist grid coverage | CSV read, 64 rows | 62 distinct chapters |
mark_write/forward_track density | grep -h over 80 spine files | 338 lines across 51 nodes |
| Significance lenses ARE wired (WIRING_AUDIT is stale) | grep -c significance .claude/skills/spine-chapter/SKILL.md | 10 hits incl. a dedicated Step 3a |
| slice_coherence reads a sequence | file docstring | carried-familiar + link-reciprocation manifests |
| spine_graph cross-file ERROR tier | docs/SPINE_SCHEMA_v3.md §6 | forward_track continuity, path_bucket consistency, seam equality |
| Path-flat endgame | CITED WHOLE_ARC_CONNECTIVE_WEB_INVENTORY.md ECV-01/02/05/07 | CH_75/76/77 render found-family path-flat |
| 65 through-line chains, 9 orphan/unpaid | CITED WHOLE_ARC_CONNECTIONS_PASS.md §1 | headline counts |