Skip to content

fix(public): serve a real 404 page so unknown URLs stop returning the homepage - #34

Merged
nish3451 merged 2 commits into
mainfrom
fix/public-soft-404
Aug 9, 2026
Merged

fix(public): serve a real 404 page so unknown URLs stop returning the homepage#34
nish3451 merged 2 commits into
mainfrom
fix/public-soft-404

Conversation

@nish3451

@nish3451 nish3451 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

What

Adds a top-level public/404.html so unknown URLs on tinystudio.in stop soft-404ing as the homepage.

Root cause

Verified live: https://tinystudio.in/this-url-does-not-exist-xyz returns HTTP 200 with the full homepage. The site is served by Cloudflare Pages, and per Cloudflare's serving docs:

If your project does not include a top-level 404.html file, Pages assumes that you are deploying a single-page application … Pages' default single-page application behavior matches all incoming paths to the root (/).

The project had no 404.html, so Pages was in implicit SPA fallback mode: every unmatched route served index.html with status 200. Adding a top-level 404.html switches Pages to its not-found behavior — unmatched routes now return HTTP 404 with the custom page.

Changes

  • public/404.html (new): a real "Page not found" page styled with the site's shared header/footer and hero-card pattern. One H1, noindex meta as a belt-and-suspenders guard, canonical omitted, and escape links to real destinations (home, support, contact, Promptly, Drishti). All links resolve to existing pages and follow the repo's WCAG 2.2 tap-target and heading conventions.
  • scripts/prepare-static-site-bundle.mjs: 404.html added to the prepared htmlFiles list so it gets the same local-asset normalization and asset assertions as every other page.
  • scripts/test-public-soft-404.mjs (new): regression test asserting the 404 page exists, is not a homepage clone (title/canonical/H1/noindex), all internal links resolve, and it keeps the shared header/footer chrome. Wired into npm run ci and npm test.
  • scripts/test-public-link-targets.mjs: 404.html added to the pages that carry the shared header/footer.

Verification

  • npm run ci passes (exit 0, 0 failures) — includes the new soft-404 test (19 checks).
  • node --check on all modified scripts; site:prepare is idempotent on the new page (no unintended diffs).
  • Live behavior after deploy should change from 200 + homepage to 404 + custom page for unknown URLs (e.g. https://tinystudio.in/this-url-does-not-exist-xyz).

Notes

No dashboard/host configuration changes are required — Cloudflare Pages honors a top-level 404.html automatically. No sitemap, robots, or llms.txt changes: the 404 page is a system page and must not be listed.

@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.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Aug 9, 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: 19 minutes

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: Pro Plus

Run ID: ac732ee5-ad4e-4858-b37a-143214276a11

📥 Commits

Reviewing files that changed from the base of the PR and between a57ab1a and 3fc2d15.

📒 Files selected for processing (5)
  • package.json
  • public/404.html
  • scripts/prepare-static-site-bundle.mjs
  • scripts/test-public-link-targets.mjs
  • scripts/test-public-soft-404.mjs

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

@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.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@nish3451
nish3451 merged commit 4499dd4 into main Aug 9, 2026
3 checks passed
nish3451 added a commit that referenced this pull request Aug 11, 2026
… leave the June-20 bundle (#81)

* fix(public): add the tinystudio.in release lane (Cloudflare Pages deploy path repair)

The live site has served the 2026-06-20 bundle (07acd07) since June 20 while
17+ public PRs merged to main; the Cloudflare Pages git connection for
tiny-studio-3f5 never shows checks/statuses on commits and no deploy
workflow or secrets exist in the repo. The fleet Workers token lacks
Cloudflare Pages:Edit, so no automation on this box can publish today.

Add an in-repo release lane that works the moment a Pages-scoped token is
provisioned (documented fail-closed message):
- scripts/prepare-public-deploy-bundle.mjs: filtered bundle (public/ minus
  the snoozed-by-Nish managed-service buyer path from PRs #10/#11; every
  other merged fix preserved), fail-closed in both directions
- scripts/test-public-deploy-bundle.mjs: regression guard, wired into
  npm test/ci (62 checks)
- scripts/publish-public-site.mjs: prepare -> wrangler pages deploy to
  tiny-studio-3f5 -> live verification
- scripts/check-public-live-deploy.mjs: live proof for the deploy-path
  accept (H2-after-H1 /promptly/support/ #18/#20, JSON-LD /contact/ #19,
  real 404s #34, homepage portfolio-only #29 + no buyer path)
- .github/workflows/deploy-public-site.yml: vps-verify lane on push to main
- wrangler 4.120.0 devDependency

verify: npm test (603 checks, 0 failures); node scripts/prepare-public-deploy-bundle.mjs; git diff --check

* fix(public): attach the source commit to Cloudflare Pages deployments

wrangler pages deploy accepts --commit-hash/--commit-message/--commit-dirty
for dashboard provenance. The bundle already records source_commit in
deploy-manifest.json; pass it through so the Pages dashboard links the
deployment to the exact tinystudio-in commit that produced the bundle.

verify: node --check scripts/publish-public-site.mjs; node scripts/test-public-deploy-bundle.mjs (62 checks, 0 failures)

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>

---------

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
nish3451 added a commit that referenced this pull request Aug 13, 2026
…se lane (#104)

The soft-404 guard chain had one unguarded link: the release lane's
deploy-proof set (NEUTRAL_PROOFS) did not assert the top-level 404 page,
even though 'real 404s' is one of the four documented live proofs. The
top-level public/404.html is what terminates Cloudflare Pages'
single-page-application fallback (without it every unknown URL is served
as the homepage with HTTP 200 - the soft-404 PR #34 fixed).

Adding it to the proof set makes the lane itself fail closed if 404.html
is ever lost or regresses into a homepage clone, instead of only being
caught by the post-deploy live check after publishing.
nish3451 added a commit that referenced this pull request Aug 14, 2026
…p) (#149)

The repo already carries the real 404 fix (PR #34) and its static guards;
the live site serves the 2026-06-20 bundle because the release lane fails
closed on the missing CLOUDFLARE_API_TOKEN Pages secret. Document the
evidence and the one-time provisioning action that resolves the item.

Co-authored-by: nish3451 <nish@tinystudio.in>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
nish3451 added a commit that referenced this pull request Aug 17, 2026
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