civic-data-spine.md

Sovereign Civic Data Spine

A sovereign Australian civic dashboard on an append-only, event-sourced spine — crime, planning applications, representatives, federal votes, and transport disruptions resolved to any Victorian suburb. Pointers are the product: it never adjudicates.

PythonPostgreSQLEvent sourcingAlembicDockerOpen civic data (VIC)Agent-swarm development639 tests

What it is

This turns Australia's scattered public data — crime statistics, development applications, parliamentary votes, representative records, transport disruptions — into one dashboard that answers a simple question: what is actually happening around this suburb? Each data domain is a self-contained pack on a shared, jurisdiction-agnostic spine; packs resolve to any Victorian suburb today, and the spine doesn't care which state comes next.

The design brief in one line: watch everything, touch nothing.

The front door today is the crime dossier: suburb-level incident trends over a decade of official data, with every line of copy deterministic — no model in the loop on anything a reader sees. The honesty problems it solves are the quiet kind: a year that fell 9% can still be the second-highest in a decade, and the dossier is built to say both.

The suburb crime dossier as served — Southbank, year ending March 2026: a decade of recorded offences, the honest 'Counts, not a rate' framing, and 'highest of 10 years' stated plainly. Product name blurred. The LGA choropleth — recorded-incident rate per 100k across Victoria, with a suburb panel of raw counts. Only the cleared official-records layer is shown; eval-gated sources blurred in the legend.

The rules

Most civic-data projects die by editorialising. Each rule here is enforced in code and locked in an append-only decision register:

  • No verdicts. No truth labels, no safe/dangerous ratings, no invented taxonomies. The dashboard points at sources; it doesn't referee them.
  • Un-doxxable by construction. No person-identifying fields exist in any schema. Locations geofuzz to street-cell minimum, and finer resolution is gated behind real k-anonymity density — not a policy, a serve-path precondition. This gate guards the incident-report packs, which stay eval-locked until launch clears them.
  • Append-only, event-sourced. State is derived from the event log, not stored. Even a takedown is an event, so the audit trail survives its own corrections. The crime dossier itself is a straight read over official aggregates — the event store carries the incident packs behind it.
  • Every record shows its tier. Lower tiers are structurally barred from feeding anything that looks like a score.
  • Sovereign front-end. Zero third-party requests, enforced by a matcher in the test suite. The page you read is served entirely by the machine you asked.
  • Licence gates as structure. Data sources with restrictive licences sit behind an eval-mode flag that a demo cannot casually flip.

How it's built

It is also an experiment in agent-swarm development with adversarial review. Every slice runs brainstorm → spec → a four-tier review of the spec itself (reviewer, devil's-advocate, security, test-isolation) → plan → fresh-agent TDD build → the same four tiers on the build. Findings either block the merge, land, or become named backlog items with explicit triggers — nothing is silently dropped. The repo carries a locked decision register, a security backlog with fire conditions, and 639 tests behind a single merge gate.

Status

639 tests, green in nine seconds (July 2026) — the spine is stable and the crime dossier is its front door. Underneath: all 79 Victorian LGAs validated against real ABS geometry, and 98.5% suburb join coverage — with the failing 1.5% degrading into an honest join-failed state rather than a silent wrong answer. Development is deliberately paused while effort goes to the claim-provenance engine; this project resumes when use reveals what deserves to be built next, not before.