Plan: Ingest Bufdir's Barnevern kommunemonitor
Ingests Bufdir's child-welfare (barnevern) kommune monitor as a new Atlas source, reusing the
bufdir-barnefattigdom ZIP-bulk-export pattern — adapted, not copied, because the two monitors'
workbooks are shaped differently (verified below).
IMPLEMENTATION RULES: Before implementing this plan, read and follow:
- WORKFLOW.md - The implementation process
- PLANS.md - Plan structure and best practices
Status: Completed
Completed: 2026-10-01
Goal: Add bufdir-barnevern as a served Atlas source, plugging the barnevern axis that Report
#2 (Child Welfare / Vulnerability Composite) is missing today.
Last Updated: 2026-10-01
Investigation: INVESTIGATE-new-norwegian-public-sources.md §Tier 1 #1 ([Q1]–[Q3])
Prerequisites: None. The "Phase 0 schema prep" this investigation originally pointed to was a
phantom (no provider enum, no dim_period/dim_indicator tables exist) — see the investigation's
2026-10-01 correction. bufdir is already a valid publishers.yaml provider (used by
bufdir-barnefattigdom), so no new publisher metadata is needed either.
Pattern reference: atlas-data/ingest/src/sources/bufdir-barnefattigdom/ (index.ts, parse.ts,
fetch_retry.ts). Adapt the shape of this module, not the literal code — Phase 1 below records
concrete, verified differences between the two monitors' ZIPs that make a byte-for-byte copy wrong.
Problem Summary
Atlas ingests Bufdir's Barnefattigdom (child-poverty) kommunemonitor but not its sibling Barnevern (child-welfare) kommunemonitor, even though both are published the same way, from the same CMS, and the investigation named this as the #1 gap-fill candidate five months ago. Today Report #2 (Child Welfare / Vulnerability Composite) has child low-income, persistent low-income, single-parent share, bullying, and overcrowded housing — but no barnevern axis at all: no measure of how many children are actually in contact with, or removed into, the child-welfare system. Bufdir's Barnevern monitor is the canonical kommune-level measurement for that axis.
Phase 1: Confirm the real shape — DONE (verified 2026-10-01, recorded here so it isn't re-derived)
The investigation's own description of this source ("machine-readable JSON... open data API") was
wrong — bufdir-barnefattigdom's own history (INVESTIGATE-bufdir-barnefattigdom-zip-ingest.md,
INVESTIGATE-bufdir-upstream-restructure.md) already corrected that to "ZIP bulk export of
Indikator_*.xlsx workbooks, discovered by scraping the monitor landing page." This phase checked
whether Barnevern follows the same mechanism and the same internal shape. It follows the
mechanism; it does not follow the same internal shape.
Tasks
-
1.1 Fetch the live monitor page (
https://www.bufdir.no/statistikk-og-analyse/monitor/barnevern/) and confirm it publishes a bulk ZIP the same way Barnefattigdom does. Confirmed —<title>Barnevern kommunemonitor | Bufdir</title>, same Strapi/Azure Container Apps CMS, canonical download link:https://ca-statistikk-strapi-prod.whitesea-89be7839.norwayeast.azurecontainerapps.io/uploads/Kommunemonitor_barnevern_2026_09_04_cedc894149.zip(Last-Modified: Fri, 04 Sep 2026,content-type: application/zip, 1,295,973 bytes). ⚠️ Filename shape differs from Barnefattigdom's. Barnefattigdom:YYYY_MM_DD_barnefattigdom_monitor_<hash>.zip. Barnevern:Kommunemonitor_barnevern_YYYY_MM_DD_<hash>.zip— different word order, different leading token.discoverZipUrl's four regex tiers inbufdir-barnefattigdom/parse.tsall require the literalbarnefattigdomsubstring (confirmed by reading the regexes directly); none would match a barnevern URL. This needs its own discovery function with its own four tiers matchingbarnevern/kommunemonitor_barnevern, not a parameterized reuse of the existing one — don't force a shared abstraction across two literal strings seen once each; copy the shape (progressive tiers,sole-uploadlast resort, loud failure on ambiguity) into a new, separate function. -
1.2 Download the live ZIP and inspect its contents. Confirmed — 24 workbooks, 1,435,207 bytes uncompressed:
1A_andel_ant_barn_tiltak_ilaaret_ialt_0_17.xlsx 1F_fosterhjem_i_familie_nære_nettverk.xlsx1B_barn_med_undersøkelse_ift_innbyggere_0_17.xlsx 2A_utgifter_per_barn_i_befolkningen.xlsx1C_barn_utenfor_hjemmet_ift_innbyggere_0_17.xlsx 2B..2F (utgifter-familien)1D_barn_med_hjelpetiltak...xlsx 3A, 3C, 3I, 3L, 3M (frister/bemanning/akutt)1E_barn_med_undersøkelse_el_tiltak_per_årsverk.xlsx 4A..4F (befolkning/sosioøkonomi)Turnover_kommunalt barnevern_2016-2024.xlsx (one non-conforming filename, has a space, no code prefix)⚠️ Filenames use an alphanumeric indicator code (
1A,1E,3M,4F, …), never the purely numericIndikator_<n>scheme Barnefattigdom uses. One of 24 files doesn't even carry a code (Turnover_kommunalt barnevern_2016-2024.xlsx) — it's the same indicator as3M_turnover_...xlsxwith a different (older?) year range; needs a decision in Phase 2 (dedupe against3M, or keep both and let a dbt test catch any disagreement). -
1.3 Inspect the internal workbook structure (sheet name, header row, columns) and compare to Barnefattigdom's
Datasheet /Region, Regionnavn, Enhet, Tallformat, <years>shape. Confirmed different, not a variant — genuinely different layout:- Sheet name is
Sheet1, notData(checked1A_...xlsx). The one non-conforming file (Turnover_...xlsx) has two sheets,InfoandTurnover saksbehandlere— a third shape again. - The header row is row 3, not row 1 — row 1 holds a single cell equal to the filename stem
(e.g.
1A_andel_ant_barn_tiltak_ilaaret_ialt_0_17), not a separate human-readable title sentence the way Barnefattigdom's row-1 title apparently is. There is no richer title string in the sheet to parse —indicator_titlefor Barnevern likely has to be a prettified version of the filename slug, at least for1A. Re-check 2–3 more files in Phase 2 before finalizing; don't assume this holds for all 24 on the strength of one file. - Columns:
Region | Regionnavn | Tallformat | <year columns 2015..2025>— noEnhetcolumn at all. Barnefattigdom'scategory_unitdimension (barn/husholdning) doesn't exist here, because Barnevern's indicators are already child-population rates, not paired child/household tuples.raw.bufdir_barnevernmust dropcategory_unitfrom its primary key and columns entirely — it is not "always null", it is not a column.
- Sheet name is
-
1.4 Before writing the parser, sample more workbooks across the numbered families to confirm the
Sheet1/ row-3-header / no-Enhetshape holds across the whole bundle, not just1A. Confirmed on2C_brutto_utgifter_...xlsx,3A_fristbrudd_...xlsx,4F_barn_med_bekymringsmelding_...xlsx: all four (including1A) areSheet1, row 1 = filename-stem title, row 3 = header, noEnhetcolumn.2C's shared-strings pool doesn't surfaceRegionnavn/Tallformatnear the front (it's dominated by a long run of region codes before those strings first appear), which looked like a possible wrinkle — checking2C's actual<row r="3">cells directly (not the string pool order) resolved it: sameRegion | Regionnavn | Tallformat | <years>header as the other three. The shape holds across all four samples spanning1*–4*.
Validation
✅ Confirmed 2026-10-01 — four sampled workbooks across 1*–4* all share the same shape
(Sheet1, row-3 header, Region | Regionnavn | Tallformat | <years>, no Enhet). Phase 1 is DONE.
Phase 2: Ingest module + raw table — DONE
⚠️ Caught during this phase's own live validation, not by the plan's Phase 1 research: every
standard workbook's Tallformat column uses the literal value Andel for decimal-formatted
figures, not the sibling Barnefattigdom source's Prosent. A first draft copied the sibling's
prosent check without re-verifying it against Barnevern's own data; running the real ingest
against the live ZIP (not just the unit tests) showed 9 of 23 workbooks returning zero rows
and the rest returning roughly half their true row count — 70,899 rows instead of the correct
191,673. Fixed by checking for andel instead of prosent throughout parse.ts. Also: andel
is not limited to 0–100 percentages — some andel-formatted indicators are kroner-per-child
figures, so it means "Norwegian-decimal formatted", not "is a percentage". See parse.ts's
parseCell doc and the manifest's category_format dimension note.
Also added during this phase, not originally listed in the task breakdown below: Dagster asset
registration (atlas-data/dagster/atlas_data/assets/raw_other.py and schedules.py's
_ANNUAL_SOURCE_IDS). Required by the standing "every ingested source appears in a scheduling
grouping or cadence.UNSCHEDULED_SOURCES" invariant (schedules.py's own comment) — without it,
bufdir-barnevern would need a human to trigger it by hand, exactly the failure mode
PLAN-zero-touch-ingest-automation (#1793) fixed for every other source this session.
⚠️ CI caught three more generated-artifact drift gates on first push (PR #489), none anticipated by the task list — recorded so the next new-source PLAN budgets for them:
tags.topic: child-welfareisn't a registered category —atlas-data/ingest/src/sources/topics.yamlis a short, curated, editorially-maintained list (check-manifests.sh+ the website'sgenerate-sources-registry.mjsboth enforce it), not free text. Changed totopic: social("the bridge between need and the services that respond to it" — the existing category description already fits barnevern without adding a new one for a single source).atlas-data/dbt/seeds/sources/_sources_manifest.csv/_sources_dimensions.csvare generated from everymanifest.ymlbyscripts/build_sources_seed.pyand must be regenerated and committed in the same PR as any manifest change —check-sources-seed-is-current.shdiffs the committed seed against a fresh regeneration. Ran it; committed the regenerated seed.atlas-data/template-info.yaml'sfirst_data.takes/first_data.first_loadstate the raw-table count in prose ("~4.1M rows across 52 raw BASE TABLEs...") andrender-template-info.shchecks that number againstgrep -c 'create table raw\.'acrossmigrations/*.sql. Bumped52→53in both occurrences — the row-count/timing narrative around it is a real prior measurement (urb-agents #1027) and was left untouched; only the table-count fact changed.
Tasks
-
2.1 Create
atlas-data/ingest/src/sources/bufdir-barnevern/:fetch_retry.ts— copy verbatim frombufdir-barnefattigdom(generic retry wrapper, no barnefattigdom-specific logic; the file's own header already notes this pattern is duplicated per-source rather than shared, so a fourth copy matches existing convention).parse.ts— new file, same shape as the sibling (discoverZipUrl-equivalent,surrogateIndicatorApiId-equivalent, sheet parser), different literals:- Discovery tiers match
barnevern/kommunemonitor_barnevern, notbarnefattigdom. - Surrogate id:
/^(\d+[a-z])_/icaptures the1a/3m-style code →bv_zip_ind_<code>(e.g.bv_zip_ind_1a). Hash fallback (bv_zip_<sha256-24>) for the one non-conformingTurnover_...xlsxfilename, same defensive shape as the sibling's hash-fallback tier — do not hardcode a special case for that one file. Use abv_prefix, notbf_, so the two sources' surrogate ids are visibly distinguishable inraw/marts even though a collision is already unlikely (Barnevern's codes are inherently alphanumeric, Barnefattigdom's are purely numeric). - Sheet reader targets
Sheet1at header row 3 (confirmed in Phase 1), noEnhet/category_unitcolumn to unpivot.
- Discovery tiers match
index.ts— adapted from the sibling's orchestration (fetch monitor page →discoverZipUrl→ download → extract → parse each workbook → upsertraw.bufdir_barnevern), samematchTier !== "canonical"warn-log pattern.manifest.yml— hand-authored, matching the sibling's style:source_id: bufdir-barnevernupstream_id: barnevern-monitorupstream_url: https://www.bufdir.no/statistikk-og-analyse/monitor/barnevern/upstream_landing_page: https://www.bufdir.no/statistikk-og-analyse/monitor/barnevern/upstream_title: "Barnevern kommunemonitor"publisher: Barne-, ungdoms- og familiedirektoratetlicense: NLODlicense_url: https://data.norge.no/nlod/no/2.0periodicity: P1Yeu_theme: SOCItags:provider: bufdirtopic: socialgeo: kommunecadence: annualsuggested_joins:- bufdir-barnefattigdomdimensions:block uses the final confirmed column set:indicator_api_id,region_code,category_format(Tallformat — valuesantall/andel, nocategory_unit),year,values_json.README.md— written, matching sibling's structure, documenting theandelvocabulary finding.__tests__/— 33 tests: discovery tiers (barnevern URL shapes, ambiguous-ZIP refusal),isStandardIndicatorWorkbookfilter,parseCell(including theandel-is-not-always-a- percentage case), surrogate id, and an end-to-end parse of the real1Afixture plus a test that the non-conformingTurnoverfixture throws rather than silently mis-parsing.- Also registered in
atlas-data/ingest/package.json(ingest:bufdir-barnevernscript) and in the Dagster asset groupings (see Phase 2 header note above) — not originally itemized here.
-
2.2
atlas-data/migrations/056_raw_bufdir_barnevern.sql—create table raw.bufdir_barnevernwith primary key(indicator_api_id, region_code, category_format, year)(nocategory_unit— see Phase 1.3), pluscomment on table/columnwritten fresh for the actual Barnevern shape (including theandelvocabulary note) rather than copied from the sibling's slightly-stale comments.
Validation
cd atlas-data/ingest && npm test -- bufdir-barnevern # 33 passed
cd atlas-data/ingest && npm test # 181 passed, whole package — no regressions
cd atlas-data/ingest && npm run typecheck # clean
env -u DATABASE_URL node_modules/.bin/tsx src/sources/bufdir-barnevern/index.ts # live run, NDJSON-only
✅ Done 2026-10-01. Live run against the real upstream ZIP: 23 workbooks, 0 workbook.no_rows
warnings, 191,673 rows, 489 distinct region codes. (First live run, before the andel fix, produced
70,899 rows with 9 workbooks at zero — exactly the "zero rows silently dropped" failure mode this
validation step exists to catch; not caught by the unit tests alone, only by running the real
ingest.) Needs Node ≥22 (engines in package.json) — Node 20.11 fails at vitest startup
(styleText not exported from node:util).
Phase 3: dbt staging and marts — DONE
⚠️ A second real defect caught by building against real ingested data, not an empty schema —
the same class of bug as Phase 2's andel/prosent miss, one layer deeper: the bare
region_code ~ '^[0-9]{4}$' / '^[0-9]{2}$' pattern (copied from the sibling model, matching its
current code) calls Svalbard a kommune/fylke. Barnevern's own ZIP carries a Svalbard placeholder
row at BOTH levels — region_code = '2111' (4-digit, 394 rows) and a bare '21' (2-digit, 394
rows), every value null across all 23 indicators. This is exactly the defect
macros/classify_region_code.sql was built to fix (urb-agents #700) — confirmed live, not
inferred, via a local Postgres loaded with the real 191,673-row ingest. Fixed kommune_nr via the
existing region_code_to_kommune_nr macro and added a region_kind column (matching the
established indicators__ssb_07459.sql convention). fylke_nr needed a narrow, local exclusion
of region_code = '21' instead — classify_region_code's own fylke branch is a bare
^\d{2}$ catch-all with the identical latent gap, but fixing that macro site-wide is a bigger
blast radius than this PLAN's scope; noted in the model's own comment for whoever investigates
the macro next.
Tasks
- 3.1 Added
raw.bufdir_barneverntoatlas-data/dbt/models/indicators/sources.yml. - 3.2
atlas-data/dbt/models/indicators/indicators__bufdir_barnevern.sql— same shape asindicators__bufdir_barnefattigdom.sql, minuscategory_unit, using'bv_' || indicator_slug || '__' || category_formatforcontents_code.kommune_nrgoes throughregion_code_to_kommune_nr, not a bare regex (see defect note above);region_kindadded. - 3.3 Documented the model's columns in
atlas-data/dbt/models/indicators/schema.yml— rancheck-osmosis.shagainst a local throwaway Postgres (initdb, TCP, short/tmpsocket path — the scratchpad directory's own path was too long for a unix socket) withraw.bufdir_barnevernactually loaded via the real ingest. All columns documented, 566 total in that file. - 3.4
atlas-data/dbt/models/marts/api/mart_indicators__bufdir_barnevern.sql— api passthrough, mirroring the sibling. Documented inatlas-data/dbt/models/marts/api/schema.yml. - 3.5
dbt buildagainst the real loaded data: 1 table model, 21 data tests, 1 view model, all green (23/23) after theregion_kind/fylke_nrfix.
Also regenerated, not originally itemized: api_v1_generated.sql / api_v1_state.json
(regenerate-api-v1.sh), lineage.csv / lineage_direct.csv (extract_lineage.py),
api_v1_relations.csv, the website's sources-registry.json and new per-view dataset page, and
template-info.yaml's raw/marts table-count prose (53 raw / 83 marts tables / 69 marts views —
each bumped and re-verified via render-template-info.sh and generate-holdings.py --check).
Validation
cd atlas-data/dbt && dbt build --select indicators__bufdir_barnevern mart_indicators__bufdir_barnevern
# against a local Postgres loaded via: npm run migrate && tsx src/sources/bufdir-barnevern/index.ts
✅ Done 2026-10-01. 23/23 pass against 191,673 real rows (not an empty schema — an empty build
passes checks that prove nothing, per [[ci-builds-from-empty-so-state-defects-are-invisible]]).
check-osmosis.sh, check-api-v1.sh, check-lineage-is-current.sh,
check-every-source-is-served.sh, check-sources-seed-is-current.sh, check-manifests.sh,
render-template-info.sh, and generate-holdings.py --check all green.
Phase 4: Catalogue, deploy, and verify arrival — DONE
Tasks
- 4.1 Website catalogue already regenerated as part of Phase 2/3's artifact fixes (
44 sources, 9 publishers—bufdir-barnevernscoped under the existingbufdirpublisher, no new publisher work needed). - 4.2
atlas-data/dbt/check-every-source-is-served.shpasses locally (44 sources, 0 exempt, 0 deferred) — confirmed as part of Phase 3's validation, re-confirmed after merge. - 4.3 Filed the deploy request — not a
~/homefile (this project's actual convention, per the bus history: cluster-deploy/verification requests go to imac, who operates the live cluster, not afor-ops-*.mddrop orops-dev). Sent viaurb send --to imac --from atlas --context atlas, filed as urb-agents#1796. Named the exact relations (raw.bufdir_barnevern,api_v1.indicators__bufdir_barnevern/mart_indicators__bufdir_barnevern), the code-location image digest (ghcr.io/terchris/atlas-data:v20261001-1b16c96,sha256:c8fb9ce64920ebb1e58b5564019f238bf972690cd09faab48292b60c44caf9de, labelled as the code-location digest, not a UIS install-artifact digest — don't have one of those from here), the derivedLANDS WITH(annual_sources_refreshthentransform_and_publish—atlas-data/uis/lands-with.sh 8cbcb84..1b16c96), and an expected row count (191,673, stated explicitly as a prediction to be measured, not a certainty — Bufdir could republish the bundle between my local fetch and imac's run, as the sibling source already has once). Also flagged:weekly_polled()'sAutomationCondition.on_cronwon't self-materialize a brand-new asset before the next Sunday 02:00 tick, so the refresh needs triggering deliberately if this should land sooner. - 4.4 Verified arrival, 2026-10-01 — not just imac's green run report, independently re-checked
against the live public API myself before closing the task:
191,673 rows — an exact match to both this plan's own local prediction and imac's independent cluster-side measurement. No upstream drift between the local validation run and the live deploy. imac also confirmed no regression elsewhere (GET /meta_sources?source_id=eq.bufdir-barnevern&select=served_as-> [{"served_as":["indicators__bufdir_barnevern"]}]GET /indicators__bufdir_barnevern?limit=1-> 200, a real row (bv_zip_ind_1a, region_kind "nasjon", category_format "andel",full 2015-2025 values_json spine)HEAD with Prefer: count=exact-> content-range: 0-0/191673, cf-cache-status: BYPASS (not a stale cached read)
bufdir-barnefattigdom81,568 rows unchanged; FHI sources unchanged) and caught one more naming gotcha worth keeping: the public API servesindicators__bufdir_barnevern, notmart_indicators__bufdir_barnevern— themart_prefix is amarts-schema internal naming convention, not part of the publishedapi_v1view name (the same mistake was made once before onbrreg_enhet). Full exchange: urb-agents#1796, closedcompleted.
Validation
✅ Done 2026-10-01, verified independently, not taken on trust. Live curl against the public API
returns real Barnevern rows through indicators__bufdir_barnevern (191,673, confirmed via
Content-Range, not a cached response), and meta_sources.served_as for bufdir-barnevern is
non-empty.
Outcome
Shipped end to end, 2026-10-01: ingest (23 workbooks, 191,673 rows, zero dropped) → dbt staging and
api_v1 publication → live cluster deploy → independently verified arrival. Two real data defects
were caught by validating against real ingested data at each phase rather than an empty schema or a
green CI run — the andel/prosent vocabulary mismatch (Phase 2) and the Svalbard-as-kommune/fylke
misclassification (Phase 3) — both documented in place rather than only in this plan, so a future
reader of the code finds them without needing this file. bufdir-barnevern plugs the barnevern axis
Report #2 (Child Welfare / Vulnerability Composite) was missing.
Acceptance Criteria
-
bufdir-barneverningests cleanly from the live ZIP with zero rows silently dropped — 23 workbooks, 191,673 rows, verified by running the real ingest, not just unit tests. -
raw.bufdir_barneverncorrectly has nocategory_unitcolumn (verified against Phase 1's finding, not assumed). -
indicators__bufdir_barnevernandmart_indicators__bufdir_barnevernbuild and test clean (23/23 data tests, against real loaded data). -
bufdir-barnevernappears inmeta_sources.served_asafter a real deploy, with rows confirmed via a livecurl, not inferred from CI. Deployed by imac (urb-agents#1796), verified independently by this agent against the live public API: 191,673 rows, non-emptyserved_as. - Golden-file tests cover both the
1A-style shape and theTurnover_...outlier shape (33 tests total, including an end-to-end parse of the real1Afixture). - The investigation (
INVESTIGATE-new-norwegian-public-sources.md) and1PRIORITY.mdare updated to mark this candidate shipped, same as the other three corrections made 2026-10-01.
Implementation Notes
- Don't force a shared discovery/surrogate-id module across the two Bufdir sources. Each has exactly one literal string to match; a shared parameterized function buys nothing two separate, readable functions don't, and couples two sources' deploy risk together for no reason.
- The
Turnover_kommunalt barnevern_2016-2024.xlsxvs3M_turnover_saksbehandlere.xlsxoverlap is the one real open modelling question this plan doesn't resolve ahead of time — Phase 2's completeness check (mirroring what PR #67 did for the sibling) is where to decide whether they're duplicates, a methodology revision, or genuinely different year ranges worth keeping both. - Do not assume Phase 1's
1Afindings hold for all 24 workbooks. Task 1.4 is unchecked for a reason — this plan's own confidence in the raw-table shape is bounded by two sampled files out of twenty-four, which is exactly the "scattered sampling misses clustered failures" risk this project has been burned by before. Finish 1.4 before writing the migration DDL.
Files to Modify
atlas-data/ingest/src/sources/bufdir-barnevern/manifest.yml(new)atlas-data/ingest/src/sources/bufdir-barnevern/index.ts(new)atlas-data/ingest/src/sources/bufdir-barnevern/parse.ts(new)atlas-data/ingest/src/sources/bufdir-barnevern/fetch_retry.ts(new, copied)atlas-data/ingest/src/sources/bufdir-barnevern/README.md(new)atlas-data/ingest/src/sources/bufdir-barnevern/__tests__/(new)atlas-data/migrations/056_raw_bufdir_barnevern.sql(new)atlas-data/ingest/package.json(ingest:bufdir-barnevernscript)atlas-data/dagster/atlas_data/assets/raw_other.py(asset registration, weekly-polled cadence)atlas-data/dagster/atlas_data/schedules.py(_ANNUAL_SOURCE_IDS)atlas-data/dbt/models/indicators/sources.ymlatlas-data/dbt/models/indicators/indicators__bufdir_barnevern.sql(new)atlas-data/dbt/models/indicators/schema.ymlatlas-data/dbt/models/marts/api/mart_indicators__bufdir_barnevern.sql(new)atlas-data/dbt/models/marts/api/schema.ymlatlas-data/dbt/api_v1_generated.sql,atlas-data/dbt/api_v1_state.json(regenerated)atlas-data/dbt/seeds/sources/lineage.csv,lineage_direct.csv,api_v1_relations.csv(regenerated)atlas-data/template-info.yaml(raw/marts table counts),website/docs/developers/index.md(regenerated)website/src/data/sources-registry.json,website/docs/datasets/indicators__bufdir_barnevern.mdx(regenerated)website/docs/ai-developer/plans/backlog/INVESTIGATE-new-norwegian-public-sources.md(mark shipped)website/docs/ai-developer/plans/backlog/1PRIORITY.md(mark shipped)