Changelog

New features and improvements to Simparlia, most recent first. Each entry marks a release of the Corpus explorer.

v0.1.20.0

Added

  • Public changelog at `/changelog` (SIM-99): a developer-docs-style page, most-recent-first, that parses this CHANGELOG.md at build time as the single source of truth (linked from the nav and sitemap), plus an auto-update pipeline — a `feat` landing on main appends its entry and bumps VERSION via a GitHub Action, so the page rebuilds itself when features drop

v0.1.19.0

Added

  • Compare two MPs side by side (SIM-118): a new `/corpus/compare/[a]/[b]` view that places two MP profiles in parallel columns — ideology scales, voting-behaviour metrics, and policy positions aligned for direct contrast — with a picker to swap either Member, a shareable URL, and a per-comparison Open Graph card

v0.1.18.0

Added

  • Evidence drill-down on profile sections (SIM-117): opening a briefing section reveals the source material behind each claim — the specific speeches, divisions, and written questions — so every statement on a profile is traceable back to the parliamentary record

v0.1.17.0

Added

  • Source-type provenance icons (SIM-15): a monochrome glyph system marking which kind of source backs each piece of evidence (speech, division, written question, committee, early day motion, and more), shown inline on the profile and in the Data & Sources panel

v0.1.16.0

Added

  • Portrait-led social share cards (SIM-16): per-MP Open Graph and Twitter images that foreground the official parliamentary portrait alongside the Member's name, party, and constituency, for richer previews when a profile is shared

v0.1.15.0

Added

  • Ideology glossary and tooltips (SIM-119): plain-English definitions for the economic, social, and sovereignty scales, surfaced as tooltips beside each ideology bar and collected in one place so the axes are legible to non-specialists

v0.1.14.0

Changed

  • Ideology and positions framed as model estimates (SIM-111): profile ideology scores and policy positions are now presented explicitly as model estimates with a confidence level rather than stated facts — honest framing while independent validation is pending

v0.1.13.0

