decisions/spine/clues/README.md
One authored CSV per spine node (CH_NN.csv). A clue is first-class data: the in-world source a
player can actually encounter that EARNS a mechanic read ("how would they have gotten a clue?" —
the standing test). Emitted by harness/extract_spine_rows.py as build/spine_rows/<node>/clues.csv
(header-always for every node; rows only where authored; the extractor REJECTS a row whose
source_kind is not in the legal enum or whose src/player_text is empty).
Columns: `chapter_id, clue_id, chain, source_kind, beat_scope, trigger_context, player_text,
status, src`.
chain — the read this clue makes legible (e.g. guardian_withdraw, hunter_taken, cold_air, hollow_gift). Clues in one chain OR together: any one earns the read, none gates —
clue = LEGIBILITY, NEVER a gate (resolutions stay keyed on the raw player action).
source_kind ∈ {observed_behavior, npc_dialogue, inscription, journal_deduction, item_examine}.beat_scope — the beat window where the clue can fire; trigger_context — internal staging note.player_text — the field-sense line surfaced on discovery (pre-Ch-13 this lands on theFIELD-SENSE re-read affordance, never the journal — HL_0070). Spoiler-safe register, same rules
as docs/spine/player_strings/ (reveal-discipline critic required before landing).
status — active, or reserve when the clue's premise needs an engine system the slice doesnot have (an engine-phantom clue must never ship as readable-but-false). Enum-enforced at emit.
bargain-hollowness rides hollow_gift (H1), not a fourth cold_air instance; do not duplicate a
sensation across chains to satisfy a list (critic-reviewed divergence from FUN_REBUILD R3.7).
src — the canon citation (cited-or-cut; positive-control the cite before authoring).Consumers: the WS-C runtime clue-state (fire + persist), the W10 field-sense display + toast, the
clue-staged objective display (GetBeatObjectiveText returns the highest unlocked stage on top of
the player_strings stage-0 base).