Skip to content

Write engine: stop the converter destroying content, add unlisted drafts - #48

Merged
HumbleBee14 merged 1 commit into
mainfrom
feat/write-engine-parity
Aug 15, 2026
Merged

Write engine: stop the converter destroying content, add unlisted drafts#48
HumbleBee14 merged 1 commit into
mainfrom
feat/write-engine-parity

Conversation

@HumbleBee14

Copy link
Copy Markdown
Member

Brings the write engine up to parity with the fixes and features developed on the sibling site, adapted to this repo's schema (blogs only, summary/topicId/authors kept as-is). No configurable date — publish dates stay derived, not author-controlled.

Why

The converter turns anything it doesn't recognise into literal text, and the serializer then escapes its <. So an unhandled construct isn't ignored on the way in — it's destroyed on the way out. Posts here have always originated in the editor, which is why this stayed latent. The moment someone hand-edits an index.mdx (or an agent writes one), reopening and republishing eats content.

Round-trip fixes

FixWas
(?<!\\) on every inline delimiter\$4.00 … \$8.00 parsed as math — the escaping backslash is itself the non-space char the closing delimiter needs
<strong>/<b>, <em>/<i>, <s>/<del>, <code>, <u>survived as text, came back as visible &lt;strong&gt;
Colour spans → palette namesdropped
tags: [a, b] bare YAMLJSON.parse threw, post wouldn't open
<details>, <Gallery>, <Video>, self-closing <Figure>, local <Image>emitted by the serializer, unreadable by the converter
Soft breaks, paragraphs opening with a tagran into the following block
Stray-component warningsilent destruction

Divergence detection

index.mdx is what the site builds from, so where it and .write-source.json disagree, the markdown wins. Publishing regenerates index.mdx wholesale, so a sidecar left stale by an outside edit would silently revert it. The editor re-serialises the sidecar, compares bodies, and reloads from markdown with a notice when they differ.

Drafts

draft: true previously excluded a post from getStaticPaths — it didn't build at all. Now it builds and answers at its real URL, but is held out of every listing, the sitemap, RSS and search, and carries noindex. /drafts lists them (itself noindexed and out of the sitemap); each row and the post's own banner link into /write with the draft box unticked and the page scrolled to the actions.

Two deliberate behaviour changes

Both have updated test coverage — worth a look during review:

  1. Dollar amounts are now escaped on the way out. The old test asserted $5 and $10 passes through bare. That's safe in isolation, but $4-$8 has no space before the closing $, so it matches as math and the round-trip is unstable. Escaping makes it stable; rendered output is identical.
  2. cover, ogCard and draft frontmatter are read back instead of being reset to defaults on reopen.

I deliberately did not port the stricter colour handling from the sibling repo — free-form hex/rgb from pasted markup still works here, and its test is untouched.

Verification

  • npm test — 84 passed
  • astro check — 0 errors, 0 warnings
  • eslint --max-warnings 0 — clean
  • npm run build — clean
  • All 4 existing posts convert with no new warnings
  • 13 constructs round-tripped twice each, checking for escaping damage and idempotence
  • Draft behaviour verified end-to-end against a temporary probe post: built and reachable, noindex present, absent from sitemap / /blog / RSS / homepage / tags / pagefind, present on /drafts, publish deep-link correct, and published posts still in the sitemap

The converter turns anything it does not recognise into literal text, and the
serializer then escapes its `<` — so an unhandled construct is not ignored on
the way in, it is destroyed on the way out. Posts written here always came from
the editor, so this stayed latent; a hand-edited index.mdx triggers it.
Round-trip fixes:
- Escaped delimiters. Every inline pattern now carries `(?<!\\)`. Without it
`\$4.00 … \$8.00` matched as math, because the escaping backslash is itself
the non-space character the closing delimiter requires. escapeProse escapes
`$` for the same reason it escapes `*`, and unescapeProse reverses it.
- Inline HTML. <strong>/<b>, <em>/<i>, <s>/<del>, <code> and <u> now read back
as styles instead of surviving as text.
- Colour spans, read back to their palette names.
- Bare YAML flow lists — `tags: [a, b]` no longer fails JSON.parse.
- <details>, <Gallery>, <Video>, self-closing <Figure> and local <Image>, none
of which the converter could read even though the serializer emits them.
- Soft breaks and paragraphs opening with a tag.
- Anything still unrepresentable raises a named warning before publish.
Divergence detection: index.mdx is what the site builds from, so where it and
.write-source.json disagree the markdown wins. Publishing regenerates index.mdx
wholesale, so a sidecar left stale by an outside edit would silently revert it.
Drafts: `draft: true` now builds and answers at its real URL, but is held out
of every listing, the sitemap, RSS and search, and carries a noindex. /drafts
lists them; each row and the post itself link into /write with the box
unticked. Previously a draft did not build at all.
Two deliberate behaviour changes, both covered by updated tests: dollar amounts
are now escaped on the way out (`$4-$8` was otherwise unstable across a
round-trip), and cover/ogCard/draft frontmatter is read back rather than reset.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying mlsystems with Cloudflare Pages Cloudflare Pages

Latest commit:010dcfa
Status: ✅ Deploy successful!
Preview URL:https://c71abe64.mlsystems.pages.dev
Branch Preview URL:https://feat-write-engine-parity.mlsystems.pages.dev

View logs

@github-actions

Copy link
Copy Markdown

@HumbleBee14
HumbleBee14 merged commit b4c0ff1 into mainAug 15, 2026
2 checks passed
@HumbleBee14
HumbleBee14 deleted the feat/write-engine-parity branch August 15, 2026 02:35
@HumbleBee14
HumbleBee14 restored the feat/write-engine-parity branch August 15, 2026 02:47
@HumbleBee14
HumbleBee14 deleted the feat/write-engine-parity branch August 15, 2026 02:49
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HumbleBee14