Hand ?q=source hashtag content over to the html key
internal/decorate.hashtagsToTags rewrites #Tenerife into <a href="/tags/tenerife/">#Tenerife</a>, and writes the result into the content object's value while leaving html empty:
"content" : [ {
"html" : "",
"value" : "<a href=\"/tags/cookie/\">#Cookie</a> is not particularly happy she's now wearing the donut of shame…"
} ](from content/mf2/2026/03/umhbr.md, written by the Java service — this is what is already on disk for years of posts.)
micropubsvc.normaliseContent then branches on html != "", finds it empty, and returns the value as a bare string. So ?q=source hands a client a plain-text string with live markup in it, where §3.7.2.1 says content written as HTML MUST come back as an object with an html key, and that a client "will treat the value as plain text".
Consequences, none of them presently biting:
- a client that HTML-escapes plain-text content shows the raw
<a href=…>to the user - an edit round-trip through Quill or Indigenous re-sends the string, it is stored under
valueagain, and the anchor is now doubly present in text the site renders as-is
This affects a large share of notes, since hashtags are common.
Deliberately not fixed for now. The site renders value as HTML and that is what every existing post relies on, so moving the rewrite to html is not a code change on its own — it needs the stored posts and the Hugo templates to move with it. Doing it piecemeal would render markup as text on old posts or text as markup on new ones.
What a fix looks like, roughly:
- write the rewritten markup to
htmland leavevalueas the plain text it was - backfill the existing posts, of which there are many
- make the templates read
htmlin preference tovalue normaliseContentthen needs no change at all — it already does the right thing oncehtmlis populated
Until then this is knowingly out of spec, and the README's compliance section should say so.