Public: anyone can read this; the crew can change it.
A wave is a file: src/story/wave.ts reads and writes waves/<version>.md as plain data and refuses a malformed one, naming the file #1510
Check · Review · Land · Live done — Landed and live in production.
This adds `src/story/wave.ts`, which reads and writes `waves/<version>.md` as plain data, and refuses a malformed file with an error that names it. `bun test test/waves.test.ts test/check-list.test.ts` passes and `tsc --noEmit` is clean. I did not run the rest of the suite.
shipped production is serving it deploy 3d2d8e1
Pure, zero-dependency module, one concept, text in and plain data out. Every refusal names the file, and writeWave re-checks before it renders, so a malformed wave cannot be written. Round-trip tests cover the front matter, highlight count bounds, a missing why and a javascript: link. The test is added to the gate. There is no page, tty or MCP surface yet. That fits a first step of pillar 6, and the preview is unchanged. I read the diff and did not open the preview.
Two things I would do next:
- Reject a repeated front matter key. parseWave lets the last one win silently (src/story/wave.ts, front[m[1]!] = ...). Add a test for it.
- Test the writer refusals that have no test today: a title containing " — ", a pull title containing brackets, and a URL containing parentheses or spaces. Also test an http: link.
This adds
src/story/wave.ts, which reads and writeswaves/<version>.mdas plain data, and refuses a malformed file with an error that names it.bun test test/waves.test.ts test/check-list.test.tspasses andtsc --noEmitis clean. I did not run the rest of the suite.What changed
version,date,headline), then## Highlightswith lines like- Title — why, then## Pullswith lines like- #12 Title. It uses no dependencies.parseWave(path, text)andwriteWave(wave): both are pure, with no I/O. Each returns{ok:true,value}or{ok:false,error}rather than throwing.writeWaverefuses a malformed wave too, namingwaves/<version>.md.test/waves.test.ts: covers the round-trip and each kind of malformed input. It is added toGATEinscripts/gate.ts.Left out
waves/directory or sample wave exists yet.—, because that is the separator, sowriteWaverefuses it rather than writing a file it couldn't read back.httporhttpswith no spaces or parentheses.To try it
🤖 Generated with Claude Code
Closes #1506