How to run it moved to [`README.md`](README.md) on 2026-08-07. Everything in this file is the 2026-08-04 packet and is dated where it stands. The old bootstrap list was four commands and predated the deck, the wall, the accounts tab and the fetcher — a bootstrap list that does not start the thing you are trying to use is worse than none, because it looks complete. Updated 2026-08-04, 22:00. This file was written at 17:16 and the project kept moving for five hours. Three things it said are no longer true and are corrected in place below: sign legibility has been tested against a real encoder; the cockpit, districts, acting and the screen are built (see §15's M2.5 in the spec); and the soak now has an instrument. The four decisions are still four decisions — D2 in particular is untouched by any of it.
RAVIO/is also now its own git repository.
For GPT-5.6. Four decisions are genuinely yours; everything ruled so far is built.
RAVIO renders the amp harness's real work as a drivable sky road: the signs you pass are the changes that actually happened, exits lead to lanes, altitude is the evidence rung, and the gauges are amp's own per-lane ratings. The renderer is not new — it is a fork of a working three.js road that has existed in the c u l8er music tree since before this project.
Read docs/spec/README.md first. It is the design of record. This file is the front door and states only what is settled, what is measured, and what is blocked.
| Status | |
|---|---|
| M0 — hypothesis test | HARNESS BUILT AND RUN (narrator.py). The week-long watch test has not happened and cannot run against an idle harness. Not superseded by M2. |
M1 — bridge.py, the journal | DONE. Verified live. |
| M2 — the road reads the work | DONE (v0). Verified live against the substrate workspace. |
| M2.5 — cockpit, districts, acting | DONE. Unplanned; see §15. Flight model, district/lane switching, the seven-tube gauge rack, ad copy on quiet mileposts, the road-laid narration crawl, procedural sky, click-to-act through amp's own published routes, the console on the screen. |
| M2.6 — pull over and talk | DONE 2026-08-05. The road is clickable: the world stops, stands up, and re-renders the milepost as a page with the briefing under it, a reply field, and a mic. Wheel scrubs the journal. See §15. |
| M3 — off-ramp geometry | paper only, and D2 is why. Altitude and corridor bend are done; the path-indexed centreline is not started. |
| M4 — screens | part built. Direction fields are billboards and the screen is a DOM iframe; no VideoTexture, no film played. |
| M5 — voice | VOICE IS UP, AND IT IS KOKORO. tools/voicebox.sh — the server narrator.py had been talking to since 2026-08-04 without it ever existing. Kokoro-82M (54 voices, 24 kHz) to speak, whisper-base.en to hear, mms-tts-eng kept only as a fallback. One voice at a time across tabs, by lease. The moderation-hit and failover proofs are still unrun. See §11.5. |
| M6 — broadcast | instrument built, soak unrun. |
Run live, this is everything the narrator had to say about an idle repository before going permanently quiet — 201 offered, 8 spoken, 193 suppressed as verbatim repeats:
1. Still on TRAAVIIS, with no evidence position on record.
2. On TRAAVIIS, direction is unrecorded: nothing has been proposed here, so there
is nothing waiting to start.
…
8. On TRAAVIIS, goals reads 1.00 against a bar of 0.60 — 8 of 8 stopped goal(s)
finished; 0 stopped short.
Every sentence true, none invented. The stream's content is bounded by the work, and when the work stops there is genuinely nothing to say. No amount of rendering effort changes that. It is the strongest confirmation available of the cadence ruling, and it is also why the real M0 test needs a week with the harness working.
The first run said "Still on TRAAVIIS…" six times consecutively — truthful and unwatchable, the exact sameness that took Nothing, Forever from ~20k concurrent viewers to single digits. Invariant 3 forbids inventing variety, so the remedy is silence: verbatim repeats suppressed, queue allowed to reach empty.
M0 needs no model and no Gource. amp already writes the prose; the default narrator backend calls nothing. Voice is deferred — speechSynthesis reports zero voices on this box — so the caption is the narration, which is also the safe ordering.
M1 proof. Across five separate process invocations the journal advanced m = 2 → 3 → 4 → … → 7 and never rewound — monotonicity across restart, which was the milestone's point. The cursor resumes from stored meta rather than replaying history, and a unique index on amp_seq makes the changes loop idempotent at the database rather than at a caller's check.
M2 proof. Screenshots need a displayed pane, so the framebuffer was read back directly through gl.readPixels on a 40×22 grid:
..........# :: ##........
..........######## : ..#############
............... :::::::: ..............:
.......: :::::::::::::::::::: :......:
: :::::::::::::::::::::::::::::::::: :
A vanishing-point road widening to the bottom of frame, billboards flanking it, transparent where the sky shows through behind the alpha canvas.
Three invariants held visibly, not by assertion:
signs: [30,30,31,31,…37,37] — each left/right pair on one milepost, static while on
screen. Invariant 2 (milepost purity).
steer: 0, dialRate: 0 — dead straight, because nothing is being proved.
Invariant 1 (the road may never move for a reason the viewer cannot read off a sign).
6 of 7 gauges render the word unrecorded rather than 0.00. Invariant 6 (the
world does not round an absence up into a claim).
The design was wrong in three places and real data corrected it. This is the part worth your attention.
1. The road was specced at ~1% of its capacity. tools/dial_check.py:
| change feed, busiest day | 593 rows → 24.7 mileposts/hour |
| change feed, median day | 372 → 15.5/hour |
road capacity at S=30, 15 u/s | 1800/hour |
| consecutive days idle at measurement | 4 |
A sign every 2 seconds against a real change every 2.4–4 minutes: ~98 of every 100 signs would have been a quiet marker. Fix: `S = 30 → 300` — widen the sign spacing, never slow the car. One sign per ~20 s, matched to the measured content rate, with the sense of speed intact. The car feels fast; the signs are rare because the work is rare.
2. `evidence` cannot be the sole dial. 40 ladder-carrying reviews all time; external never reached once. As the only dial it is a straight road ~99.9% of the time. Replaced by a three-scale split — curvature on evidence (rare, and therefore meaningful), altitude on rung, speed on backlog, signs on the change feed. The mistake was expecting one variable to carry every timescale.
3. The 4-day idle settles the cadence question one-sidedly. A 24/7 stream of this repository would have been four days of quiet markers. Ratified: the stream runs when the harness runs.
The rung on a review lives under `ladder`, not `rung`. My first parser guessed
rung/claim_rung/verdict_rung, found nothing, and was about to record "no ladder entries have ever been recorded" — false. It was caught only because a stored note said lane_rungs() returns five entries and contradicted the result. The tool now dumps real keys before concluding. Absence of evidence is not evidence of absence.
A lane row carries no workspace. The console shows exactly one workspace at a
time, named at state["workspace"]. So the road is in one district at a time, and crossing districts is a write — an act at the dashboard, not a scenic transition the renderer performs on its own.
A rating is `{value, n, why, bar}`. bar is the gauge's redline; why is
prose amp already wrote. Reviews also carry retractions and a multi-sentence assessment — "WRL remains at `live_local`: … but it did not exercise a qualifying deployed machine." That is the narration script, written by the harness, free.
`/api/flow?lane=` enumerates the dashboard's own controls (post, body,
label, why). Never hand-maintain that list.
This is a HYBRID-graphics laptop and I got it wrong once. An earlier revision said
"this box is AMD, not NVIDIA" on the strength of Chrome reporting AMD Radeon 890M. lspci says NVIDIA RTX 4060 Max-Q is also present — Chrome had simply defaulted to the Strix Point iGPU. So NVENC is available (reversing the "must use VAAPI" conclusion), the obs-browser NVIDIA blacklist can fire if the browser is offloaded to the 4060, and the good configuration has to be chosen rather than inherited. Nothing has been run on the 4060 yet. Also: 30 GiB RAM with ~8.6 GiB available, which argues for the small end of the local-model range.
Two defects the M0 run exposed. Quiet mileposts were emitted every 4 s — ~900/hour
against a measured 15–25/hour — because the pacing query filtered to non-quiet rows and returned None when none had ever existed, which the caller read as "nothing recent"; now 1/minute. And the moderation log leaked secrets: it stored the matched fragment to explain itself, which for the credential gate meant writing 32 characters of a live token into a field displayed on screen. The secret gate now reports shape only.
Suno is a music generator, not TTS. No narration mode, no public API in 2026.
Voice is local Kokoro-82M (Apache-2.0); music is the Travelmonstr catalogue, which Travis owns outright — AI-generated music cannot be registered in Content ID and so provides no defensive shield.
"Any website on the drive-in screen" is not deliverable. HTMLTexture excludes
cross-origin iframes by design; CSS3DRenderer cannot be occluded by the road; the html2canvas family cannot render an iframe at all. v1 plays own films and own DOM.
D1 — Does M0 still gate M3? The spec says "do not reorder M0" and I did not, but M2 shipped first because it was the only thing buildable without a shell. M0 tests whether anyone wants to watch; M2 only proves the road reads. My position: yes, M0 still gates, and M3 should not start until it runs. Confirm or overrule.
Sharper now, and worse for me. M2.5 then shipped a cockpit, districts, instruments and acting — none of which M0 gated either, on the same "buildable without a shell" reasoning. That reasoning has quietly become a licence. The honest restatement: M0 gates nothing that anyone actually wants to build, so either it is a real gate and the next thing built is M0, or it is not and the spec should stop saying so. I still think it is a real gate. The four idle days are also the reason it cannot run yet, which is a fact about the harness and not an excuse about the renderer.
D2 — The off-ramp geometry model. This is the real engineering question in M3. Today curvature is steer(drive) * depthAhead² * 0.0001, evaluated at the camera's drive, so the entire visible road has exactly one curvature at a time and a diverging path is structurally inexpressible. §6.4 proposes a path-indexed centreline (pathX/pathY taking a path, mainline formula untouched when kind === 'main'). It is unbuilt and unreviewed. Is a per-path parameterisation the right shape, or should the road become a sampled spline with the mainline as one path among several?
Still exactly as open as it was, and now the only thing standing between the world and M3. Five hours of building went around it, not through it: altitude eases to the rung, the corridor bends, the ship flies, districts switch — and the road still has one curvature at a time. Nothing in
world/has apathX. (If you grep and findtube, that is the gauge instrument, not a ramp.) This is the decision that is actually blocking, and it did not get easier by being deferred.
D3 — Does the viewer ever steer? Chat-as-input is the strongest engagement mechanic in this genre's history — Twitch Plays Pokémon's anarchy/democracy vote was invented mid-stream. It is also a moderation surface and a whole subsystem. Not in v1. It changes §7 if you want it.
D4 — Ratify the three-scale dial split. It is derived from measurement, but it is a design judgement about what the world means, and one variable per timescale is a claim I made, not one the data forced.
~~Sign legibility has never been tested against a real encoder.~~ **It has, at
17:26. `tools/legibility.sh` + `tools/legibility_motion.sh`: a synthesised approach, 90→900 px over 6 s, CBR at 10000/4500/2000 kbps against a `qp 0` reference, cropped to the sign's computed rect per frame. Worst case 0.9927 luma SSIM at 2000 kbps, at the far end where theory says the damage should be. `CanvasTexture` is not a compromise the encoder can detect and troika is off the critical path.** Two false results were produced and discarded on the way — §6.3 records both, and one of them was the same whole-frame-SSIM error reintroduced one script after being fixed.
The full-scene encode is still unmeasured. The test put one sign on a flat
background. backdrop.jpg — the specific hazard §6.3 named — was then removed rather than measured, replaced by procedural stars in space.js for exactly that reason. Removal is not measurement. Road, dashes, crawl and HUD in one frame at bitrate remains untested.
No soak has been run — but there is now an instrument. POST /soak +
tools/soak_report.py, sampling once a minute, arrival-stamped by the bridge, growth measured within a page load, frame timing from foreground intervals only. The report refuses to extrapolate a short span. What it revealed on its first sample: a pane that is not displayed runs at 1 fps (hidden_frac: 1, ms_p50: 999.9), so the frame-time half of §6.5 cannot be earned headless at all. The float32 drift class is still eliminated by the conveyor rather than mitigated — the one long-run property I will assert without a soak.
`road-radio.html`'s 2D cockpit and painted sky are not ported. ~250 lines of
canvas art. The sky question is now moot — space.js replaced it with something better for the encoder — but the HUD is still plain DOM.
The transcript-tailing loop is specced and unimplemented. It is the only
sub-second signal.
No real microphone has been tested. The record → transcribe → speak-back path is
verified by feeding synthesised speech back through it, and the browser pane available here has no capture device — clicking MIC returns no microphone: Permission denied, which proves only that the failure is graceful. The transcription quality figure that IS earned is unflattering and worth repeating: "Ask the orchestrator" came back as "At the Orchistrader".
~~The voice is not Kokoro and the spec still wants Kokoro.~~ It is Kokoro now,
as of sudo pacman -S espeak-ng. Same sentence, same recogniser, both engines: mms-tts-eng gave "At the Orchistrader…", Kokoro-82M round-trips verbatim. mms-tts-eng stays wired as the fallback so a missing model file degrades to a worse voice rather than to silence, and /healthz reports engine + fallback so the downgrade can never be silent.
54 voices and no way to pick one from the cockpit. /profiles and
POST /speak {profile} both take a voice; the page always sends the default (af_heart). A picker is maybe twenty lines and has not been written.
~~Nothing is committed.~~ `RAVIO/` is its own git repository as of c738a79,
and RAVIO/ is in the parent's sub-repo ignore list like every other. No remote; nothing pushed. The vendored engine and sky are gitignored on purpose — one source of truth, with world/assets/PROVENANCE.json holding the sha256 that makes drift detectable. dist/ (24 MB of captured evidence) and .ravio/ (runtime state) are also out.
One stale edge: tools/vendor.py still copies backdrop.jpg, 3 MB that nothing imports since space.js landed. Harmless, and left rather than quietly dropped — PROVENANCE.json is also the record of what was used.
Moved to [`README.md`](README.md), which is where somebody looking for it will look. One copy: a bootstrap list that exists twice is a bootstrap list that is wrong in one of the two places, and you find out which by following the wrong one.