Personal project · 2025, revived 2026
Mock South Australian addresses, with the receipts.
Test data needs addresses that look right: a real suburb, the right postcode and council, a plausible spread across the city and the outback. This lab generates them, shows whether a sample actually hits its target mix, and documents exactly where every field comes from.
It began in August 2025 as a small Python CLI. The revival keeps that generator, fixes its data from ABS open sources, checks every sampling design over hundreds of seeds, and runs entirely in the browser with no API keys of its own.
Specimen sheet · seed 2025
population weighted
662 Halifax Street, MOUNT JAGGED SA 5211
MockAlexandrina · Inner Regional · IRSAD decile 6
542 Main Street, WEST LAKES SHORE SA 5020
MockCharles Sturt · Major Cities · IRSAD decile 8
385 Unley Road, HOPE VALLEY SA 5090
MockTea Tree Gully · Major Cities · IRSAD decile 5
392 Pirie Street, FINDON SA 5023
MockCharles Sturt · Major Cities · IRSAD decile 4
What's in the lab
- GenerateUp to 5,000 seeded addresses, filtered by suburb, council, remoteness or SEIFA decile, as text, JSON or CSV.
- Check the sampleRealised shares with 95% Wilson intervals, and an exact or chi-square test with its effect size against the target the design promises.
- Verification LabEvery address checked inside its own suburb against ABS boundaries, target mix with chi-square and confidence intervals, spatial spread, and same-seed reproducibility.
- Sampling designUniform, weighted and stratified designs over 200 seeds, exact and chi-square tests, a sample-size calculator, and spatial checks on every coordinate.
- MapAll 1,695 suburbs and localities on a free OpenFreeMap basemap, shaded by remoteness, SEIFA, or the 2025 table.
- LookupSearch a real place with Photon, then find its suburb, postcode, council and decile by point-in-polygon.
- 2025 replayThe original Python CLI ported to TypeScript, bugs included, printing the same bytes for the same seed.
- ProvenanceThe 2025 table against an ABS rebuild: what was missing, what agrees, and every source and licence.
- Methods and decisionsHow every claim is checked, the assumptions and limits, five decision records and a data card for the reference table.
- Describe a scenario (optional AI)Bring your own key: a model proposes generator settings, you review each change, and every call goes to an audit log you can export.
Field notes
What the 2025 version actually did
Porting the code line by line and testing it against recorded Python output surfaced four problems the original README did not mention. The replay keeps them; the generator fixes the data underneath.
Read the full provenance- 01
0 weights applied
The README promised remoteness and socio-economic weighting. The weights sat in config.py, but the import was commented out, so every suburb was equally likely.
- 02
1,894 / 1,894
rows had socio-economic status 0, so asking for level 1 to 5 matched nothing and silently fell back to the whole state.
- 03
997
rows had the remoteness level “Not Applicable”, more than half the table.
- 04
19
postcodes lost their leading zero, so AMATA printed as “SA 872” instead of 0872.
Key results
- 1,695
- South Australian suburbs and localities, each with a postcode, council, remoteness area and boundary
- 99.3%
- postcode agreement with the 2025 table where names match (1,682 of 1,694)
- 20/20
- recorded Python runs reproduced exactly by the TypeScript port, checked on every CI run
- 6 / 200
- seeds in which the weighted design's test rejects its target at 5% (95% CI 1.4% to 6.4%): calibrated, not lucky
About this project
Personal project, 2025
Written by Sunchuangyu (Rin) Huang in August 2025 as a small tool for generating South Australian test addresses, and revived in October 2026 as this site. It is not university coursework.
Provenance. The 2025 Python code, its data files and its README are preserved unchanged in the repository's original/ folder, with history intact. The website is a rewrite: its generator is a faithful port of that code, and its suburb data is rebuilt from ABS open data by the scripts in scripts/.
- Language
- 2025Python 3.8+
- 2026TypeScript (strict), Python only for data builds
- Interface
- 2025argparse CLI and a Python class
- 2026Next.js 16 static site, Web Worker generator
- Suburb data
- 20251,894-row CSV, source not recorded
- 2026ABS 2021 SAL, LGA, POA, RA, SEIFA (CC BY 4.0)
- Coordinates
- 2025Mapbox geocode of the suburb name (key needed)
- 2026Seeded point inside the ABS boundary (no key)
- Address lookup
- 2025Mapbox Geocoding v5 (key needed)
- 2026Photon via a cached route, local point-in-polygon
- Maps
- 2025None
- 2026MapLibre GL + OpenFreeMap, bundled outline fallback
- Statistics
- 2025None (the promised weights were never applied)
- 2026Wilson intervals, exact and chi-square tests, Cohen's w, replicate studies over fixed seeds
- AI
- 2025None
- 2026Optional, your own key: proposes settings for review, every call audit-logged
- Tests
- 2025None
- 2026Vitest parity tests against recorded Python output, SciPy reference values
| Aspect | 2025 original | 2026 revival |
|---|---|---|
| Language | Python 3.8+ | TypeScript (strict), Python only for data builds |
| Interface | argparse CLI and a Python class | Next.js 16 static site, Web Worker generator |
| Suburb data | 1,894-row CSV, source not recorded | ABS 2021 SAL, LGA, POA, RA, SEIFA (CC BY 4.0) |
| Coordinates | Mapbox geocode of the suburb name (key needed) | Seeded point inside the ABS boundary (no key) |
| Address lookup | Mapbox Geocoding v5 (key needed) | Photon via a cached route, local point-in-polygon |
| Maps | None | MapLibre GL + OpenFreeMap, bundled outline fallback |
| Statistics | None (the promised weights were never applied) | Wilson intervals, exact and chi-square tests, Cohen's w, replicate studies over fixed seeds |
| AI | None | Optional, your own key: proposes settings for review, every call audit-logged |
| Tests | None | Vitest parity tests against recorded Python output, SciPy reference values |