Skip to content

fix(#211): free articles wrongly paywalled + show app version in Settings#216

Merged
forcingfx merged 3 commits into
mainfrom
fix/issue-211-paywall-version
May 31, 2026
Merged

fix(#211): free articles wrongly paywalled + show app version in Settings#216
forcingfx merged 3 commits into
mainfrom
fix/issue-211-paywall-version

Conversation

@forcingfx

Copy link
Copy Markdown
Owner

Closes #211. Two distinct bugs, one commit each.

1. Articles incorrectly flagged as paywalled (c993ccd)

Root cause: extraction-store.fetchExtracted ran detectPaywall() against the raw page before extraction. The default detector substring-matches the entire markup, so industry-standard "Subscribe to continue" / "Already a subscriber?" CTAs in the nav/footer/newsletter chrome of every page (Wired, NYT, lttlabs, …) — free or gated — produced a false phrase-match verdict. The raw-page body-too-short rule mis-fired similarly.

Fix: Extract first. A substantial extraction (≥600 visible chars of extracted content) renders immediately and ignores page chrome. Paywall heuristics now run only as a fallback for thin/empty extraction, scoped to the extracted teaser, and body-too-short never overrides content we did extract (short free posts still render). HTTP gated status (401/402/403/451) stays a first-class signal.

Tests: two regression cases (full article wrapped in subscribe chrome → renders, no verdict; short free post → renders). Existing paywall suite (stub→prompt, 403→prompt, authorized retry) stays green; its baseline now models reality (anonymous fetch of a gated page yields no extraction).

2. Settings doesn't show the installed version + version drift (3f318d2)

Root cause: No UI surface read the version. Separately, the 0.10.0/0.11.0 releases never bumped package.json (still 0.9.0) — the single source for VITE_APP_VERSION (SPA) and inlined process.env.APP_VERSION (serverless) — so prod /api/health reported 0.9.0 while the changelog said v0.11.0.

Fix: getAppVersion() accessor + "FeedZero v{version}" in Settings → Help (and in the support diagnostic context). Bump package.json0.11.0 so the SPA display, /api/health, and the health-version smoke invariant agree. Committed api/*.ts bundles are regenerated by build:api at deploy, so no hand-edit needed.

Tests: help-tab.test.tsx asserts the version renders; existing tests/smoke/health-version.test.ts already enforces prod version == package.json version.

Verification

  • npx vitest run → 3735 passed, 35 skipped, 0 failed.
  • tsc --noEmit (TS 6.0.3, the pinned version) → clean.

⚠️ Follow-up for the maintainer: the /new-release flow must bump package.json (it was skipped for 0.10/0.11). Not auto-merging — yours to land.

🤖 Generated with Claude Code

**What** — Clicking "Full text" on freely-readable articles from many
sources (Wired, NYT, lttlabs, …) showed a "Paywalled article" box even
though the whole article was present.

**Why** — `fetchExtracted` ran `detectPaywall()` against the *raw page*
HTML *before* extraction. The default detector phrase-matches the entire
markup, so industry-standard "Subscribe to continue" / "Already a
subscriber?" CTAs that appear in the nav, footer, or newsletter chrome of
*every* page (free or gated) produced a false `phrase-match` verdict. The
`body-too-short` rule, measured on the raw page, similarly mis-fired.

**Fix** — Reorder to extract-first. A substantial extraction (≥600 visible
chars of *extracted* content) is now the definitive "this is readable"
signal and renders immediately, ignoring page chrome. Paywall heuristics
run only as a fallback for thin/empty extraction, scoped to the extracted
teaser (not the chrome), and a `body-too-short` verdict never overrides
content we did extract — so short free posts still render. HTTP gated
status (401/402/403/451) remains a first-class signal. Extracted the
shared cache-and-mark-available dance into `cacheExtracted()`.

**Prevention** — Two regression tests in extraction-store-paywall.test.ts:
a full readable article wrapped in subscribe chrome must render with no
verdict; a short free post with no gate phrases must render. The existing
paywall suite (stub → prompt, 403 → prompt, authorized retry) stays green;
its baseline now models reality (anonymous fetch of a gated page yields no
extraction).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented May 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
feedzero Ready Ready Preview, Comment May 31, 2026 6:22pm

github.sudoku and others added 2 commits May 30, 2026 23:15
**What** — The Settings menu never displayed the installed FeedZero
version, and the baked version had drifted: package.json was 0.9.0 while
the current release line is 0.11.0 (prod /api/health reported 0.9.0).

**Why** — No UI surface read the version. Separately, the 0.10.0 and
0.11.0 releases bumped the changelog/Atom feed but never bumped
package.json, the single source for both VITE_APP_VERSION (SPA) and the
inlined process.env.APP_VERSION (serverless) — so every build identified
itself as 0.9.0.

**Fix** — Add getAppVersion() (reads the build-time VITE_APP_VERSION,
"dev" fallback for non-Vite contexts like tests) and render
"FeedZero v{version}" in the Settings → Help tab, plus include it in the
support-email diagnostic context. Bump package.json to 0.11.0 so the SPA
display, /api/health, and the health-version smoke invariant all agree.
The committed api/*.ts bundles are regenerated by build:api at deploy, so
no hand-edit is needed there.

**Prevention** — help-tab.test.tsx asserts the version renders. The
existing tests/smoke/health-version.test.ts already enforces
prod /api/health == package.json version; this commit makes that the
correct number. Follow-up for the user: the /new-release flow must bump
package.json (it was skipped for 0.10/0.11).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@forcingfx forcingfx enabled auto-merge (squash) May 31, 2026 18:22
@forcingfx forcingfx merged commit 3ab8ffb into main May 31, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Articles incorrectly flagged as paywalled & settings menu doesn't display the installed version

1 participant