Skip to content

fix(public): serve /favicon.ico from the canonical SVG so legacy clients stop 404-ing - #238

Merged
nish3451 merged 1 commit into
mainfrom
fix/favicon-ico-serve-2026-08-17
Aug 17, 2026
Merged

fix(public): serve /favicon.ico from the canonical SVG so legacy clients stop 404-ing#238
nish3451 merged 1 commit into
mainfrom
fix/favicon-ico-serve-2026-08-17

Conversation

@nish3451

Copy link
Copy Markdown
Collaborator

Fix

Item 017eb201fc — "[unreviewed-by-opus] No rel=icon link is served, so every page load fires a 404 /favicon.ico request while favicon.svg exists and is allow-listed".

Prior re-verify receipts (PRs #132, #182, #230 — 2026-08-12, 2026-08-14, 2026-08-15) closed the observed symptom on modern Chromium by adding to every served page, but the underlying request path /favicon.ico was still answered with HTTP 404 whenever any legacy / search-engine / screenshot client asked for it. This branch lands the source-side fix so the path is no longer 404-able on the live worker.

What changed

  • src/worker.js

    • PUBLIC_ASSET_PATHS adds "/favicon.ico" with a comment explaining why the legacy path needs an explicit allow-list entry.
    • A new branch ahead of the generic asset handler pulls the canonical /favicon.svg bytes via env.ASSETS.fetch(...) and re-serves them with Content-Type: image/x-icon and Cache-Control: public, max-age=31536000, immutable. Security headers continue to flow through withSecurityHeaders, matching every other served response.
  • scripts/check-site.mjs

    • The existing "Favicon (dogfood)" section adds two source-side guards so npm run check fails non-zero if either the allow-list entry or the image/x-icon content-type override is removed in a future refactor — the fallthrough back to 404 becomes a guarded regression, not a silent loss.
  • docs/evidence/favicon-ico-2026-08-17.md — receipt recording the fix and the local HTTP probe.

  • .lane/reports/fix-favicon-ico-2026-08-17.md — lane-1 closeout report.

Verification

  • node scripts/check-site.mjs → exit 0, "TinyStudio.io checks passed."
  • wrangler deploy --dry-run → exit 0, bindings registered cleanly.
  • wrangler dev --local --port 8791 + curl /favicon.ico → HTTP 200, Content-Type: image/x-icon, body SHA-256 = 998e43ad83f78adcd8a75fb37a87657ba2289b760470f42583c7fab166d9184c (matches public/favicon.svg).
  • HEAD, GET, and GET /favicon.ico?v=1 all return 200; POST correctly returns 404 (only GET/HEAD are supported on static asset paths).
  • All eight test suites stay green: test:headings (6), test:sitemap (7), test:product-contract (8), test:agent-worker (80), test:agent-ui (16), test:first-viewport-audience (4), test:narrow-viewport, test:narrow-viewport-pages, check:render-blocking.

What did not change

  • The seven served HTML pages each keep their single in ; modern browsers continue to use the canonical SVG, the new handler only fires for legacy clients.
  • The asset-bucket contract, the allow-list semantics for the other public paths, and every served-response security header.

…nts stop 404-ing

The /favicon.ico fallback path was 404-ing on every legacy / crawler /
screenshot request because the asset bucket only contains
public/favicon.svg and isAssetLikePath send the request to asset_not_found.
This branch:

- Adds /favicon.ico to PUBLIC_ASSET_PATHS and a dedicated branch in the
  worker handler that pulls the canonical /favicon.svg bytes via
  env.ASSETS and re-serves them with Content-Type: image/x-icon and
  Cache-Control: public, max-age=31536000, immutable.
- Adds two source-side guards in scripts/check-site.mjs so a future
  refactor that drops either the allow-list entry or the content-type
  override exits npm run check non-zero (the fallthrough back to 404
  becomes a guarded regression, not a silent loss).

The single <link rel="icon" href="/favicon.svg"> in every served page
is unchanged, so modern browsers continue to use the canonical SVG; the
new handler only fires for clients that ignore the <link> and fall
through to the well-known path.

Verification: npm run check exits 0, wrangler deploy --dry-run bundles
cleanly, all eight test suites stay green, and wrangler dev + curl on
the local port returns HTTP 200 with the canonical SVG bytes and
Content-Type: image/x-icon.

Receipt: docs/evidence/favicon-ico-2026-08-17.md
Lane report: .lane/reports/fix-favicon-ico-2026-08-17.md
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@nish3451, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Free

Run ID: 7c799a09-b7ae-4bbb-a8eb-17a5774239d8

📥 Commits

Reviewing files that changed from the base of the PR and between 83a5974 and fd75bb7.

📒 Files selected for processing (4)
  • .lane/reports/fix-favicon-ico-2026-08-17.md
  • docs/evidence/favicon-ico-2026-08-17.md
  • scripts/check-site.mjs
  • src/worker.js

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@nish3451
nish3451 merged commit 5ca6241 into main Aug 17, 2026
3 checks passed
nish3451 added a commit that referenced this pull request Aug 21, 2026
… current main and live (2026-08-20, lane 1) (#250)

Item 017eb201fc ("[unreviewed-by-opus] No rel=icon link is served, so
every page load fires a 404 /favicon.ico request while favicon.svg exists
and is allow-listed") is closed against current main and live. The code
fixes are already merged: #85/#113 added rel=icon links to all seven
served pages plus the CI guard, and #238 added the /favicon.ico legacy
fallback serving the canonical SVG bytes. This receipt re-verifies the
guarantee on head d0daea9 and the live site: npm run check and npm test
pass, all seven pages serve exactly one /favicon.svg rel=icon link with
zero /favicon.ico requests in real Chromium, and the /favicon.ico path
itself now returns 200 image/x-icon with byte-identical canonical bytes.

Co-authored-by: minimax-vps <minimax-vps@fleet.local>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
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.

1 participant