fix(reader): the archive banner was ~100% false — gate on the hash#186
Merged
Conversation
shouldOfferArchive compared raw HTML strings, and the two sides are different substrates: the capture is Readability innerHTML (wrapped in <div id="readability-page-1">), the relay side is markdownToHtml(md). For any multi-paragraph article — every real one — they cannot match: markdownToHtml joins paragraphs with "\n\n", Readability emits "</p><p>". Neither the equality guard nor the containment guard could fire, and 'always' (the default) probes unconditionally, so the banner fired on every published article, every visit, carrying no information. Stated precisely: containment is not unreachable in principle. A single-paragraph body IS a clean substring of its wrapper, so the guard suppressed correctly there. Short pieces behaved; real articles did not. The tests pin both halves, with the relay fixture taken verbatim from real markdownToHtml output. Gate on the canonical 13.4 hash, which was already correct on both sides and never consulted — the published `x` tag (_articleHash), the archive row's articleHash, and state.articleHash agree by construction. The gate only ever SUPPRESSES: equal hashes ⇒ same content ⇒ nothing to offer, in any mode. A missing hash or a real difference falls through to the prior heuristics untouched, so 'richer' stays conservative. The decision moves to reader/archive-banner.js (pure — index.js is not importable from tests). checkArchiveAvailability now computes the current hash itself when state.articleHash has not landed: it is filled by an async IIFE at load while the probe runs on a 100ms timer, and silently degrading to the unsound body compare is exactly the bug. An edited article leaves the hash null and the body heuristics answer, as before. Does not address the markdown→HTML→markdown escape doubling that mints a new x tag on a Load-archive round trip (fixed for PDFs only, 2026-07-08). No wire-format change. 1739 tests green; lint 0 errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bryanmatthewsimonson
force-pushed
the
claude/archive-banner-hash
branch
from
July 17, 2026 06:46
84d0c55 to
5e6d71c
Compare
This was referenced Jul 17, 2026
bryanmatthewsimonson
changed the base branch from
claude/archive-identity-check
to
main
July 18, 2026 05:14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #185 (base:
claude/archive-identity-check). Fixes: "Major bugs are experienced daily by me in the content comparisons... very misleading banners so frequent that I ignore them."You were right to ignore them. The banner wasn't mistuned — it could not have worked.
Root cause
shouldOfferArchivecompared raw HTML strings, and the two sides are different substrates:article.content— ReadabilityinnerHTML, wrapped in<div id="readability-page-1">markdownToHtml(markdown), rebuilt from the eventFor any multi-paragraph article — every real one — these cannot match:
markdownToHtmljoins paragraphs with\n\nwhile Readability emits</p><p>with no separator. So neither the equality guard nor the containment guard could fire, and'always'(the default) probes unconditionally. Every published article, every visit, forever. Once a banner is always on, it's off.One correction to how this was first described to you. I said both guards were "structurally unreachable." That's too strong, and the test caught me: a single-paragraph body has no
\n\nto introduce, so it is a clean substring of its wrapper and the containment guard suppressed correctly. Short pieces behaved; real articles didn't. That asymmetry is why the flood looked erratic rather than total. Both halves are now pinned, with the relay fixture taken verbatim from realmarkdownToHtmloutput rather than hand-written.The fix
Gate on the canonical 13.4 hash — which was already correct on both sides and simply never consulted. The published
xtag (read back as_articleHash), the archive row'sarticleHash, andstate.articleHashagree by construction.The gate only ever suppresses: equal hashes ⇒ same canonical content ⇒ nothing to offer, in any mode. A missing hash (older rows, pre-13.4 events) or a genuine difference falls through to the prior heuristics untouched, so
'richer'stays exactly as conservative as it was.Two things fell out of doing it properly:
reader/archive-banner.js— pure, so it can be tested (index.jsisn't importable from tests; this matches howfindings-section.js/lens-section.jsare already factored).checkArchiveAvailabilitynow computes the current hash itself whenstate.articleHashhasn't landed. It's filled by an async IIFE at load while the probe runs on a 100ms timer — the probe can win that race, and silently degrading to the unsound body compare is precisely the bug. An edited article leaves the hash null and lets the body heuristics answer, as before.Not fixed here
The markdown→HTML→markdown escape doubling that mints a new
xtag on a Load-archive round trip — already fixed for the PDF path only (JOURNAL 2026-07-08). Until that lands, a hash difference after a round trip may be an artifact rather than a real edit. That's the third of the four archive bugs and wants its own PR.Verification
npm test— 1739 pass, 0 failnpm run build— clean ·npm run lint— 0 errorsOnce this lands you can put Archive banner back to
always— it will finally mean something.🤖 Generated with Claude Code