flowingkhaosSign inBrowse the marketplace
New here? flowingkhaos is a build-in-public workshop. This is one part of one of two production failures.What this site is

openFix 02 · part three of five

Investigation — Astro trailing slash on Cloudflare: fix the 307 and sitemap duplicates

Updated

Investigation

2026-10-07, 18:00 — the read. A script that asks the Search Console URL Inspection API about every URL in the sitemap wrote the index report: 26 URLs, 1 indexed, 21 duplicates, 4 unknown. Grade A for what it measures: it comes from Google’s own API. What it measures is the addresses in the sitemap — that distinction took six hours to matter.

2026-10-07, 18:25 — first attempt, one URL form. Three commits set the canonical link on every page, made every internal link slashless, and moved the build to format: 'file' so the built file and the sitemap match the linked address. Tested locally: /column 200, /column/ 307 to it. Measured on production at 23:00 after the deploy: /column/ still 307. The temporary redirect comes from Cloudflare’s assets layer, before the Worker runs, and no Astro setting reaches it. The attempt made the sitemap, the canonical and the links agree; it did not change the redirect’s status.

2026-10-07, 23:10 — the live crawl. All 26 URLs with a plain HTTP client, recording status, headers, canonical, description, H1, JSON-LD and outbound links per page:

  • http:// → 200, no HSTS. Dead end for “the zone already forces https”: it did not.
  • 0 of 26 pages with JSON-LD. 0 with an author. 0 with a date in markup.
  • 16 of 26 with the same description.
  • On a workshop step page, 8 of the 25 outbound links were sign-in links carrying ?next=.

2026-10-07, 23:30 — where the 307 can become a 301. Cloudflare’s static assets setting html_handling changes which form is served, but every mode answers the other form with a 307. public/_redirects cannot say “strip the trailing slash of any path” in one rule, and the file is first-match-wins with the old site’s wildcards already in it. A Worker could do it, but only with run_worker_first, which puts every request through code to rewrite one header. The one place left is a Redirect Rule on the zone, the same place the existing www → apex rule lives, which answers before assets or Worker. Decision: that rule, plus “Always Use HTTPS” and HSTS as zone settings. Dashboard items, not code.

2026-10-07, 23:45 — why the sitemap had no dates. The sitemap integration’s serialize hook receives only the URL. The dates exist on every CMS row (updatedAt, createdAt) and are already used as the content digest and as the feed’s pubDate; the integration cannot see them. Decision: drop the integration and write the sitemap as an endpoint of the site, from the same collections the pages are built from.

2026-10-08, 00:30 — the fixtures build read the wrong Polar. The fixture-driven test build failed with a Polar product id no product matched. The fixture flag was being ignored: the repo’s local .env carries the live Polar token, and the prerender step runs inside wrangler’s sandbox, which loads .env as variables that shell flags cannot override. The CMS loader, which runs in Node, honoured the flag; the Polar reader, in the sandbox, did not. Two runtimes, two sources of environment, one build. An hour; the fix for the gate is to move .env aside during a fixtures build.

2026-10-08, 00:45 — the tests still believed the old layout. Every test that reads the built output looked for fixes/index.html; since the first attempt’s format: 'file' the file is fixes.html. 113 tests failed on first run. One helper that names the file a route builds, used in nine tests; 265 pass after.

2026-10-08, 00:22 UTC — the second read, and the correction. The same script, run after the merge, against the sitemap that now lists slashless URLs: 24 of 26 “submitted and indexed”, last crawled between 19 and 29 September — before any of today’s work. 2 unknown: one marketplace tag page and one workshop step. So the pages had been indexed for weeks at the slashless address. The first read’s “1 of 26” was the truth about the 26 addresses the sitemap submitted, not about the pages. Measurement lesson, written down so it is not repeated: a URL Inspection report answers for the address you give it; when the site answers at two addresses, inspect the one Google chose (the google_canonical column was in the CSV the whole time), or the report describes the sitemap’s mistake, not the site’s reach.

The column · weekly · free

The next fix, in your inbox the week it happens.

One written column a week. The email service holds the list.

The marketplacePay once

Skip the build. Start from code that ships

Production-ready code under a one-time licence. Buy it, and start building with the code you bought.

  • Pay once
  • Resell what you build
  • No subscription

Luke Sidney writes and builds everything here, alone, in the open. lukesidney.me

Next part · 04 of 05Repair