-- Utterances: the content of a dialogue node (and utterance-bearing cutscenes). -- One table for both NPC lines and player choices, distinguished by `utterer`. -- The intra-node conversation graph uses two self-references; `terminal_id` is the -- exit that leaves the node via one of its output terminals. Runtime is Phase 2. CREATE TABLE osint.utterances ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), node_id UUID NOT NULL REFERENCES osint.story_nodes(id) ON DELETE CASCADE, utterer TEXT NOT NULL DEFAULT 'npc' CHECK (utterer IN ('npc','player')), npc_id UUID REFERENCES osint.npcs(id), -- speaker for NPC lines; NULL for player choices pose_key TEXT, -- resolved with the usual pose fallback text TEXT NOT NULL DEFAULT '', -- Intra-node conversation graph: parent_utterance_id UUID REFERENCES osint.utterances(id) ON DELETE CASCADE, -- player options hang under the NPC prompt they answer advances_to_utterance_id UUID REFERENCES osint.utterances(id) ON DELETE SET NULL, -- next line; may loop back to the same one -- Inter-node exit: terminal_id UUID REFERENCES osint.story_node_terminals(id) ON DELETE SET NULL, effect TEXT, -- optional authored side-effect hook (vocabulary TBD) xpos DOUBLE PRECISION NOT NULL DEFAULT 0, -- position in the node's utterance sub-canvas ypos DOUBLE PRECISION NOT NULL DEFAULT 0, sort_order INTEGER NOT NULL DEFAULT 0 ); CREATE INDEX utterances_node_idx ON osint.utterances (node_id); COMMENT ON TABLE osint.utterances IS 'Dialogue content per story node. Same-node integrity for parent/advances_to/terminal links is enforced in the repository (Phase 1).';