Series seed

The first thing I built wasn't the editor

Before any of it was visible, one question: can a post survive being opened and saved?

6 min read

On the 19th of September I didn’t build an editor. I wrote a throwaway script that opened all forty posts on this site and saved them again without changing anything, then compared the before and after.

That sounds like a strange place to start. It isn’t, though. The thing I was about to build sits between me and everything I’ve written here, back to a post from 2018. If it can quietly reformat a post while I’m editing a different paragraph, I wouldn’t find out on the day. I’d find out months later, looking at an old note, wondering why the spacing went strange and whether I did that or something did it for me.

So the first question wasn’t what the editor should look like. It was much smaller. Open a post, save it, is it still the same file.

I assumed it would be. Markdown goes in, markdown comes out. The library ecosystem for this is old and well travelled, remark and mdast and all of it, and I was mostly running the check to tick it off.

files 40 ok 35 bad 5

Five of them came back different.

The content was never clean

Nothing was wrong with the library. The posts were just messier than I remembered writing them.

Four of the live notes, August, September, October and November, start with a blank line before the opening ---. So every piece of code that looks for frontmatter at the very top of the file finds nothing at the very top of the file. I have no memory of doing that. It was probably a paste, four times, over four months.

Then the yaml. Re-serialising the frontmatter gave me twenty nine files identical, six where a flow list came back as a block list, and one that wouldn’t parse at all.

tags: ["blog", "portfolio"] goes in. This comes out:

tags:
  - blog
  - portfolio

Same data. Different file. Multiply that by every post I open in a week.

The one that wouldn’t parse was blogspot-the-first-patch.mdx. Part one of the first series I wrote here. It breaks because of this:

excerpt: "It began with curiosity and a blank page.
A small corner of the web, stitched together with wonder and borrowed code.
The start of a lifelong urge to make, share, and shape what lives online."

Three lines inside one quoted string. I wrote it that way because it reads like that on the series page and I wanted to see the line breaks while I was writing it. It’s the most deliberately written thing in any of my frontmatter, and it’s the one file that made the parser give up.

There’s something a bit funny about that. The bits I fussed over are the bits that break the machine.

And then the wikilinks. @portaljs/remark-wiki-link, the plugin this site uses to turn [[something]] into a link, threw on the way out:

Cannot read properties of undefined (reading 'data')

I wrote it down as D6, worked around it inside the editor’s own pipeline, and moved on. Keep that error in mind. It comes back.

What the failure actually changed

If I’d skipped the check and built on the assumption, the editor would have worked. It would have opened posts, saved posts, and quietly rewritten spacing and frontmatter across the whole site as I went. Every file I touched would have come back subtly different from every file I hadn’t. I’d have noticed eventually. Probably in a diff, probably annoyed, probably months in.

So the design changed before there was anything to design. Instead of parse the whole post, model it, render it back out, the rule became: only re-render the block I actually edited. Everything else gets written back from its original source text, byte for byte. The frontmatter is patched surgically, the one key I changed, leaving the rest of the file’s formatting alone, including the three line excerpt that no parser is happy about.

It’s a less elegant design. There’s a whole layer whose only job is to remember what the original looked like so it can refuse to touch it. But it means the blast radius of a save is the paragraph I was typing in, and nothing else.

[? I’m fairly sure this is the point where you decided the thing was worth building properly rather than hacking together. Is that right, or was that later?]

The other half of the day

I should say how this actually got written, because it’s half the story of this series.

I didn’t write the parser. I wrote the plan for it, and the plan is the part that took the time: which files, what each function had to do, and a list of acceptance criteria specific enough to check off a diff. Then Codex implemented it, and I reviewed what came back against that list.

The bit I didn’t expect is the step in between. Before writing any code, Codex reads the plan against the actual repo and reports where the plan is wrong. On this first phase it came back with six mismatches and seven blocking questions, every one of them answerable from the repo, and every one of them mine. Things I’d assumed about my own site that weren’t true.

[GAP: how did that first read pass feel? Useful, or irritating to be told your plan is wrong before anything’s been built? I don’t want to guess at this.]

Even then it wasn’t clean. The test I’d written into the plan, the exact code, didn’t typecheck. Two new errors from tsc, both in my block, both my fault. Which is a slightly humbling way to learn that writing the test in the plan and writing a test that runs are different skills.

Where it landed

By the end of the day there was no editor. No canvas, no toolbar, nothing to look at. What there was:

  • every post on the site opening and saving byte-identical
  • the frontmatter patcher leaving everything it wasn’t asked to change
  • cards for the eighteen components I actually use in posts, and raw passthrough for anything it didn’t recognise
  • a test that runs the whole of src/content through the round trip, one case per post

That last one is still running today, and every post I’ve written since has quietly become another test case. Including this one. If this piece can’t survive the editor it’s about, the suite goes red, which feels like the correct amount of pressure.

Next part is the other decision from that day, and the stranger one. The editor only exists when the dev server is running. There is no login, because there is no deployed thing to log in to.

seed maturity Seed — this note will change as the strip does