Amends decision #8: the producer now lives in tools/fest_flatten.py (stdlib Python, streaming iterparse over the 115 MB M30 XML) instead of an out-of-repo server job. It pulls fest251.zip from dmp.no, flattens 8934 active human-use brand entries (name/strength/unit/form/ATC + modal package size from pakningsinfo), and writes the asset checked in at app/src/main/assets/fest/slim.json — so autocomplete works offline out of the box. preReleaseBuild depends on refreshFestData: fast-exits under 30 days, keeps the old file on download failure (offline release builds never break). FestRepository: downloaded cache wins over the bundled asset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2.1 KiB
FEST slim dataset — contract
The app does offline autocomplete against a slim, pre-flattened JSON file.
The producer is tools/fest_flatten.py in this repo: it downloads FEST's open
Rekvirent extract (the M30 XML dump, fest251.zip from dmp.no), flattens the
human-use brand entries, and writes app/src/main/assets/fest/slim.json,
which is checked in and bundled in the APK — autocomplete works out of the
box with zero configuration.
Release builds run the script automatically (preReleaseBuild →
refreshFestData): it regenerates when the bundled file is >30 days old,
fast-exits when fresh, and keeps the old file if the download fails, so an
offline release build never breaks. Manual run:
python3 tools/fest_flatten.py --out app/src/main/assets/fest/slim.json --force.
Why FEST and not Felleskatalogen: FEST is the open national dataset; Felleskatalogen is licensed editorial content with no open API. Why not live lookups: M30 is a bulk XML dump, not a per-keystroke API — and the phone must work offline.
Where the app loads it from
Bundled asset fest/slim.json by default. Optionally, Innstillinger → FEST-URL downloads a newer file to filesDir/fest-slim.json, which then
wins over the bundle. Old data keeps working — autocomplete is a convenience,
never a gate.
JSON shape (version 1)
{
"version": 1,
"updated": "2026-06-01",
"entries": [
{
"name": "Paracet",
"strength": "500 mg",
"unit": "tablett",
"form": "tablett",
"atc": "N02BE01",
"packageSize": 20.0
}
]
}
name— preparation name (varenavn), required.strength— display string, may be empty.unit— what one dose counts ("tablett", "ml", "dose"), required.form— FEST's form text, free-form (not this app's MedForm enum; the editor maps it heuristically and lets the user override).atc— ATC code, optional.packageSize— units per package for the most common package, optional.
Unknown extra keys are ignored (ignoreUnknownKeys), so the producer can add
fields without breaking older app versions. Bump version only for breaking
changes.