feat(gig-log): record what was PLAYED, not what was looked at
#150, and the fix at the source of #148.
gig-log recorded tab-focus events -- which file PLN was LOOKING at. Album
track boundaries were then derived from those, and they were wrong, because a
livecoder tabs around constantly while a pattern keeps running. Looking at a
file is not playing it.
An EVAL is the moment a pattern actually changes. That is the honest boundary.
SIGNAL SOURCE
`atom.commands.onDidDispatch` in the HUD package, filtered to `tidalcycles:eval*`.
Confirmed ctrl+enter maps to `tidalcycles:eval-multi-line` in Pulsar's own
keymap, and that MULTI_LINE sends exactly the blank-line-delimited paragraph
around the cursor -- which is already this repo's block convention. onDidDispatch
rides Atom's EXISTING command routing, so it adds no new per-keystroke listener:
it cannot make the renderer burn worse.
Rejected: GHCi stdout (no stable per-eval marker without changing the REPL
protocol) and SuperDirt OSC sniffing (needs its own listener process -- closer
to the observer-perturbs trap this rig has already been burned by).
SHAPE
New `k:"eval"` record {t, path, d}, where d is a best-effort list of dN streams
found by a narrow regex: dN as the FIRST token of a line, inside the evaluated
block only. Documented as best-effort rather than dressed up as complete.
Transport is ~/.cache/parvagues/eval-events.jsonl, APPEND-only -- unlike
current-track, which overwrites. An eval is an EVENT, in the same category as a
MIDI note, never coalesced; current-track is STATE. Conflating the two is how
the focus lens got mistaken for a play lens in the first place.
`EvalTail` polls it once per tick with a byte-offset seek, buffers torn lines,
and rebaselines if the file shrinks or is recreated -- the same pattern
XrunReader already uses for node respawns. It never replays pre-session content.
`track` events are UNTOUCHED. This adds a lens; it does not replace one.
Boundary detection wants several (gap < orbit-flip < tempo), and focus is still
the cheapest of them.
BLAST RADIUS
Folded into load()'s existing marks list exactly as `track` is, so cmd_report
renders it for free and load()'s tuple signature does not change. The one real
consumer, tools/take-segments.py, reads the JSONL itself and already ignores
any `k` it does not recognise -- verified by reading it, not assumed.
VALIDATION
111/111 python tests pass (91 pre-existing + 20 new), covering the pure
normalizer, the tail's offset / torn-line / rebaseline behaviour, and a full
write -> load round trip.
NOT VERIFIED: whether the running gig-log.service picks this up without a
restart. It was deliberately left alone -- PLN was performing.
Showing