Skip to main content

check-manifests.sh: the source-manifest schema gate

atlas-data/ingest/src/sources/check-manifests.sh is the CI gate that fails a PR if any per-source manifest.yml is shape-invalid, or if a manifest references a tags.topic or publisher that isn't declared in the companion YAML files.

It is the sibling of check-osmosis.sh (which gates dbt schema.yml column documentation). Non-overlapping scopes; both gates must be green to merge a PR touching source manifests.

This page covers what the gate enforces, when it runs, what failure looks like, and how to fix it.


What the gate enforces​

Two layers, both run by default:

1. Schema validation​

Each manifest.yml is validated against manifest.schema.json — a JSON Schema 2020-12 document covering required fields, types, enums, regex patterns, and URI format.

Catches:

  • Missing required fields (lifecycle, time_coverage, tags.topic, dimensions, …)
  • Wrong types (upstream_id: 07459 silently parses as integer 7459 — schema requires string; quoting forces preservation)
  • Invalid enum values (lifecycle: maintained — not in [stable, beta, deprecated, broken])
  • Malformed URLs in upstream_url / upstream_landing_page / feedback_url
  • Malformed periodicity (must match ISO 8601 duration or literal irregular)

2. Cross-file resolution​

Two further checks, separate from the per-manifest schema:

  • Every manifest's tags.topic must resolve to a topic id in topics.yaml.
  • Every manifest's publisher field must match a display_name in publishers.yaml.

These keep manifests consistent with the curated editorial files the catalog renders from.


When the gate runs​

  • Locally — run it before any commit touching atlas-data/ingest/src/sources/:

    cd atlas-data/ingest/src/sources
    ./check-manifests.sh

    Or via the npm script wrapper:

    cd atlas-data/ingest
    npm run sources:check-manifests
  • In CI — wired up as a required check on PRs and on push to main in .github/workflows/check-manifests.yml. Triggers only on changes to the manifests themselves, the schema, the validator, the companion files, or the workflow.


What failure looks like​

Schema failure​

→ schema check: 41 manifests under src/sources/
✗ ssb-07459/manifest.yml
/upstream_id: must be string
/: must have required property 'lifecycle'
...
✗ 1 schema failure(s), 0 cross-file failure(s)
exit=1

The error lines name the file and the JSONPath of the failing property. Most failures fall into:

  • Missing required field — open the manifest, add it. See adding-a-source.md § Step 4b for the v2 field reference.
  • Wrong type — usually upstream_id parsed as integer. Wrap the value in double quotes: upstream_id: "07459".
  • Bad enum — typo. Allowed values for lifecycle: stable | beta | deprecated | broken. Allowed values for eu_theme: the 13 DCAT-AP codes.

Cross-file failure​

→ cross-file checks
✗ 1 manifest(s) have tags.topic not in topics.yaml:
ssb-new-source/manifest.yml: topic 'demographics-and-housing'

The fix is one of:

  1. The topic was a typo — correct it in the manifest.
  2. The category genuinely doesn't exist yet — add an entry to topics.yaml with id, name, description, emoji, order. New categories are editorial choices — discuss in the PR.

Same pattern for publisher failures — either fix the typo in the manifest, or add an entry to publishers.yaml.


How to fix a failure​

Case A — you added a new source​

  1. After npm run sources:bootstrap-manifest -- <id>, fill in the v2 fields the bootstrap leaves empty (lifecycle, time_coverage, keywords). See adding-a-source.md § Step 4b.
  2. If the source is from a new publisher, add an entry to publishers.yaml + a placeholder logo SVG.
  3. If the source is in a new editorial category, add an entry to topics.yaml.
  4. Re-run ./check-manifests.sh.

Case B — you renamed a field or changed a value​

If the schema rejects a value you believe is correct, the schema is the contract — either fix the value or, if the schema is genuinely too strict for a legitimate case, propose a schema change in the same PR. Schema changes need maintainer review; per-source workarounds do not.

Case C — VS Code complains before you run the gate​

Add this to your workspace .vscode/settings.json to get hover docs + autocomplete on manifest fields:

{
"yaml.schemas": {
"atlas-data/ingest/src/sources/manifest.schema.json": "atlas-data/ingest/src/sources/*/manifest.yml"
}
}

Prerequisites​

  • Node ≥ 20.
  • Dependencies installed under atlas-data/ingest/ (npm ci).
  • The script uses ajv (JSON Schema validator), ajv-formats (URI format), and js-yaml (YAML parser), all declared in atlas-data/ingest/package.json.

Why a manifest gate matters​

The per-source manifest.yml is the editorial contract between Atlas's ingest team and every downstream consumer: mart_meta_sources, the dbt docs at /lineage/, the public datasets catalogue under /datasets/, and any future DCAT-AP-NO emitter for harvesting by data.norge.no.

Until this gate landed, manifest shape was conventional but unenforced — silent corruption was possible. The first run of this validator exposed 20 manifests whose upstream_id had silently lost a leading zero (07459 → integer 7459) and 6 manifests with empty / TODO upstream_landing_page values. Both bugs had been in production for months without anyone noticing.

At 200 sources, this kind of silent drift is not optional to catch.

See INVESTIGATE-sources-catalog-at-scale.md for the design rationale.


Cross-references​