All work
Systems & fixesCompleted

The Sitemap Said /blog. The Site Did Not.

The sitemap advertised `/blog/:slug` while Astro generated root-level article routes. Both now consume the same normalized permalink.

Project
Dakic website
Role
Technical diagnosis, implementation, and release verification
Timeframe
August 2026
Status
Completed

Evidence from the work

Fault
Sitemap hard-coded `/blog/:slug` URLs
Verification
Generated sitemap now matches live article routes

What this is

The Dakic blog router generated articles at root-level permalinks. The custom sitemap built a second version of each address under /blog.

The site could publish an article that worked in the browser and advertise a different, nonexistent address to search engines.

The friction

The sitemap loaded raw content entries and reconstructed article URLs itself. It removed the filename extension, sanitized the remaining text, and prefixed the result with /blog/.

The blog system already had permalink code. That code read the configured permalink pattern and normalized each post into the same route used during the Astro build. The sitemap ignored it.

Both versions looked plausible in code. Comparing the generated sitemap with the generated pages exposed the mismatch.

The senior decision

We removed the sitemap’s private permalink implementation.

The sitemap now calls the same fetchPosts() function used by the blog routes. Each normalized post already contains its permalink, category, tags, publication date, and draft state. The sitemap uses those values instead of rebuilding them.

The change removed a second source of truth and reduced the amount of sitemap code. Draft filtering and permalink configuration now flow through the existing blog contract.

What became real

The sitemap now emits /${post.permalink} for each published post. A generated entry such as /2026-08-23-the-next-release-should-answer-a-question matches the page Astro creates.

The same change replaced raw category and tag sanitization with the normalized slugs supplied by the blog utilities.

Evidence

The implementation diff removed the hard-coded /blog/${slug} construction and imported fetchPosts from the shared blog utility. A production build generated the article routes and sitemap from the same post set.

After deployment, the three new AI work articles returned HTTP 200 at their root-level URLs. The live sitemap contained the same addresses.

What we learned

A route rule belongs in one module. Sitemaps, RSS feeds, navigation, and static paths should consume that module rather than approximating its behavior.

A successful page build does not validate discovery metadata. Route verification needs to compare the generated page, canonical URL, and sitemap entry.

Current state

The correction is live. The sitemap and blog router now share normalized post data and permalink behavior.