From 24f9740d9717e5efa4d6688984df57fdee4f3442 Mon Sep 17 00:00:00 2001 From: biosias Date: Sat, 12 Sep 2026 16:23:26 +0200 Subject: [PATCH] Fix bugs and robustness gaps found in a full code review (AI) Real bugs: - loadArticle()/loadAuthorView() had no stale-render guard (unlike loadArticleList()/loadSearch()) -- a slower, superseded request could overwrite a newer one's render. Both now capture and check a generation snapshot. - #post/... links interpolated article.hash (raw, unencoded "author/slug") directly, but router.js unconditionally decodeURIComponent()s each segment when parsing -- would throw (silently swallowed) for any author/slug containing a literal "%" or other reserved character. Links now go through a new postHref() helper that encodes each segment individually. - A startup failure replaced the entire document.body, which would wipe out a host site's own page content when cmjs is embedded alongside it. Now scoped to cmjs's own mount points when at least one exists. - hydrateArticle() had no in-flight de-duplication -- two concurrent callers for the same not-yet-hydrated stub (e.g. a page's hydration racing the next page's prefetch) could each fire a duplicate fetch. Now tracked via a WeakMap keyed by the stub. - Leftover "expedition blog"/"expedition year" wording missed by the earlier astronomy-club genericization pass (that pass's grep didn't cover the English word "expedition"). Robustness gaps: - cache.js no longer permanently disables the whole IndexedDB cache after a single failed transaction -- only openDb() itself failing does that now. - Listing mtimes are normalized to minute precision at the one point they enter the system, so cache comparisons stay consistent even if a server flips between JSON and HTML-fallback autoindex. - The root author-listing fetch failing outright is now treated like "every author's listing failed" (a new rootFailed crawl stat) instead of surfacing a generic, less-specific error. - router.js now checks both required mount points exist right after startup and fails with a clear, catchable message instead of a bare TypeError the first time showListView()/showArticleView() runs. - The article view's "back" link now returns to whatever list/search/ filter page the user actually came from (tracked via lastListHash) instead of always resetting to page 1 of everything. - filterLabel() now checks filter.type === 'category' explicitly instead of falling through to it as the default case. - Author-name filtering is now case-sensitive, matching how author paths/profile lookups are looked up everywhere else. - Documented (in code comments and a new README note) that article/bio Markdown renders via marked.js with no HTML-sanitization pass -- only trusted authors should be adding content. Minor: - Extracted applyArticleMetaFields() to share the date/reading-time/ category-badge logic between renderCard() and loadArticle() instead of duplicating it. - Clarified resolveMediaUrl()'s WordPress-migration special case as legacy compatibility, not a general-purpose feature. - frontmatter.js no longer requires a trailing newline after the closing "---" -- a file that's nothing but frontmatter now parses instead of falling through to "no frontmatter at all". Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01AXSVPS3UmmASiiprPfcnUd --- README.md | 4 ++ demo/css/reset.css | 4 +- js/cache.js | 22 ++++++-- js/discovery.js | 70 +++++++++++++++++++++---- js/frontmatter.js | 7 ++- js/router.js | 34 ++++++++++-- js/views.js | 125 +++++++++++++++++++++++++++++++++------------ 7 files changed, 210 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 4543dd5..be92382 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,10 @@ metadata never requires fetching anything beyond the directory listing that alre no further per-article request at all, which is what makes the "Article discovery & caching" section below possible. +> **A note on trust:** article and author-bio Markdown is rendered directly via marked.js with no +> HTML-sanitization pass — anyone who can write a `.md` file here can include raw HTML, including +> `