The `Slug` brand and `PostMeta` introduced in #61 work as designed — the brand sits at a real security boundary (raw interpolation into URLs and the sitemap XML) and `parseSlug` is the single safe constructor. Three low-cost follow-ups to harden it further:
1. Use a `unique symbol` instead of a structural brand
`lib/blog.ts:18` defines `Slug = string & { readonly __brand: "Slug" }`. This is structurally forgeable: anyone writing `"foo" as Slug` or constructing `{ __brand: "Slug" as const }` adjacent to a string compiles. The `unique symbol` brand pattern is unfakeable across modules.
2. Apply the same brand pattern to `date`
`lib/blog.ts:23-29` types `date: string` even though `parseEntry` already proves the value matches `ISO_DATE_RE`. Mirror `Slug` with `IsoDate` + `parseIsoDate` so future consumers (RSS feed, archive page) don't have to re-test the regex.
3. Delete dead `summary` conditional
`summary` is required + trimmed-non-empty at parse, so `{post.summary ? (…) : null}` at `app/blog/page.tsx:91` is dead defensive code. Delete the guard.
Found during PR review of #61.
The `Slug` brand and `PostMeta` introduced in #61 work as designed — the brand sits at a real security boundary (raw interpolation into URLs and the sitemap XML) and `parseSlug` is the single safe constructor. Three low-cost follow-ups to harden it further:
1. Use a `unique symbol` instead of a structural brand
`lib/blog.ts:18` defines `Slug = string & { readonly __brand: "Slug" }`. This is structurally forgeable: anyone writing `"foo" as Slug` or constructing `{ __brand: "Slug" as const }` adjacent to a string compiles. The `unique symbol` brand pattern is unfakeable across modules.
2. Apply the same brand pattern to `date`
`lib/blog.ts:23-29` types `date: string` even though `parseEntry` already proves the value matches `ISO_DATE_RE`. Mirror `Slug` with `IsoDate` + `parseIsoDate` so future consumers (RSS feed, archive page) don't have to re-test the regex.
3. Delete dead `summary` conditional
`summary` is required + trimmed-non-empty at parse, so `{post.summary ? (…) : null}` at `app/blog/page.tsx:91` is dead defensive code. Delete the guard.
Found during PR review of #61.