Listening (src/listening.ts reads and writes all three, through src/listening-store.ts). Anonymous: no address, visitor or account. A performance keeps the day it was recorded (not the time), so history can be read by date; nothing else says who or when.
reactions: the 🔥/😴 buttons of every listener, a count per (song,
section, reaction). section is the name the song's form gives it
(walk()), or the section's number in a song without a form; the Worker
cannot check it against the song, so the page shows and sends Jev only
the names its song's form has.
11CREATE TABLE reactions ( 12 song TEXT NOT NULL CHECK (length(song) BETWEEN 3 AND 129), 13 section TEXT NOT NULL CHECK (length(section) BETWEEN 1 AND 64), 14 reaction TEXT NOT NULL CHECK (reaction IN ('fire', 'sleep')), 15 n INTEGER NOT NULL CHECK (n > 0), 16 PRIMARY KEY (song, section, reaction) 17) STRICT;
performances: one play of a song, as Jev arranged it, for a replay link
(/songs/<song>/?performance=<id>) and for Jev's decision history.
code_hash is the SHA-256 of the code that played, so a replay of code
changed since can say so. form_jev/form_question name the choice a
walk() form is over, when the song has one.
24CREATE TABLE performances ( 25 id TEXT PRIMARY KEY CHECK (length(id) = 22), 26 song TEXT NOT NULL CHECK (length(song) BETWEEN 3 AND 129), 27 code_hash TEXT NOT NULL CHECK (length(code_hash) = 64), 28 model TEXT NOT NULL, 29 every INTEGER NOT NULL CHECK (every > 0), 30 ended TEXT NOT NULL CHECK (ended IN ('finished', 'stopped')), 31 jevs INTEGER NOT NULL CHECK (jevs > 0), 32 form_jev INTEGER CHECK (form_jev >= 0 AND form_jev < jevs), 33 form_question TEXT, 34 day TEXT NOT NULL CHECK (day GLOB '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'), 35 CHECK ((form_jev IS NULL) = (form_question IS NULL)) 36) STRICT; 37CREATE INDEX performances_by_song ON performances (song);
performance_segments: Jev's decision history, one row per segment per
jev() of a performance. answers is the JSON the segment played, keyed
by question: { choice | score | noul, confidence?, probabilities?,
sampled?, top?, fallback?, forced?, absent? } (jevCore.mjs's answers).
section is the form's section this segment plays and after_section
the one before it, when there is a form: so "what does Jev pick after
drop2d" is WHERE after_section = 'drop2d', and json_each(answers)
reaches every question.
47CREATE TABLE performance_segments ( 48 performance TEXT NOT NULL REFERENCES performances (id) ON DELETE CASCADE, 49 jev INTEGER NOT NULL CHECK (jev >= 0), 50 segment INTEGER NOT NULL CHECK (segment >= 0), 51 section TEXT, 52 after_section TEXT, 53 status TEXT NOT NULL CHECK (status IN ('opening', 'answered', 'fallback')), 54 ms INTEGER CHECK (ms >= 0), 55 from_cycle INTEGER CHECK (from_cycle >= 0), 56 answers TEXT NOT NULL CHECK (json_valid(answers) AND json_type(answers) = 'object'), 57 PRIMARY KEY (performance, jev, segment), 58 CHECK (segment > 0 OR after_section IS NULL) 59) STRICT; 60CREATE INDEX performance_segments_by_section ON performance_segments (section, after_section);