Register
Entered
2026-10-01
First commit
2026-10-01

on-record

App · public record · live

What French deputies actually do, on the record, not what they say.

How French deputies actually vote, vote by vote. Every public vote of the Assemblée nationale, explained in plain French for readers who never followed a session, each figure traced back to the official record.

  • TypeScript
  • React
  • Zod
  • GitHub Actions
  • Cloudflare Pages
  • Vitest
Open live (opens in a new tab)Source (opens in a new tab)
Live1 · X · 2026
Drawing: one figure about a deputy, wired to the single ballot it counts, on a stack of official vote sheets where each row is a vote and each square a ballotASSEMBLÉE NATIONALEPUBLIC VOTESONE FIGURE · ONE DEPUTYFORwith the group of the dayOFFICIAL RECORDevery page cites its sourceEVERY FIGURElinks to the votes it countsNO RANKING, NO SCORE
Drawn for this register, not a screenshot
Entered
2026-10-01Live
First commit
2026-10-01Project docs and build plan
Commits
28on main, read 2026-10-02
Coverage
28%lines run by the ingest, web and protocol tests, read 2026-10-02
House packages
11 of 11installed from npm

What shipped

  1. Every public vote of every deputy, with the group they sat in on the day of the vote. No ranking and no score: every figure links to the votes it counts, and every page cites its official source.
  2. No server and no database: a nightly GitHub Actions job asks the Assemblée’s open data whether anything changed, rebuilds only what did and deploys. A night without a new vote downloads nothing and deploys nothing.
  3. The host publishes 20,000 files per deployment, and there are over 8,000 votes: they ship in blocks, one file per deputy, small indexes for lists and search, and the build checks its whole output against a budget.
  4. About 750 pages prerendered by the very loaders the browser runs, a fake fetch answering their data during the build, each with its own head tags and a place in the sitemap.
  5. Find your deputy from your commune or your address, in French, light and dark.

How it works

no server, a nightly job asks what changed

Diagram: every night a GitHub Actions job asks the Assemblée’s open data whether anything changed; a new vote rebuilds only what changed and deploys to Cloudflare Pages, a quiet night downloads and deploys nothingNightlyGitHub ActionsOpen dataanything changed?new voteRebuildonly what changedDeployCloudflare Pagesno new voteQuiet nightno download, no deploy20,000 files per deployment,8,000+ votes shipped in blocks,the output checked against a budget.

As the compiler reads it

Set the way an editor shows it: a wavy line is a build that refuses, a violet line is what the compiler works out on its own.

  1. source-version.ts
    Compiles0 errors
    export const isNewerVersion = ({
      cached,
      downloaded
    }: {
      cached: SourceValidators | null
      downloaded: SourceValidators
    }): boolean => {
      if (cached?.lastModified == null || downloaded.lastModified === null) {
        return true
      }
      return (
        Date.parse(downloaded.lastModified) >
        Date.parse(cached.lastModified)
      )
    }
    

History

Straight from the git log, abridged: 7 of 28 commits, newest first.

  1. Link scrutins to their legislative file from the files dataset
  2. Show who votes with whom on the compare page
  3. Find my deputy from a commune or an address
  4. Prerender pages with their head, sitemap and share card
  5. Nightly refresh and deploy workflow
  6. Ingest Assembly votes into datasets
  7. Project docs and build planFirst commit

Installs

11 of the 11 house packages, from npm, down to the compiler and linter settings.

Your team, 2026

I am looking for my next job. Write to me, or take the CV: a designed one, and a plain one for applicant tracking systems.