Files
unique/CHANGELOG.md
T
rzen 9e5fce1eb0 site: topics axis + per-source indexes
Topics — the curated subscription layer: 18-value controlled vocabulary
in src/lib/topics.ts, enum-enforced by the content schema on finds and
reviews so unattended runs can't drift it. /topics/ index +
/topics/<t>/ pages with finds first-class alongside reviews, per-topic
RSS feeds that include finds (unlike category/tag feeds), "By topic"
section on /feeds/, Topics footer link and llms.txt section, dev-shim
coverage for the new feed URLs. daily-finds and build-review skills now
classify at capture/graduation time; "giftable" is a tag, never a
topic.

Per-source indexes: /sources/<slug>/ lists every review and find from a
source (catalog ∪ names in content, so retired sources resolve);
find/review colophons link "(more from this source)"; /sources/ cards
link "everything from this source →"; sub-3-item pages noindexed.

Claude-Session: https://claude.ai/code/session_01WZaczDJjL3xZ3u5spsN5AL
2026-07-12 19:39:11 -04:00

16 KiB

Changelog

July 2026

  • Topics — a new coarse classification axis for following slices of the site: an 18-value controlled vocabulary (src/lib/topics.ts), enum-enforced by the content schema on finds and reviews so unattended capture runs can't drift it. All 864 finds and 64 reviews retroactively classified (subagent batch job); the retired source-inherited values (dad-jokes, quotes, apple-tips, general-delight…) map into the new set, and gifts became a giftable tag on 140 finds ("giftable" is a facet, not a topic). New /topics/ index and /topics/<topic>/ pages where finds are first-class alongside reviews, per-topic RSS feeds that include finds (unlike category/tag feeds), a "By topic" section on /feeds/, a Topics footer link, and a Topics section in llms.txt; daily-finds and build-review skills now classify at capture/graduation time
  • Per-source indexes: /sources/<slug>/ lists everything surfaced via a source (reviews + finds, newest first, with the source's outbound link and notes); find and review colophons gain a "(more from this source)" link next to the source name, and /sources/ cards link through via "everything from this source →". Pages exist for every source ever named in content, including retired ones; sub-3-item pages are noindexed
  • Tag pages now include finds: /tags/<tag>/ is generated from the union of entry and find tags (1,179 tags that existed only on finds — most tag links on find pages — previously 404'd) and lists tagged finds in a compact secondary section below the entry grid, keeping reviews/bundles/posts visually on top. Find-only tag pages with fewer than 3 finds are noindexed until they fill out; tag feeds stay entries-only, and the RSS pill only renders where a feed exists. Category pages are unaffected (finds have no category)
  • Feeds for everything: alongside the existing /rss.xml, add a JSON Feed 1.1 at /feed.json, per-category RSS at /categories/<name>/rss.xml, and per-tag RSS at /tags/<name>/rss.xml — all derived from a shared src/lib/feed.ts item source (reviews + posts + bundles, same visibility rules as the site). Category/tag pages advertise their scoped feed via <link rel="alternate"> autodiscovery and show a visible RSS pill in the subheader (browsers dropped feed-detection UI years ago, so autodiscovery alone is invisible); a new /feeds/ directory page (linked from the footer) lists every feed with entry counts; every RSS feed carries an atom:link self reference and renders as a readable page in browsers via public/feed.xsl
  • Programmatic-reader pass: build-generated /llms.txt (llmstxt.org format — site description, feed/endpoint map, and every review, bundle, and post with one-line descriptions), SearchAction on the home-page WebSite JSON-LD wired to /search/?q=, and a "For robots" section on /feeds/ documenting search.json, llms.txt, the sitemap, and JSON-LD coverage
  • Autonomous pipeline overhaul: new /daily-pipeline skill chains capture → bundle → review graduation → pick-of-the-day → build → commit → push and ends with a digest; daily-finds gains a score-and-shortlist stage (up to 12 shortlist: true finds per run, top 1-3 flagged as review candidates), feed-first fetching (fetch: "feed" + feedUrl in sources.json), cadence-aware scanning, and authority to apply mechanical source maintenance itself; build-bundle/cluster-bundles/build-review gain unattended auto modes (publish + log instead of pausing for confirmation), and build-bundle weekly writes a date-based "week's catch" so shortlisted finds never sit unbundled for weeks
  • Review heroes are now auto-discovered: src/lib/hero.ts globs reviews/*/hero.<ext> (images and hero.mp4), so a new review needs no registration — only legacy non-hero-named assets remain as explicit overrides; both hero globs also accept .avif
  • Pick of the day moves from a hardcoded constant in src/pages/index.astro to src/data/pick.json (falls back to the latest review); the dev-mode "Make today's pick" button writes the JSON file
  • Optional amazonLink frontmatter on finds and reviews renders an "Also on Amazon" link with the existing affiliate tagging, badge, and disclosure; the capture pipeline looks up exact Amazon matches for shortlisted physical products
  • Fact-checking against the product's own site is now a mandatory step when a find graduates to a review unattended

May 2026

  • Bucket find/ folders by capture date: every find moves from src/content/find/<slug>/index.mdx to src/content/find/<year>/<month>/<slug>/index.mdx (all 289 existing finds migrated to 2026/05/). The find content-collection loader uses a new leafSlug generateId so the id (and therefore the URL at /find/<slug>/) stays flat, and src/lib/find-hero.ts switched to a recursive **/hero.{...} glob. No URL changes; bundle items[], promotedTo/fromFind cross-references, and category/tag pages all keep working unchanged. Rationale: the flat folder was getting hard to scan and slow git status at ~290 finds and growing 20+/day
  • Rename the "finds" superpost concept to bundle. The finds collection becomes bundles (src/content/bundles/), URLs move from /finds/<slug>/ to /bundles/<slug>/, and the home/footer/search labels switch from "List" to "Bundle". Internal renames: findListMosaicbundleMosaic, FindsPostBundle, findsReferencingbundlesReferencing, Entry.type 'finds''bundle', OgFallback 'finds''bundles'. Build script and generated mosaic dir follow (scripts/build-bundle-mosaics.mjs, src/generated/bundle-mosaics/). Skills build-finds and cluster-finds renamed to build-bundle and cluster-bundles. The find collection (individual items) is unchanged
  • Add Cloudflare Web Analytics: privacy-preserving, cookieless beacon injected into BaseLayout.astro so per-page traffic, referrers, and Core Web Vitals show up in the Cloudflare dashboard scoped to unique.rzen.dev. Privacy statement on /legal/ updated to disclose the beacon
  • Strengthen the "Use of the site" section on /legal/: explicit "inclusion isn't endorsement" + no warranty on safety/quality/durability/fit/continued-existence + no responsibility for what happens after click-through. Tone kept plain, not legalese
  • Colocate every collection's articles with their media: each entry is now a folder <slug>/index.mdx with sibling media files. Applied to reviews/, find/ (104 articles + 89 heroes auto-resolved by src/lib/find-hero.ts via import.meta.glob('../content/find/*/hero.{...}')), finds/, and posts/. Slug derivation handled by a shared stripIndex helper on each glob loader; URLs unchanged across the entire site. MDX paths shortened from ../../assets/reviews/<slug>/<file> to ./<file>. src/assets/ removed entirely
  • Media optimization pass: re-encode the 13 heaviest assets (h264 CRF 28, scale ≤1280px, audio stripped) and convert the two animated GIFs (cotypist, flux-markdown) to MP4 — dist/ drops from 53 MB to 31 MB (~42% smaller); biggest single wins are homerow/search.mp4 (6.7 MB → 1.6 MB), antinote/links.mp4 (2.9 MB → 193 KB), flux-markdown/demo.gif (3.9 MB → 1.3 MB MP4). Originals preserved at src/assets/reviews/<slug>/source/ and never bundled
  • Tile videos on / and /grid/ switched from preload="metadata" to preload="none" so below-the-fold demos don't fetch on page load
  • src/lib/hero.ts and the cotypist/flux-markdown review MDX updated to render the new MP4 heroes as inline autoplay-loop muted <video> instead of <img>
  • Comprehensive SEO pass: new <SEO> component centralising every head-level tag (canonical, Open Graph, Twitter Card, theme-color, RSS alternate, JSON-LD); page-aware structured data — Review + BreadcrumbList on review pages, BlogPosting on posts, Product + BreadcrumbList on finds, Article + ItemList on finds superposts, CollectionPage + ItemList on category/tag/sources/blog pages, WebSite + Organization + ItemList on the home page, AboutPage on /about
  • Add @astrojs/sitemap (auto sitemap-index.xml excluding /grid/, /index3/, /404/) and @astrojs/rss (feed at /rss.xml covering reviews + posts + finds superposts); add public/robots.txt pointing at the sitemap
  • Add custom 404 page with recent reviews + nav fallback (noindex)
  • Wire promoted finds to canonical to their review (via promotedTo); other finds self-canonical
  • Noindex /grid/ and /index3/ (kept linked but absent from sitemap and search)
  • Per-page descriptions + OG image alt text for every page; count-bearing titles and descriptions on category/tag pages ({category} ({n})); hero image upgraded with real alt text, fetchpriority="high", loading="eager", decoding="sync"; static OG fallback tiers in /public/og/ (default/reviews/finds/posts — PNGs to be supplied)
  • Set trailingSlash: 'always' and build.format: 'directory' explicitly to keep canonical URLs stable
  • Memoize getSiteStats() so per-page SEO additions don't multiply build cost
  • Site-wide UI/UX refresh: newspaper-style masthead on every page (entry-count + last-updated on the left, large serif "Unique" wordmark centered between thin rules, About · Blog nav on the right), per-page italic subheader with last-updated date on listing pages, and an SEO-friendly footer with Browse / Collections / About link columns
  • Home page swapped to a Pinterest-style hero + masonry grid; the plain chronological list view moves to /index3/
  • New /about stub and /blog index (Astro page over the posts collection with an empty-state when no posts exist)
  • Single 76rem page width across the entire site (replaces the 42rem default + wide prop split); article prose is constrained to a 42rem reading measure inside the wider layout so reviews/finds stay readable
  • New getSiteStats() helper in src/lib/entries.ts powers the masthead counts and footer Collections column live
  • Amazon affiliate handling: outbound links to amazon.com, amzn.to, a.co, and smile.amazon.com get the configured tracking ID appended at render time, are marked with rel="sponsored noopener noreferrer", and display a clearly-signposted "Affiliate" badge plus a one-line FTC-style disclosure on review and find pages. Tracking IDs live in src/lib/affiliate.ts keyed by marketplace; non-US Amazon hostnames are recognized but left untagged until a marketplace-specific ID is added
  • Restructure into a four-collection content pipeline: find (captured items, hidden from indexes), finds (editorial superposts that reference find slugs in a Pinterest-style grid), reviews (existing — gains optional source and fromFind fields for graduations), and posts (existing, generic essays)
  • New routes /find/<slug>/ (direct URL only — finds don't appear on home, tag, or category pages) and /finds/<slug>/ (superpost detail with intro + grid)
  • New components: FindCard, FindsGrid, Backlinks, SourceBadge
  • /sources cards gain a "Recent finds" sub-list per source — the one cross-cutting surface where individual finds are visible
  • Find pages show "Featured in:" backlinks computed at build time from any superpost referencing them; review pages show "← First surfaced…" when promoted from a find
  • New project-local skills under .claude/skills/: daily-finds (capture-only — no theme detection, no candidate post, no winner pick), build-finds (editorial superpost author), build-review (find → review graduation)
  • sources.json gains per-source fetch strategy (webfetch / curl / skip) with optional fetchUrl override; 11 sources switch to curl with a Safari User-Agent (Cool Material, MoMA Design Store, StyleForum, Atlas Obscura, etc.); 9 marked skip after Cloudflare JS challenges and active anti-bot defeats both WebFetch and curl
  • New /sources page (3-column card stream listing every source with its type, cadence, topics, and notes)
  • Migrate the seed daily-finds post: extract 5 candidates into individual find files, slim the superpost to just the intro paragraph, move from posts/ to finds/
  • Initial sources.json curated across macOS apps, useful tools, gifts, clothing, travel, and general-delight feeds (47 sources)
  • Daily-finds capture log at daily-finds.log.md; new-source nominations queued at candidate-sources.md
  • Initial blog scaffold with Astro 5 (content collections, no client JS)
  • Base layout with light/dark theme via prefers-color-scheme
  • Index page listing posts by date (newest first)
  • Per-post page with title, date, category, optional external link, tags
  • Auto-generated category and tag listing pages
  • Seed content: 12 posts on delightful Mac apps (Cotypist, Folder Peek, DockDoor, TypeWhisper, Hyperkey, AntiNote, FluxMarkdown, Monocle, Alcove, Shottr, MiddleDrag, LinearMouse)
  • Switch to MDX (@astrojs/mdx) for post bodies
  • Restructure into two content types: reviews (name + subtitle + body) and posts (title + body, empty for now)
  • Unified entry helper (src/lib/entries.ts) and shared EntryList component so the home, category, and tag pages render a mixed chronological feed across collections
  • Reviews route moved to /reviews/<slug>/; review detail pages show name as <h1> with subtitle as a tagline beneath
  • Index entries now show two lines for reviews (bold name + muted subtitle), single line for posts
  • Migrate the 12 seed entries from src/content/posts/*.md to src/content/reviews/*.mdx with the new schema
  • Add 5 new reviews: Ice (interface), AltTab (interface), Mac Mouse Fix (input), Homerow (input), Tot (writing)
  • Establish media convention at src/assets/reviews/<slug>/ for real screenshots/clips downloaded from each app's site
  • Add visuals to 15 of 17 reviews (mp4 demos, animated gifs, or App Store screenshots), with one-line italic captions naming what's shown
  • Style images and videos in review pages: max-width 100%, centered, soft border-radius; italic-only paragraphs auto-render as captions
  • Use import …?url for animated GIFs (cotypist, flux-markdown) to bypass Sharp and preserve animation
  • linearmouse and middledrag intentionally have no visual: linearmouse.app is JS-only with no scrapeable demo and the repo carries no screenshots; the artginzburg/MiddleDrag repo cited in the review no longer exists
  • Rewrite all 17 reviews — informative, concise, no sales tone; longer reviews lead with a pre-review blockquote summary
  • Style .body blockquote as a confident lead (accent left-border, no italics, foreground color) on review and post detail pages
  • Add optional linkText field to reviews: overrides the external-link label (e.g. "Visit in App Store" or "Visit on GitHub"); defaults to the link's hostname with www. stripped
  • Sample a Pinterest-like 3-column tile stream at /grid/ (CSS column-count masonry, no JS); responsive to 2 cols / 1 col on narrow viewports
  • src/lib/hero.ts maps slug → hero asset (image or video) so the grid can render visuals; reviews without media (linearmouse, middledrag) become text-only tiles with an accent gradient
  • Add wide prop to BaseLayout for pages that need a wider max-width than the default reading column
  • Floating "grid view →" link from the home page; the main index keeps its plain list layout
  • Add a CSS-only scroll-snap carousel for reviews with multiple visuals: each <figure> slide carries its own <figcaption>; pure CSS, no client JS; thin scrollbar visible on desktop, swipe on touch
  • Expand 8 reviews into multi-slide carousels with downloaded media — antinote (5), typewhisper (6), dockdoor (3), shottr (3), folder-peek (3), homerow (3), ice (3), tot (2); 28 slides total across the site
  • Limit the home page index to the 12 most recent entries across all collections; older entries remain reachable via /grid/, categories, and tags