Added

  • MP roles (SIM-110): sitting post in the profile header (Commons-green accent line — "Prime Minister and First Lord of the Treasury" on Starmer's page; backbenchers stay quiet), and a Government Record briefing section with each MP's dated government/opposition post history (Sunak's page now shows his PM and Chancellor record)

v0.1.12.0

Changed

  • MP profile page design pass, iteration 1 (SIM-12): numbered briefing sections with hairline rules, ideology bars gain quarter-tick grid + evidence lines + settle-in motion, voting bars thickened with fill animation (all motion honest-HTML and reduced-motion safe), portrait+name header lockup, provenance footer (profile version, model, generation date)

v0.1.11.0

Added

  • Find your MP by postcode (SIM-25): `POST /api/mp/lookup` resolves UK postcodes via postcodes.io (ONS data) matched against our own MP data — rate-limited, 30-day cached, clear errors for invalid/unknown postcodes and vacant seats; compact lookup form on the Members directory navigating straight to the MP's profile; `mp_lookup` analytics event (never logs the postcode itself)

v0.1.10.0

Added

  • MP portraits across Corpus (SIM-22): official parliamentary photographs (© UK Parliament, CC BY 3.0) on directory cards (64px greyscale thumbnails) and profile headers (128px), served from Supabase Storage — 635 of 650 MPs; the 15 without official portraits render text-only with attribution omitted

v0.1.9.1

Changed

  • Production builds cut from ~17 minutes to ~14 seconds (SIM-104): MP profile pages now render on demand with hourly ISR instead of pre-rendering all 650 at build time; data-layer accessors wrapped in React `cache()` to dedupe the metadata + page double-fetch per request

v0.1.9.0

Changed

  • `/corpus` restored as the marketing page (live-review iterate, SIM-105): description, "Browse the 650 Members" primary CTA, waitlist secondary, Dispatch cross-link — ASCII scene retained
  • MP directory moved to `/corpus/members` (search, party filter, full grid); sitemap updated; profile pages link back to "All Members"
  • Data pages (`/corpus/members` + all 650 `/corpus/[slug]` profiles) render a plain background — no ASCII scene behind dense content, which was unreadable

v0.1.8.0

Added

  • `/corpus` is now the MP discovery portal (SIM-27): browsable card grid of all 650 MPs (surname-ordered), instant client-side search across names and constituencies, party filter with display-level grouping (Labour (Co-op) folds into Labour for filtering; cards show the verbatim party), live result count, `corpus_search`/`corpus_filter` analytics events
  • `MPCard` and `MPDirectory` components join the mp-profile library
  • Honest degradation: a data-layer outage shows an unavailable notice instead of failing the page; the waitlist (now a secondary footer CTA) survives

v0.1.7.0

Added

  • 650 MP profile pages at `/corpus/[slug]` (SIM-26): SSG via `generateStaticParams` + 1-hour ISR, persona lede, ideology position bars (economic/social/sovereignty), voting-behaviour metrics, key interests, policy positions, notable rebellions, reasoning style, and background — all rendered from the live `mp_profiles` data layer
  • Reusable `mp-profile` component library (BriefingSection, IdeologyBar, MetricBar, ProfileHeader, DataTierBadge, PositionList, RebellionList, ProfileViewTracker) — design-token driven, honest no-data states
  • Per-MP dynamic Open Graph images (Caslon display, Commons-green accent bar)
  • SEO: per-page metadata + canonical, JSON-LD Person schema, sitemap entries for all 650 MPs; `mp_profile_view` analytics event; 404 page for unknown MPs

Changed

  • Background location resolution falls back to the section path, so dynamic routes inherit their section's ASCII scene
  • Vitest runs on the threads pool (forks pool broken under Node 25; 306 tests now run in ~6s)

v0.1.6.0

Added

  • `mp_profiles` Supabase table — the Corpus data layer bridging the synthetic-parliament research pipeline to the product (SIM-20). Migrations 002–004: JSONB `layer1_profile`/`layer2_profile`/`ideology_scores`, provenance columns, CHECK constraints (slug format, rates 0–1), `updated_at` trigger, `sort_name` ordering column, RLS locked to service-role reads, documented slug collision rule
  • Typed data-access module `src/lib/mp-profiles.ts`: `mpSlug()` canonical slug generation (honorific stripping incl. stacked titles, diacritic folding, non-decomposable transliteration), `getMPProfileBySlug()` and `listMPProfiles()` accessors that throw on query errors so outages surface as 500s rather than cached empty states
  • 20 unit tests covering slug rules, fetch hit/miss/error, list ordering/filtering/error

v0.1.5.0

Added

  • `sitemap.xml` generated via Next.js App Router (`src/app/sitemap.ts`) listing all 9 public routes
  • `robots.txt` allowing all crawlers with sitemap reference (`src/app/robots.ts`)
  • Per-page metadata (unique title + description) for all pages via route-level layouts
  • JSON-LD structured data: Organization + WebSite schema in root layout
  • Canonical URLs (`alternates.canonical`) on all pages

v0.1.4.4

Fixed

  • Homepage scroll and CTA button blocked during ASCII background reveal animation and window resize re-render
  • Prevents broken background transitions when user interacts before the reveal completes

v0.1.4.3

Added

  • Staggered fade-out for homepage hero content on scroll: heading fades first, then subtitle, then CTA button. All invisible by ~55% scroll depth.

v0.1.4.2

Changed

  • All buttons full-width on mobile: homepage CTA, Explore Corpus, Explore Dispatch now match waitlist form button width
  • Desktop button sizing unchanged (min-w-65 inline)

v0.1.4.1

Changed

  • Corpus page rebuilt from flex column to block layout matching Dispatch pattern
  • Single responsive layout (no duplicate desktop/mobile render)
  • Tests restored to `getBy` (single element) instead of `getAllBy` workarounds

v0.1.4.0

Added

  • Hamburger menu on mobile (<640px) with full-screen overlay and Caslon Old Face links
  • `prefers-reduced-motion: reduce` support — disables all animations and transitions
  • `aria-label` on all waitlist form inputs and ASCII canvas
  • `aria-live` region for waitlist form error announcements
  • `<main>` semantic wrapper in layout
  • iOS input zoom prevention (16px minimum on mobile inputs)
  • Homepage hero left-aligned on mobile with "Parliament," / "Predicted." line break
  • Subtitle constrained to max-w-lg on desktop for balanced wrapping

Changed

  • Muted text colour darkened from `#7A7570` to `#736E69` (4.83:1 contrast ratio, passes WCAG AA)
  • Mobile background: clean off-white, no images (placeholder for custom mobile assets)
  • Dispatch and Privacy pages: mobile layout left-aligned with 20vh top padding
  • Research and About pages: static positioning on mobile with 20vh top padding
  • Corpus page: separate desktop/mobile layouts (mobile is block-level, left-aligned)
  • Cross-link buttons use `max-sm:flex max-sm:w-full` for full-width on mobile
  • Button gap between form and cross-link standardised to mt-2 on Corpus and Dispatch

v0.1.3.1

Changed

  • Page transition mode changed from `sync` to `wait` — exit animation completes before enter starts, eliminating content overlap on slow connections
  • Nav links preload target route's background image on hover for faster transitions
  • All route background images preloaded after 2 seconds idle

Removed

  • 6 unused high-res PNG images (~65MB) and 5 unused JPG images (~1.9MB) from `public/images/`

v0.1.3.0

Added

  • Server-side traffic source classification: every event gets a `traffic_source` field (`direct`, `organic`, `social`, `referral`, or `campaign`) derived from referrer and UTM signals
  • Referrer domain parsing: `referrer_domain` field extracted from `document.referrer` with `www.` stripping for human-readable querying
  • Internal page navigation tracking: `from_page` field on `page_view` events enables user journey reconstruction through the site
  • Domain boundary matching for traffic source classification to prevent false positives (e.g. `googledocs.com` not misclassified as organic)
  • Waitlist confirmation email via Resend — sends on new signups only, not duplicates
  • `src/lib/resend.ts` — Resend client singleton (same pattern as Supabase client)
  • `src/lib/waitlist-email.ts` — plain text + minimal HTML email matching the design system (Geist Mono, monochromatic palette, Caslon wordmark)
  • `simparlia.com` domain verified with Resend (EU region, enforced TLS, DKIM + SPF configured via Cloudflare)

Changed

  • Waitlist route now checks for existing email before inserting (duplicates return success silently, no email sent)
  • Waitlist route handles invalid JSON body gracefully (400 instead of unhandled throw)
  • Email validation runs after normalisation (trim + lowercase) so whitespace-padded emails are accepted
  • Select query errors are now logged and return 500 (previously silently swallowed)
  • Supabase mock supports `selectChain()` for `.select().eq().limit().maybeSingle()` patterns

v0.1.2.0

Added

  • Dual-layer analytics: Vercel Web Analytics + Speed Insights for the dashboard, Supabase `events` table for SQL-queryable owned data
  • `POST /api/event` endpoint with event name allowlist, type validation, and Supabase insert
  • `useAnalytics()` hook and standalone `trackEvent()` for dual-writing to Vercel + Supabase via `sendBeacon`
  • Anonymous session IDs via `sessionStorage` + `crypto.randomUUID()` (no cookies)
  • UTM parameter capture from URL on first load, cached in `sessionStorage`
  • Automatic `page_view` tracking on every route change via `template.tsx`
  • `page_exit` event with `duration_seconds` metadata via `visibilitychange` and client-side navigation
  • Waitlist funnel events: `waitlist_expand`, `waitlist_submit`, `waitlist_success`, `waitlist_error`
  • CTA, product scroll, and cross-link click tracking on homepage, Corpus, and Dispatch pages
  • Consent event tracking (`consent_accept`, `consent_reject`) that bypasses the consent gate
  • Analytics section in CLAUDE.md documenting the system and requiring analytics review for new features

Changed

  • Privacy overview page: "Cookies" section replaced with "Analytics" section describing session-storage-based tracking
  • Privacy policy: added anonymous usage data and Vercel Speed Insights to "Data We Collect" and "Third-Party Sharing"
  • Cookie policy: updated overview and third-party sections to reflect session storage and Vercel Speed Insights
  • Corpus page converted to client component (`'use client'`) for cross-link click tracking

v0.1.1.2

Added

  • `--type-section` type scale token (`clamp(20px, 2.5vw, 24px)`) bridging the gap between hero (80px) and subheading (18px)

Changed

  • Product card headers on homepage scroll section now use `--type-section` (24px) instead of `--type-subheading` (18px)
  • Dispatch description copy: removed "affairs" from audience label
  • Dispatch description extended for line-wrap parity with Corpus card
  • `/dispatch` CTA button gap equalised with `/corpus` (both `mt-6`)
  • OG meta description: lowercase "parliamentarian"

Removed

  • "Two Products, One Parliament" header from homepage scroll section

v0.1.1.1

Added

  • Open Graph image generated dynamically via `next/og` (Satori) with ASCII texture background and Caslon Old Face headline, matching Figma design system
  • Twitter card meta (`summary_large_image`) for rich social sharing previews
  • Custom favicon: Commons green square with outlined Caslon Old Face "S" letterform (vector paths, no font dependency)
  • Layout metadata tests covering OG, Twitter card, and metadataBase configuration

Changed

  • Site title updated to "Simparlia — Parliament, Predicted."
  • OG description updated to "Predict Parliamentarian voting behaviour"

v0.1.1.0

Added

  • Dual-product showcase on the homepage: scroll down from the headline to discover Corpus and Dispatch side by side, with a scroll-driven ASCII morph between hero and products images
  • New `useScrollMorph` hook dispatching progress events for canvas transitions
  • Vertical edge fade on the scroll morph target for gradual top/bottom detail falloff
  • New baked hero and products images for homepage ASCII art

Changed

  • Unified ASCII renderer defaults (opacity 0.45, brightness boost 0.03) so every page looks consistent
  • Exported `OPACITY_DEFAULT` from the renderer, replacing all hardcoded fallbacks
  • Scroll morph now recovers gracefully when the target image fails to load

Fixed

  • Background flicker when navigating between pages caused by mismatched opacity/brightness defaults

© 2026 Simparlia