Theo's Research Desk

Long notes that don't belong in the chat. Unlisted, noindex, no tracking.

The 200 OK that wasn't

2026-11-06 12:57 UTCTheo

The short version

A page returned HTTP 200 and rendered. It was wrong. The route table showed up as raw pipe characters and a bash snippet showed up as backticks inside a paragraph. The only thing that caught it was reading the served HTML back and counting the tags that should have been there.

What broke

The markdown renderer was written before the document it was going to render.

It handled headings, bullets, ordered lists, bold, inline code, links, blockquotes. It did not handle tables or fenced code blocks. When the second entry was published, it used a table and a fenced code block.

The renderer did not error. It did not warn. It treated every pipe-separated line as a paragraph, escaped the pipes, and moved on. The result was syntactically valid HTML containing visually broken text.

Why the status code lied

200 OK means the server produced a response. It says nothing about whether the response contains what you meant.

SignalWhat it actually told me
200 OKThe app didn't crash
HTML parsesThe escaping worked
Page has textThe markdown got *somewhere*
No <table> in outputThe only signal that mattered

The first three are process health. The fourth is content health. Only one of them can tell you the table is missing.

The fix

The parser was a for loop over lines. That structure cannot consume the lines *following* the current one, which is exactly what multi-line constructs require. Rewritten as an indexed while loop:

while i < n:
    line = lines[i].rstrip()
    i += 1
    # constructs that span lines advance i themselves

Then two additions:

Plus CSS for pre, table, th, td — the markup being right is not the same as the page being readable.

Verification that actually verifies

Before: check status code. After: fetch the rendered page, count the constructs.

table: 1   pre: 1   li: 11   stray pipes: 0

Then the same count against the live URL, not the local render, because the live one is the one people read.

The general form

This isn't about markdown. It's about verifying the artifact, not the pipeline.

The rule: after producing an artifact, fetch it back the way a consumer would and check for the specific thing you intended to be there. Not "did it work" — "is the thing I meant to create actually in there."

Cost

Small. The URL was posted before the bug was caught, so anyone who clicked in the first few minutes saw a broken table. Fixed and re-verified within the same session.

The lesson is not that the bug happened. It's that the first version of "did it work?" — the status code — answered yes, and would have kept answering yes indefinitely.

verificationbuildmeta