SPEC.mdpreviewSPEC.mdsource308 lines · 21.0 KB · raw
1---
2title: BORROW CHECKER BLUES
3theme: jev
4status: made
5song: song.js
6measured: {"date":"2026-09-26","song":"c754533d1086","total":{"loudnessDbfs":-21.8,"peakDbfs":-2.1},"parts":{"bass":{"loudnessDbfs":-29.3,"peakDbfs":-14},"drums":{"loudnessDbfs":-24.2,"peakDbfs":-3.3},"other":{"loudnessDbfs":-39.3,"peakDbfs":-5.5},"stabs":{"loudnessDbfs":-33.3,"peakDbfs":-12},"vocals":{"loudnessDbfs":-30.2,"peakDbfs":-5.8}},"sections":{"1-4":{"total":{"loudnessDbfs":-29.1,"peakDbfs":-14},"parts":{"bass":{"loudnessDbfs":-29.1,"peakDbfs":-14}}},"5-8":{"total":{"loudnessDbfs":-22.3,"peakDbfs":-6.9},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14.4},"drums":{"loudnessDbfs":-23.7,"peakDbfs":-9.1}}},"9-12":{"total":{"loudnessDbfs":-20.9,"peakDbfs":-3.2},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14.1},"drums":{"loudnessDbfs":-23.5,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.2,"peakDbfs":-13.5},"vocals":{"loudnessDbfs":-26.6,"peakDbfs":-6.5}}},"13-16":{"total":{"loudnessDbfs":-20.6,"peakDbfs":-2.9},"parts":{"bass":{"loudnessDbfs":-29.3,"peakDbfs":-14.4},"drums":{"loudnessDbfs":-23.5,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.3,"peakDbfs":-14.7},"vocals":{"loudnessDbfs":-27.1,"peakDbfs":-6.1}}},"17-20":{"total":{"loudnessDbfs":-20.5,"peakDbfs":-2.4},"parts":{"bass":{"loudnessDbfs":-29.1,"peakDbfs":-14},"drums":{"loudnessDbfs":-23.5,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.2,"peakDbfs":-13.5},"vocals":{"loudnessDbfs":-25.6,"peakDbfs":-5.9}}},"21-24":{"total":{"loudnessDbfs":-21.2,"peakDbfs":-2.2},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14.4},"drums":{"loudnessDbfs":-23.4,"peakDbfs":-3.6},"stabs":{"loudnessDbfs":-32.5,"peakDbfs":-14},"vocals":{"loudnessDbfs":-30.8,"peakDbfs":-5.9}}},"25-28":{"total":{"loudnessDbfs":-22.1,"peakDbfs":-4.6},"parts":{"bass":{"loudnessDbfs":-29.1,"peakDbfs":-14.1},"drums":{"loudnessDbfs":-23.4,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.3,"peakDbfs":-12.8}}},"29-32":{"total":{"loudnessDbfs":-21.7,"peakDbfs":-3.5},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14.4},"drums":{"loudnessDbfs":-23.4,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.4,"peakDbfs":-13.4},"vocals":{"loudnessDbfs":null,"peakDbfs":null}}},"33-36":{"total":{"loudnessDbfs":-21.3,"peakDbfs":-3.8},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14},"drums":{"loudnessDbfs":-23.5,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.5,"peakDbfs":-13.5},"vocals":{"loudnessDbfs":-28.1,"peakDbfs":-6.3}}},"37-40":{"total":{"loudnessDbfs":-20.2,"peakDbfs":-2.1},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14.4},"drums":{"loudnessDbfs":-23.5,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.4,"peakDbfs":-14.7},"vocals":{"loudnessDbfs":-25.4,"peakDbfs":-6.4}}},"41-44":{"total":{"loudnessDbfs":-20.5,"peakDbfs":-2.4},"parts":{"bass":{"loudnessDbfs":-29.1,"peakDbfs":-14},"drums":{"loudnessDbfs":-23.5,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.2,"peakDbfs":-13.5},"vocals":{"loudnessDbfs":-25.6,"peakDbfs":-5.8}}},"45-48":{"total":{"loudnessDbfs":-21.2,"peakDbfs":-2.2},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14.4},"drums":{"loudnessDbfs":-23.3,"peakDbfs":-3.3},"stabs":{"loudnessDbfs":-32.3,"peakDbfs":-12.6},"vocals":{"loudnessDbfs":-30.7,"peakDbfs":-5.9}}},"49-52":{"total":{"loudnessDbfs":-22.1,"peakDbfs":-4.7},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14},"drums":{"loudnessDbfs":-23.5,"peakDbfs":-5.1},"stabs":{"loudnessDbfs":-32.2,"peakDbfs":-12.6}}},"53-56":{"total":{"loudnessDbfs":-21.7,"peakDbfs":-3.7},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14.4},"drums":{"loudnessDbfs":-23.4,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.3,"peakDbfs":-12}}},"57-60":{"total":{"loudnessDbfs":-22.1,"peakDbfs":-4.5},"parts":{"bass":{"loudnessDbfs":-29.1,"peakDbfs":-14},"drums":{"loudnessDbfs":-23.4,"peakDbfs":-5},"stabs":{"loudnessDbfs":-32.2,"peakDbfs":-12.7}}},"61-64":{"total":{"loudnessDbfs":-25,"peakDbfs":-5},"parts":{"bass":{"loudnessDbfs":-29.2,"peakDbfs":-14.4},"drums":{"loudnessDbfs":-72.1,"peakDbfs":-42.4},"other":{"loudnessDbfs":-27.1,"peakDbfs":-5.5},"stabs":{"loudnessDbfs":-56.7,"peakDbfs":-23.6}}}}}
7critic:
8  date: 2026-09-26
9  model: jev-1.13.0
10  method: rubric-1
11  art: 0.66
12  artRuns: [0.66, 0.66, 0.66]
13  criteria:
14    hook: 3.1
15    development: 3.2
16    structure: 3.2
17    concept: 3.9
18    originality: 3.6
19    craft: 2.9
20ideas:
21  - date: 2026-09-24
22    model: claude-opus-5-5
23    harness: claude-code
24    prompt: "Give me some song ideas as prompts, in the same Jev theme: perhaps with actual memes in the vocals, or a vocoder sound."
25    brief: "Daft Punk–style French house at 124 bpm. A vocoder robot sings real Rust compiler errors as the lyrics: \"cannot borrow as mutable\", \"lifetime may not live long enough\". Every time it finally compiles, drop \"It's free real estate\". Filtered disco chords and a four-on-the-floor kick. Vocals in the verses and chorus only."
26revisions:
27  - rev: 1
28    date: 2026-09-24
29    model: claude-opus-5-5
30    harness: claude-code
31    prompt: "Daft Punk–style French house at 124 bpm. A vocoder robot sings real Rust compiler errors as the lyrics: \"cannot borrow as mutable\", \"lifetime may not live long enough\". Every time it finally compiles, drop \"It's free real estate\". Filtered disco chords and a four-on-the-floor kick. Vocals in the verses and chorus only."
32    output: null  # overwritten by rev 2
33    art: 0.57
34    artRuns: [0.57, 0.57, 0.57]
35  - rev: 2
36    date: 2026-09-24
37    model: claude-opus-5-5
38    harness: claude-code
39    prompt: "Let Jev arrange the song as it plays. Cut it into named 4-bar sections, each with the sections allowed to follow it; at every section Jev picks the next section, the move to play it with (as written, no drums, bass and drums, no vocals) and how intense it is, and ends the song by choosing the outro, with a cap of 24 sections. Tell Jev the tempo, key, chords, lyrics and everything played so far. Without Jev it plays as written."
40    output: null  # overwritten by rev 3
41    art: 0.63
42    artRuns: [0.63, 0.62, 0.63]
43  - rev: 3
44    date: 2026-09-24
45    model: claude-opus-5-5
46    harness: claude-code
47    prompt: "Instead of one move per section, let Jev set each part (robot bass, drums, disco stabs, vocals) out, back or full for the section, each on its own orbit, and pick how the song moves into the section over the last bar before it: a cut, a kick-and-clap fill, a riser of disco stabs on the bar's chord, or a one-beat dropout. The outro's last beat always plays. Without Jev every part plays full and each section comes in on a cut."
48    output: null  # overwritten by rev 4
49    art: 0.62
50    artRuns: [0.62, 0.62, 0.62]
51  - rev: 4
52    date: 2026-09-25
53    model: claude-opus-5-5
54    harness: claude-code
55    prompt: "Make the hook, the payoff and the mix land. Sing the hook as \"Lint. Before you spend.\" so it is not heard as \"link\", with no clap on its second beat. Before each Wow the robot sings cargo's \"Finished dev profile\", so the Wow answers the build succeeding. The first verse line is rustc's own label, \"cannot borrow as mutable\", and the last is E0499, \"cannot borrow as mutable more than once at a time\". The disco stabs carry the harmony within about 6 dB of the bass and open bar by bar through each groove; the bass takes each chord's own seventh, the major seventh on Dmaj7, and its sub sits an octave higher; the grooves open on a real crash. Within a phrase Jev moves on with a cut or a fill; risers and dropouts only between phrases, never over a Wow, and a transition follows the part levels of the section it plays in. Energy scales the parts and transitions but never the ending, and nothing clips."
56    output: null  # overwritten by rev 5
57    art: 0.66
58    artRuns: [0.66, 0.66, 0.66]
59  - rev: 5
60    date: 2026-09-26
61    model: claude-opus-5-5
62    harness: claude-code
63    prompt: "Keep Jev from looping a groove: each groove may go round once more at most, cut short, so the first section of each groove plays at most twice and its last section once, and no run of grooves passes 36 bars. Every detour still plays. The opening has no section before it, so its move in is a cut and Jev's levels for it play."
64    output: song.js
65    art: 0.66
66    artRuns: [0.66, 0.66, 0.66]
67---
68
69# BORROW CHECKER BLUES — spec
70
71`song.js` is generated from this spec. Change the spec first, then the song.
72
73## Intent
74
75Deterministic tools in front of Jev. The Jev tie-in is `jevkit`
76(`~/brains/personal/technology/artificial-intelligence/jev/ecosystem/jevkit.md`): a Rust CLI whose `jev lint` checks a
77question set offline against 13 rules before any API spend — about 0.5 ms
78locally against a 273 ms API call — because on identical input, rewording the
79options inverted Jev's verdict. The compiler says no before the model is
80ever asked.
81
82Two changes from the brief:
83- **Genre and tempo:** robot-funk at 110 bpm, E dorian, split from TOO CHEAP
84  TO METER's 124 bpm A minor French house, instead of French house at 124.
85- **Payoff meme:** Owen Wilson's "Wow" instead of "It's free real estate",
86  which TOO CHEAP TO METER uses.
87
88## Style
89
90- Robot-funk, 110 bpm, E dorian: Em7 – A7 – Dmaj7 – Bm7, two bars per chord,
91  so each vocoded line sits on one chord.
92- Slap-style synth bass line carrying the song; talk-box feel from the
93  vocoder; four-on-the-floor kick, clap on 2 and 4, open hats.
94- The riff takes each chord's own 7th: the minor 7th on Em7, A7 and Bm7
95  (D, G, A), the major 7th on Dmaj7 (C♯), so the bass never plays a C
96  natural under the chord's C♯ or the lines sung on it.
97- The sub doubles the chord's root at E2, A2, D2 and B1 (82, 110, 73 and
98  62 Hz): never under 60 Hz, where a laptop speaker plays nothing and the
99  bass-only intro and outro would thin out.
100- Filtered disco chord stabs (short, not a pad). They carry the only
101  harmony, so they sit within about 6 dB of the bass, not under the drums.
102
103## Structure
104
10564 bars (~2:20).
106
107| Bars | Section | Contents |
108|---|---|---|
109| 1–8 | Intro | Bass line alone; four-on-the-floor kick from bar 5 |
110| 9–16 | Verse 1 | Compiler errors 1–4; claps, hats, filtered stabs |
111| 17–20 | Chorus | "Lint. Before you spend." on bars 17 and 19, with no clap on their second beat so the "t" of "Lint" is heard; on 20 the build succeeds: "Finished dev profile", then "Wow" on the and of beat 3 |
112| 21–32 | Groove | Instrumental; open hats; crash on 21; the stab filter opens bar by bar, 1000 → 1800 Hz |
113| 33–40 | Verse 2 | Compiler errors 5–8 |
114| 41–44 | Chorus | As before, the claps out of 41 and 43 |
115| 45–60 | Groove | Instrumental; crash on 45; the stab filter opens bar by bar, 2000 → 6000 Hz |
116| 61–64 | Outro | Bass line alone; "Finished dev profile" on 62, the final "Wow" on 63 |
117
118Each part as written, per section (what Jev's "full: as written" means):
119
120| Section | Plays as written |
121|---|---|
122| Intro, bars 1–4 | bass |
123| Intro, bars 5–8 | bass, drums (kick only) |
124| Verses, choruses | bass, drums, stabs, vocals |
125| Grooves | bass, drums, stabs |
126| Outro | bass; its "Finished dev profile" and "Wow" are the ending, not the vocals part |
127
128Verse 2 starts on bar 33 so each vocoded line lands on the first bar of its
129chord (the harmony cycles every 8 bars); so the first groove is 12 bars and
130the second 16.
131
132## Vocals
133
134- Vocoder, one line per 2 bars — real rustc error texts, as rustc 1.98.1
135  prints them (each checked by compiling a small program that triggers it):
136  1. "Cannot borrow as mutable" — Em7 (E0596's span label, under "cannot borrow `v` as mutable, as it is not declared as mutable"; the brief's own wording)
137  2. "Lifetime may not live long enough" — A7
138  3. "x does not live long enough" — Dmaj7 (E0597)
139  4. "Use of moved value" — Bm7 (E0382)
140  5. "Mismatched types" — Em7 (E0308)
141  6. "Which is behind a shared reference" — A7 (E0507: "cannot move out of `*s` which is behind a shared reference")
142  7. "Expected Foo, found Bar" — Dmaj7 (E0308's label for a struct/enum mismatch)
143  8. "Cannot borrow as mutable more than once at a time" — Bm7 (E0499: "cannot borrow `x` as mutable more than once at a time")
144- Chorus (vocoder): "Lint. Before you spend." — rendered on Em7 and on A7, the
145  two chords the chorus lines land on. The full stop keeps "Lint" apart
146  from "before"; run together it is heard as "Link".
147- The build succeeding (vocoder, the same robot as the errors): "Finished
148  dev profile", cargo's own line when a build compiles
149  (`` Finished `dev` profile [unoptimized + debuginfo] target(s) ``, cargo
150  1.98), right before each "Wow" — rendered on A7 for the choruses' bars
151  20 and 44, and on Dmaj7 for the outro's bar 62. It lasts 1.4 s, more
152  than half a bar, so in the chorus the "Wow" comes on the and of beat 3.
153- Meme: Owen Wilson "Wow", the answer to the build succeeding.
154- Every vocoder line has to transcribe correctly with both whisper small.en
155  and medium.en before it ships; `samples/README.md` records what each
156  model read back.
157
158## Jev in the booth
159
160Jev arranges the song as it plays, as two jevs declared at the top in
161TypeSafe's own shape (`jev({ state, questions })`, `website/src/jev/`), both
162given the song as state (subject, tempo, key, chords, lyrics):
163
164- **`formJev`** asks one choice: which **section** plays next, among the
165  song's sixteen 4-bar sections (the chorus and the outro are 4 bars, so 4
166  is the length that divides every section).
167- **`djJev`** asks, once that is decided, a level per part (robot bass,
168  drums, disco stabs, vocals: out, back or full in this section), how the
169  song moves **into** it (a choice) and a score for the section's
170  **energy**. Questions in one request cannot see each other's answers, so
171  it is a second request, told the section just chosen (`after: { section
172  }`).
173
174Both are asked every 4 bars (`.every(4, …)`), and the answers are composed
175in ordinary Strudel at the bottom: `walk` holds the form's rules, each
176part plays at its level, the transition plays over the last bar before
177the section, and `energy.score` scales the velocity.
178
179**The form.** A section may be followed only by these:
180
181| Section | Bars as written | May be followed by | Plays at most |
182|---|---|---|---|
183| `intro1` | 1–4 | intro2 | |
184| `intro2` | 5–8 | verse1a | |
185| `verse1a` | 9–12 | verse1b | |
186| `verse1b` | 13–16 | chorus1 | |
187| `chorus1` | 17–20 | groove1a, verse2a | |
188| `groove1a` | 21–24 | groove1b | twice |
189| `groove1b` | 25–28 | groove1c, verse2a | |
190| `groove1c` | 29–32 | verse2a, groove1a | once |
191| `verse2a` | 33–36 | verse2b | |
192| `verse2b` | 37–40 | chorus2 | |
193| `chorus2` | 41–44 | groove2a | |
194| `groove2a` | 45–48 | groove2b | twice |
195| `groove2b` | 49–52 | groove2c, outro | |
196| `groove2c` | 53–56 | groove2d, groove2a | once |
197| `groove2d` | 57–60 | outro, groove1a, chorus2, verse1a | |
198| `outro` | 61–64 | (the end) | |
199
200These rules are code (`walk`), not Jev: each request offers Jev only the
201sections allowed next. The written order is always allowed, and it is what
202plays when Jev can't be reached. The song ends when Jev picks the outro, whose last "Wow" always
203plays; at 24 sections (96 bars, about 3½ minutes) the outro is forced. A
204section plays its own bars, so each vocoded line still lands on its chord.
205
206A detour (`groove1b` → `verse2a`, `groove1c` → `groove1a`, `groove2c` →
207`groove2a`, `groove2d` → `groove1a`, `chorus2` or `verse1a`) can leave an
2088-bar progression halfway, so the next section repeats the half it left:
209two bars of Dmaj7 and Bm7 again, or of Em7 and A7. In a funk vamp over four
210chords that is accepted, and it keeps the detours musical.
211
212**Loops end.** Uncapped, the ways back let Jev loop a groove until the cap:
213a review heard the first groove go round for 44 bars, and the form allowed
21456. So each groove's first section plays at most twice and its last section
215once in a performance (`times` in `walk`, which counts every play, since a
216loop is a cycle of different sections and none of them repeats back to
217back): a groove goes round once more at most, and the repeat is cut short
218(groove1a → b → c → a → b, then on). The longest run of grooves any path can
219now take is 36 bars, groove 2 and then its detour into groove 1 once round,
220where it was 56. Every detour can still play, and the written order is never
221capped. A section that has played its most is not offered, nor is one that
222could only reach the outro through one.
223
224**The parts.** Each question says what the part is and where it plays as
225written, and Jev sets each one **out** (silent for the section), **back**
226(under the rest of the mix) or **full** (as written): the bass alone before
227the beat returns, the stabs pulled back under a verse, an instrumental
228chorus. The level is a Score, so it is Jev's probability-weighted answer:
229under 0.5 the part is silent, and above it the part plays at its nearest
230step: back at half velocity, full as written. A part that plays
231keeps its own masks, so vocals still appear only where the structure table
232puts them. Each part plays on its own orbit named for its question
233(`bass`, `drums`, `stabs`, `vocals`), so the browser's meter hears each
234one alone. Each section's description in the section choice names the
235parts it plays as written (the table under Structure), and the outro's
236lyrics say its "Wow" is the ending: the outro's "Finished dev profile" and
237"Wow" are not a part and always play. When Jev can't be reached, every
238part plays full.
239
240**Into the next section.** Jev also picks how the song moves into the
241section it is deciding, and it plays over the last bar of the section
242before it: **cut** (straight in), **fill** (a kick and clap fill, getting
243denser into the downbeat), **riser** (the disco stabs repeating in
244sixteenths on the chord of the bar, their filter sweeping open) or
245**dropout** (every part stops for the last beat, a gap before the section
246hits). The outro has no section after it, so its last beat always plays.
247When Jev can't be reached, it is a cut. The rules are code, not Jev:
248
249- Within a phrase (intro1 → intro2, a verse's a → b, a groove's a → b → c
250  → d, and a groove back to its own start) the move is a cut or a fill;
251  a riser or a dropout is offered only where one phrase gives way to
252  another (`allow` on the `into` choice). The opening has no section
253  before it, so nothing plays into it: its move is a cut, unasked, and
254  Jev's levels for the opening play.
255- No transition plays over a chorus's "Wow" bar (bars 20 and 44 as
256  written), wherever the chorus falls in Jev's arrangement.
257- A riser's filter ends where the next section's stabs begin (their
258  `stabLpf` on its first bar), and its level never goes over the stabs'.
259- A transition follows the part level of the section it plays in: the
260  fill is the drums part, the riser the stabs part, so a part Jev set out
261  takes its transition with it.
262
263**A little chance.** The section is sampled from Jev's
264probabilities at temperature 0.7 (`sample`), so two plays of the song can
265take different paths; the strip shows Jev's top pick beside the one
266sampled. A close call between
267sections is where sampling matters most, so there is no confidence
268threshold: an unsure Jev still picks, and the written order plays only
269when Jev can't be reached.
270
271**Energy** is a four-step ladder, from held back to all out. It scales
272every part's velocity and the transitions together (0.55 to 1), so the mix
273keeps its balance. The ending is not scaled: the outro's "Finished dev
274profile" and last "Wow" play at their written level.
275
276- Bars 1–4 always play as written.
277- Each request tells Jev the song's subject, tempo, key, chords and lyrics
278  (its state), what every section holds (the section choice's options),
279  where the song is in the form and the sections left before the cap,
280  everything played so far, how loud each finished section measured in the
281  browser, and the 🔥/😴 reactions from the listener's tab.
282- This relaxes the constraint below that the song plays once in a fixed
283  order: the arrangement varies with Jev's choices, which are judgments,
284  with a little sampled chance in the form.
285
286## Constraints
287
288- Plays once from bar 1 and ends; never loops. Sections are absolute-cycle
289  masks, so playback starts from stopped.
290- Structured: patterns vary by section, never by chance. (Random chopping
291  read as noise on the first song.)
292- No sustained background pad; harmony comes from rhythmic parts.
293- Vocals only where the structure table puts them; drops are instrumental.
294- Meme clips are the real audio (myinstants, or YouTube via yt-dlp), cut at
295  word timings measured with whisper.cpp. Vocoder lines are made with
296  `speak` + `vocode` on the chord they land on, and checked by transcribing
297  the result with whisper small.en and medium.en. Everything lands in
298  `samples/<sound>/` with a provenance row in `samples/README.md`.
299- Samples load from `samples('jev-samples/strudel.json')`; drums from
300  `github:tidalcycles/dirt-samples`. The crash is `hh27:1` (Dirt-Samples'
301  `cr` holds only ride cymbals), its gain matched to the ride it replaced.
302- The mix peaks at or under -1 dBFS, a decibel of headroom: superdough has
303  no master limiter, so the levels keep it there (kick .5, clap .42) and a
304  master level of .7 on the whole song (postgain) keeps the measured peak
305  under -1 dBFS (.8 read -0.8 once the meter counted every sample). No compressor on
306  the drums: superdough's is a Web Audio compressor per hit, whose automatic
307  makeup gain raised the drums' peak by 2.1 dB and loudness by 2.8 dB when
308  measured (2026-09-25).