blog: check links in ci, serve llms.txt and markdown, add seo metadata
- ci: .tangled/workflows/blog.yml builds the blog with nix and runs blog/scripts/check-links.sh over it twice: offline with #fragments for links between pages (breakage only we can cause), then the external links. lychee can't parse the at:// standard.site links, so the script strips them from a copy first. `pnpm check:links` runs the same check locally (lychee is in the devshell). fixes the two broken links it found in 6-months and spindle-microvm. - llms: every post as markdown at /<slug>.md (root-relative links made absolute), an llmstxt.org index at /llms.txt and all posts in /llms-full.txt; pages advertise their markdown with a rel=alternate link. - seo: @astrojs/sitemap with robots.txt pointing at it, BlogPosting json-ld on posts and Blog on the index, article:published_time/author meta, noindex on the 404 and drafts, a real meta description for the index, and links to /<slug>/, the canonical url cloudflare redirects to. - standard.site and feed.json, from the go generator this replaces: the json feed with announcement tags (the web app's timeline reads it), the .well-known/site.standard.publication verification file and the publication/document <link>s. rkey and announce are in the content schema; `blog publish` (cmd/blog) still writes the records. - build: nix builds with pnpm from pnpm-lock.yaml (the astro 7 upgrade left it on a stale package-lock that npm ci rejected), vite is pointed at the blog's own tsconfig instead of web/.svelte-kit's, and the web app's #lib and $app/env imports resolve. the app's shell footer is gone from web/, so the blog has its own copy of the minimal one, linking to tangled.org.