Your raw_billing source is already declared in sources.yml and models select from it, but dbt source freshness reports nothing for it. The project runs on Postgres, and the vendor stamps every row with synced_at. Arrange the steps to get a freshness state reported for the table, and to read what it measured. Two steps in the pool do not belong.
In the exam you drag the steps into order. The correct sequence is below.
- 1Under the raw_billing table's config: block, set loaded_at_field: synced_at and a freshness block with warn_after 12 hours and error_after 24 hours.
- 2Run dbt source freshness.
- 3Open target/sources.json and read the table's max_loaded_at and its status.
- Run dbt build --select source:raw_billing+ so dbt reloads the vendor table before it is measured.
- Run dbt compile to write the freshness result to target/sources.json.
WHY
Freshness is opt-in per source, and on Postgres it needs both halves of the config before anything can be measured. loaded_at_field is "Optional on adapters that support pulling freshness from warehouse metadata tables, required otherwise" — Postgres is not one of those adapters, so dbt has no timestamp column to measure without it. And the thresholds are what turn a timestamp into a verdict: "If neither is provided, then dbt will not calculate freshness for the tables in this source." Both live as sibling keys under the table's config: block, so they are one edit, not two ordered ones (s2). Running the command comes next and is genuinely separate work: dbt queries the table for the maximum loaded_at_field value and compares its age against the criteria (s4). Before the config exists there is nothing to calculate, which is exactly the state the question opens in — the command already runs today and reports nothing. Reading the artifact is last because the artifact does not exist until the command has run: "When dbt source freshness completes, a JSON file containing information about the freshness of your sources will be saved to target/sources.json", and sources.json is documented as produced by source freshness. It carries max_loaded_at ("Max value of loaded_at_field timestamp in the source table when queried"), snapshotted_at, and status — "one of pass, warn, or error" (s5). That is where the number behind the CLI verdict lives.
WHY THE OTHERS ARE WRONG
- Run dbt build --select source:raw_billing+ so dbt reloads the vendor table before it is measured.
- dbt does not load source data. A source is a declaration pointing at a table some other process populates — here the vendor's — so there is nothing for dbt to "reload" and no dbt command that refreshes the rows. dbt build --select source:raw_billing+ builds the MODELS downstream of the source, which changes nothing about the source table's own max synced_at and so cannot change its freshness state. Source: https://docs.getdbt.com/docs/build/sources
- Run dbt compile to write the freshness result to target/sources.json.
- dbt compile does not check freshness and does not write this artifact. sources.json is documented as produced by source freshness, and the freshness docs are specific that it appears "when dbt source freshness completes". compile renders model SQL into target/; it never queries the source for its maximum timestamp. Sources: https://docs.getdbt.com/reference/artifacts/sources-json · https://docs.getdbt.com/reference/commands/source