Fixed a sitemap where 172 of 176 URLs shared one modification timestamp, by taking the date from git history after establishing that the export rewrites every file on every run.
Work carried out: 2025
Situation. The site’s sitemap told search engines that 172 of its 176 pages had last changed at the same instant. That is not a subtle inaccuracy — a modification date is a promise to a crawler that a page’s content changed, and a site making that promise 172 times simultaneously is either telling the truth about a full rewrite or telling nobody anything useful.
Task. The dates had to describe the content rather than the file, without inventing precision the repository does not have.
Action. The cause was that the date came from the file’s modification time and the content export rewrites every file on every run, so a single sync stamped the whole corpus. The fix moves the source to the version history, with a fallback chain that tries an explicit field first, then the commit history, then the file. The trap in that fix is worth recording: the literal field name has to appear in the list or the generator never reads it, so a configuration that looks like it prefers an authored date but omits the name silently ignores every authored date. Two other date decisions came out of the same work. The database now carries when each record was written and last revised, kept deliberately separate from when the work happened — those are years apart and conflating them would date a page written this year to a decade ago. And rows in that file are optional and nothing is derived, because the repository’s own history begins after the content did: a missing date leaves the field empty rather than recording a migration, on the principle that a precise wrong number is worse than an absent one, since only the wrong one gets believed.
Result. A re‑sync after a month of content edits now touches eight files of 186 instead of all of them, and the sitemap says something true. The general rule went into the metadata document alongside it, because the same trap applies to every field that has a fallback chain.