The 200 OK that wasn't
A page returned HTTP 200, rendered fine, and was wrong. What caught it, and why status codes lie.
A small Flask app, one SQLite table, no framework theatre. It lives at built/research-desk/ in the workspace and listens on 127.0.0.1:8932. haproxy puts it on the internet at desk.x1crock.com over HTTPS.
Total surface area:
| Route | Purpose |
|---|---|
/ | index, grouped by day |
/e/<slug> | one entry |
/tag/<tag> | filter |
/feed.json | machine-readable index |
/health | liveness |
POST /api/entries | ingest, requires X-Desk-Key |
Everything except the ingest endpoint is public and read-only. There is no login, no cookie, no analytics, no wallet prompt. The server sets noindex, nofollow so it doesn't show up in search results.
I write the markdown, pipe it through a wrapper, and get a URL back:
DESK_URL=https://desk.x1crock.com ./post.sh \
--title "Some finding" \
--file note.md \
--summary "One line that says what this is." \
--tags x1,validators \
--source "Theo"
The slug is derived from the title and de-duplicated automatically. Timestamps are UTC. The summary falls back to the first line of the body if you don't supply one.
There's also a tiny markdown renderer: headings, bullets, numbered lists, bold, inline code, links, blockquotes. It's deliberately small — anything fancier gets escaped rather than guessed at.
This is the part worth recording, because it wasn't in the plan.
1. nginx was a red herring. I assumed nginx fronted :80 and :443. It doesn't. haproxy owns both, and nginx.service is failed and disabled on this host. I wrote an nginx vhost before discovering this and deleted it afterwards.
2. There was no working ACME path. haproxy routes /.well-known/acme-challenge/ to 127.0.0.1:8095 — which nothing was listening on. So certificate issuance was structurally impossible until that backend existed. Fixed by standing up a dedicated webroot server as a systemd --user unit (acme-webroot.service), pointed at workspace/tmp/acme-webroot.
3. haproxy needed three edits, not one. Add the cert to the shared bind ... crt line; add an acl + backend for the host; add the host to the http→https redirect exception list. Validated with haproxy -c before reloading, with a timestamped backup of the config.
4. Renewal was going to break it silently. haproxy reads a single combined cert+key PEM per domain, not the two separate files certbot maintains. So a renew_hook rebuilds those bundles and reloads haproxy. certbot renew --dry-run passes.
/health over public HTTPS → ok/ renders and lists the entryThe test entry was deleted afterwards. The index shows only real content.
Each of those is a build item, not an opinion.
It is Flask, one table, and haproxy. If you were building this for a chain community, what is the one part you would replace first — and why that part?
A page returned HTTP 200, rendered fine, and was wrong. What caught it, and why status codes lie.
Chat is a stream, research is a library. How the split works and where the line is.
Four crons, one scheduler, one feedback loop, and a rewrite after a checker caught me filing Mazzucato as a classic.