diff --git a/changelog.d/nz-qes-prefu-earnings.added.md b/changelog.d/nz-qes-prefu-earnings.added.md new file mode 100644 index 00000000..7b965a67 --- /dev/null +++ b/changelog.d/nz-qes-prefu-earnings.added.md @@ -0,0 +1,6 @@ +Add 26 Stats NZ QES all-sector ordinary-time and total weekly earnings levels +per FTE for June 2023–June 2026, with exact workbook-vintage ownership, and +seven Treasury PREFU 2026 published ordinary-time earnings growth assumptions +for years ending June 2025–2031. Preserve the 2026 Forecast4 header and its +footnote-qualified actual status; 2027–2031 are publisher projections. Include +receipt-pinned artifacts, provenance, licences, labels and drift regressions. diff --git a/chronicle/bundle.py b/chronicle/bundle.py index 96224cc1..f4b98c6b 100644 --- a/chronicle/bundle.py +++ b/chronicle/bundle.py @@ -397,10 +397,13 @@ "stats-nz-census-2023-weekly-rent-rc-18", "stats-nz-census-2023-weekly-rent-rc-99", "stats-nz-household-net-worth-2024", + "stats-nz-qes-average-weekly-earnings-june-2025", + "stats-nz-qes-average-weekly-earnings-june-2026", "stats-nz-subnational-population-estimates-2025", "stats-nz-subnational-population-ta-2025", "treasury-an24-01-fiscal-totals", "treasury-estimates-of-appropriations-2026-27", + "treasury-prefu26-economic-assumptions", ) BUNDLE_SUITES = ("nz", "uk") diff --git a/chronicle/source_package.py b/chronicle/source_package.py index 89def304..362fccee 100644 --- a/chronicle/source_package.py +++ b/chronicle/source_package.py @@ -243,6 +243,12 @@ "stats-nz-census-2023-households-by-region-rc-99": Path( "stats_nz/census_2023_households_by_region/rc_99" ), + "stats-nz-qes-average-weekly-earnings-june-2025": Path( + "stats_nz/qes_average_weekly_earnings_june_2025" + ), + "stats-nz-qes-average-weekly-earnings-june-2026": Path( + "stats_nz/qes_average_weekly_earnings_june_2026" + ), "stats-nz-subnational-population-estimates-2025": Path( "stats_nz/subnational_population_estimates_2025" ), @@ -622,6 +628,9 @@ "msd-annual-report-benefit-expenses-2025": Path( "msd/annual_report_benefit_expenses_2025" ), + "treasury-prefu26-economic-assumptions": Path( + "treasury/prefu26_economic_assumptions" + ), "treasury-an24-01-fiscal-totals": Path("treasury/an24_01_fiscal_totals"), "treasury-estimates-of-appropriations-2026-27": Path( "treasury/estimates_of_appropriations_2026_27" diff --git a/db/data/stats_nz/qes_average_weekly_earnings_june_2025/manifest.yaml b/db/data/stats_nz/qes_average_weekly_earnings_june_2025/manifest.yaml new file mode 100644 index 00000000..4ace961f --- /dev/null +++ b/db/data/stats_nz/qes_average_weekly_earnings_june_2025/manifest.yaml @@ -0,0 +1,23 @@ +source_id: stats_nz +package_id: qes_average_weekly_earnings_june_2025 +dataset: stats_nz_qes_average_weekly_earnings_june_2025 +source_page: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ +table: 'Table 7: Average weekly earnings for FTEs, by sector' +license: + name: Creative Commons Attribution 4.0 International + url: https://creativecommons.org/licenses/by/4.0/ + evidence_url: https://www.stats.govt.nz/about-us/copyright/ + notes: Licence attribution supplied by the hub; unchanged publisher workbook. +files: + 2025: + filename: quarterly-employment-survey-june-2025-quarter.xlsx + source_url: https://www.stats.govt.nz/assets/Uploads/Labour-market-statistics/Labour-market-statistics-June-2025-quarter/Download-data/quarterly-employment-survey-june-2025-quarter.xlsx + sha256: 25053dcbd343320cad72e2896475eaebaf5f5bb0b5965ca788506ca15efcea30 + size_bytes: 135784 + fetched_at: '2026-10-22T07:57:28Z' + storage: + r2: + provider: r2 + bucket: ledger-raw + key: raw/nz/stats_nz/qes_average_weekly_earnings_june_2025/2025/25053dcbd343320cad72e2896475eaebaf5f5bb0b5965ca788506ca15efcea30/quarterly-employment-survey-june-2025-quarter.xlsx + uri: r2://ledger-raw/raw/nz/stats_nz/qes_average_weekly_earnings_june_2025/2025/25053dcbd343320cad72e2896475eaebaf5f5bb0b5965ca788506ca15efcea30/quarterly-employment-survey-june-2025-quarter.xlsx diff --git a/db/data/stats_nz/qes_average_weekly_earnings_june_2025/quarterly-employment-survey-june-2025-quarter.xlsx b/db/data/stats_nz/qes_average_weekly_earnings_june_2025/quarterly-employment-survey-june-2025-quarter.xlsx new file mode 100644 index 00000000..0e35d279 Binary files /dev/null and b/db/data/stats_nz/qes_average_weekly_earnings_june_2025/quarterly-employment-survey-june-2025-quarter.xlsx differ diff --git a/db/data/stats_nz/qes_average_weekly_earnings_june_2026/manifest.yaml b/db/data/stats_nz/qes_average_weekly_earnings_june_2026/manifest.yaml new file mode 100644 index 00000000..fef558fb --- /dev/null +++ b/db/data/stats_nz/qes_average_weekly_earnings_june_2026/manifest.yaml @@ -0,0 +1,23 @@ +source_id: stats_nz +package_id: qes_average_weekly_earnings_june_2026 +dataset: stats_nz_qes_average_weekly_earnings_june_2026 +source_page: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ +table: 'Table 7: Average weekly earnings for FTEs, by sector' +license: + name: Creative Commons Attribution 4.0 International + url: https://creativecommons.org/licenses/by/4.0/ + evidence_url: https://www.stats.govt.nz/about-us/copyright/ + notes: Licence attribution supplied by the hub; unchanged publisher workbook. +files: + 2026: + filename: quarterly-employment-survey-june-2026-quarter.xlsx + source_url: https://www.stats.govt.nz/assets/Uploads/Labour-market-statistics/Labour-market-statistics-June-2026-quarter/Download-data/quarterly-employment-survey-june-2026-quarter.xlsx + sha256: 1af2e7e37f1c108a2656842cf1f519c903e1a982bcdc03ee02d0ad888ebc3a97 + size_bytes: 124556 + fetched_at: '2026-10-22T07:57:28Z' + storage: + r2: + provider: r2 + bucket: ledger-raw + key: raw/nz/stats_nz/qes_average_weekly_earnings_june_2026/2026/1af2e7e37f1c108a2656842cf1f519c903e1a982bcdc03ee02d0ad888ebc3a97/quarterly-employment-survey-june-2026-quarter.xlsx + uri: r2://ledger-raw/raw/nz/stats_nz/qes_average_weekly_earnings_june_2026/2026/1af2e7e37f1c108a2656842cf1f519c903e1a982bcdc03ee02d0ad888ebc3a97/quarterly-employment-survey-june-2026-quarter.xlsx diff --git a/db/data/stats_nz/qes_average_weekly_earnings_june_2026/quarterly-employment-survey-june-2026-quarter.xlsx b/db/data/stats_nz/qes_average_weekly_earnings_june_2026/quarterly-employment-survey-june-2026-quarter.xlsx new file mode 100644 index 00000000..601ba6f1 Binary files /dev/null and b/db/data/stats_nz/qes_average_weekly_earnings_june_2026/quarterly-employment-survey-june-2026-quarter.xlsx differ diff --git a/db/data/treasury/prefu26_economic_assumptions/manifest.yaml b/db/data/treasury/prefu26_economic_assumptions/manifest.yaml new file mode 100644 index 00000000..807a25bf --- /dev/null +++ b/db/data/treasury/prefu26_economic_assumptions/manifest.yaml @@ -0,0 +1,28 @@ +source_id: treasury +package_id: treasury-prefu26-economic-assumptions +dataset: prefu26_economic_assumptions +source_page: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 +table: PREFU 2026 Table 4.1 - Key economic assumptions for fiscal forecasts +published_at: '2026-09-29' +license: CC BY 4.0 +license_url: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 +attribution: The Crown (New Zealand Treasury); written attribution, no reproduction of emblems, logos + or Coat of Arms. +license_evidence: Publication page (hub supplied); workbook Index!A13:A14 explicitly records CC BY 4.0 + and Crown attribution. +notes: Original workbook bytes copied from the hub staging receipt unchanged. Declared R2 object is uploaded + by the hub before merge. Index and Table 4.1 used ranges are parsed; other sheets remain in the preserved + workbook and emit no facts. +files: + 2026: + filename: prefu26-charts-data.xlsx + source_url: https://www.treasury.govt.nz/sites/default/files/2026-09/prefu26-charts-data.xlsx + sha256: e2486375dde515d0722f8c3022f481804bb014beb83c81b8bfc99bc9426544d9 + size_bytes: 664670 + fetched_at: '2026-10-22T07:57:29Z' + storage: + r2: + provider: r2 + bucket: ledger-raw + key: raw/nz/treasury/treasury-prefu26-economic-assumptions/2026/e2486375dde515d0722f8c3022f481804bb014beb83c81b8bfc99bc9426544d9/prefu26-charts-data.xlsx + uri: r2://ledger-raw/raw/nz/treasury/treasury-prefu26-economic-assumptions/2026/e2486375dde515d0722f8c3022f481804bb014beb83c81b8bfc99bc9426544d9/prefu26-charts-data.xlsx diff --git a/db/data/treasury/prefu26_economic_assumptions/prefu26-charts-data.xlsx b/db/data/treasury/prefu26_economic_assumptions/prefu26-charts-data.xlsx new file mode 100644 index 00000000..c44f6e19 Binary files /dev/null and b/db/data/treasury/prefu26_economic_assumptions/prefu26-charts-data.xlsx differ diff --git a/docs/pe-nz-source-checklist.md b/docs/pe-nz-source-checklist.md index 2bed5172..223133e1 100644 --- a/docs/pe-nz-source-checklist.md +++ b/docs/pe-nz-source-checklist.md @@ -69,7 +69,8 @@ tests, and record a verified `raw/nz/...` R2 URI. | `msd/nzs_vp_fact_sheet_june_2026` | [x] | [x] | [x] | Row 12: 46 June 2026 NZS/VP recipient count facts, including published additional-support and demographic cuts. Raw artifact published to its `raw/nz/msd/...` key and verified by SHA-256 on 2026-10-07. | | `msd/annual_report_benefit_expenses_2025` | [x] | [x] | [x] | Row 13: 11 actual FY2024/25 expense facts, fiscal_year 2024, published $000 × 1000. Accommodation Assistance 2,232,026; total 38,267,536 in source $000. Payment-definition evidence absent from staged annual-report PDF; the [Budget 2026 Estimates package](../packages/treasury/estimates_of_appropriations_2026_27/evidence.md) identifies Accommodation Supplement and Away from Home Allowance in the 2026/27 appropriation, without asserting unchanged FY2024/25 conditions. Raw artifact published to its `raw/nz/msd/...` key and verified by SHA-256 on 2026-10-07. | | `mbie/tenancy_bond_rents_tla_2026` | [x] | [x] | [x] | 5,663 administrative facts, August 2025–July 2026, the latest 12 months of MBIE's September 2026 TLA file (published 10 September 2026; MBIE calls the data provisional and subject to revision); 66 TA IDs plus ALL/NA. Raw CSV published to its `raw/nz/mbie/...` key and verified by SHA-256 on 2026-10-09. Source scope and TA-register caveats below. | -| `stats_nz/qes_average_earnings_march_2026` | [ ] | [ ] | [ ] | | +| `stats_nz/qes_average_weekly_earnings_june_2025` and `stats_nz/qes_average_weekly_earnings_june_2026` (supersede the planned March 2026 row) | [x] | [x] | [x] | G8-d3: 26 actual, unadjusted all-sector average weekly earnings levels per FTE (QEMQ.SBSZ9A ordinary time and QEMQ.SBSZ9Z total), June 2023–June 2026. Two receipt-pinned workbook vintages, each quarter emitted once; ten overlap cells agree exactly. Full workbooks preserved, excluded sectors/overtime/change blocks not emitted. CC BY 4.0; both raw workbooks published to their `raw/nz/stats_nz/...` keys and verified by SHA-256 on 2026-10-23. [Cell and period evidence](../packages/stats_nz/qes_average_weekly_earnings_june_2026/evidence.md). | +| `treasury/prefu26_economic_assumptions` | [x] | [x] | [x] | G8-d3: seven published annual percentage changes in ordinary-time weekly earnings, years ending 30 June 2025–2031, Table 4.1!C17:I17. Footnote 4 qualifies 2026 Forecast4 earnings as actual; 2027–2031 are source projections. CC BY 4.0; receipt-pinned unchanged workbook, published to its `raw/nz/treasury/...` key and verified by SHA-256 on 2026-10-23. [Footnotes and exact cells](../packages/treasury/prefu26_economic_assumptions/evidence.md). | ### WFF source semantics diff --git a/packages/stats_nz/qes_average_weekly_earnings_june_2025/evidence.md b/packages/stats_nz/qes_average_weekly_earnings_june_2025/evidence.md new file mode 100644 index 00000000..80a9eacc --- /dev/null +++ b/packages/stats_nz/qes_average_weekly_earnings_june_2025/evidence.md @@ -0,0 +1,7 @@ +# June 2025 QES vintage + +This package emits only Table 7 P/T rows 13–16, June 2023–March 2024: eight +published all-sector earnings levels. All sixteen workbook worksheets are +preserved. June 2024–June 2025 overlap cells agree exactly with the June 2026 +vintage and are preserved but not emitted here. See the [shared cell, period, +licence and guard evidence](../qes_average_weekly_earnings_june_2026/evidence.md). diff --git a/packages/stats_nz/qes_average_weekly_earnings_june_2025/source_package.yaml b/packages/stats_nz/qes_average_weekly_earnings_june_2025/source_package.yaml new file mode 100644 index 00000000..93daabd0 --- /dev/null +++ b/packages/stats_nz/qes_average_weekly_earnings_june_2025/source_package.yaml @@ -0,0 +1,685 @@ +schema_version: ledger.source_package.v1 +package_id: stats-nz-qes-average-weekly-earnings-june-2025 +label: Stats NZ QES all-sector average weekly earnings per FTE, June 2025 vintage +dimension_labels: + earnings_sector: QES sector + earnings_series_reference: QES series reference + earnings_component: Earnings component + earnings_denominator: QES earnings denominator + seasonal_adjustment: Seasonal adjustment +dimension_value_labels: + earnings_sector: + all_sectors: All sectors + earnings_denominator: + fte: Full-time equivalent employees (FTEs) + seasonal_adjustment: + actual: Actual (not seasonally adjusted) + earnings_series_reference: + QEMQ.SBSZ9A: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not + seasonally adjusted) + QEMQ.SBSZ9Z: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + earnings_component: + ordinary_time: Ordinary time + total: Total (ordinary time and overtime) +artifact: + source_name: stats_nz + source_table: 'Quarterly Employment Survey June 2025 quarter, Table 7: Average weekly earnings for + FTEs, by sector' + resource_package: db + resource_directory: data/stats_nz/qes_average_weekly_earnings_june_2025 + manifest: manifest.yaml + vintage: stats_nz_qes_june_2025 + extracted_at: '2026-10-22' + extraction_method: Full XLSX used-range preservation; direct Table 7 published level cells only + parser: xlsx_used_range + artifact_year: 2025 +record_sets: +- record_set_id: stats_nz.qes.awe.2023q2 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2023q2.v1 + source_record_id_prefix: stats_nz.qes.awe.2023q2 + sheet_name: Table 7 + period_type: quarter + period: 2023-Q2 + period_coverage: + start_date: '2023-04-01' + end_date: '2023-06-30' + basis: calendar + source_period_label: Jun 2023 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 13 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Jun + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2023' + label: Workbook vintage first level year + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2023q3 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2023q3.v1 + source_record_id_prefix: stats_nz.qes.awe.2023q3 + sheet_name: Table 7 + period_type: quarter + period: 2023-Q3 + period_coverage: + start_date: '2023-07-01' + end_date: '2023-09-30' + basis: calendar + source_period_label: Sep 2023 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 14 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Sep + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2023' + label: Workbook vintage first level year + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2023q4 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2023q4.v1 + source_record_id_prefix: stats_nz.qes.awe.2023q4 + sheet_name: Table 7 + period_type: quarter + period: 2023-Q4 + period_coverage: + start_date: '2023-10-01' + end_date: '2023-12-31' + basis: calendar + source_period_label: Dec 2023 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 15 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Dec + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2023' + label: Workbook vintage first level year + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2024q1 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2024q1.v1 + source_record_id_prefix: stats_nz.qes.awe.2024q1 + sheet_name: Table 7 + period_type: quarter + period: 2024-Q1 + period_coverage: + start_date: '2024-01-01' + end_date: '2024-03-31' + basis: calendar + source_period_label: Mar 2024 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 16 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Mar + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2023' + label: Workbook vintage first level year + - column: A + row: 16 + expected_value: '2024' + label: Published year anchor + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2025-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector diff --git a/packages/stats_nz/qes_average_weekly_earnings_june_2026/evidence.md b/packages/stats_nz/qes_average_weekly_earnings_june_2026/evidence.md new file mode 100644 index 00000000..84c16bda --- /dev/null +++ b/packages/stats_nz/qes_average_weekly_earnings_june_2026/evidence.md @@ -0,0 +1,64 @@ +# QES average weekly earnings: publisher-cell evidence + +Two packages preserve the unchanged Stats NZ June 2025 and June 2026 quarterly +employment workbooks. Both use `xlsx_used_range` with no sheet restriction: +every worksheet's rectangular used range is preserved before fact selection. +Source URLs, receipt timestamps, lengths and SHA-256 hashes are in each manifest; +the canonical `raw/nz/stats_nz/...` keys are generated with +`chronicle.artifacts.build_r2_key`. The hub published both objects to those keys +on 2026-10-23 and verified each by streaming it back and matching its SHA-256. + +## Exact scope and vintage ownership + +Only Table 7, “Average weekly earnings for FTEs(1)”, “By sector”, is emitted. +P6 names the all-sector group “Total”; P7/P8 identify ordinary time / SBSZ9A, +and T7/T8 identify total / SBSZ9Z. A8 supplies the `QEMQ` prefix. The two +series are `QEMQ.SBSZ9A` and `QEMQ.SBSZ9Z`, in NZD per week per full-time +equivalent employee, actual (not seasonally adjusted). + +| Package | Source rows | Published quarters | Facts | +|---|---|---|---:| +| `stats_nz/qes_average_weekly_earnings_june_2025` | Table 7 rows 13–16, P/T | June 2023–March 2024 | 8 | +| `stats_nz/qes_average_weekly_earnings_june_2026` | Table 7 rows 13–21, P/T | June 2024–June 2026 | 18 | + +The June 2025 file also publishes June 2024–June 2025 in rows 17–21. All +five overlapping quarters agree exactly in both P and T against June 2026 +rows 13–17 (ten comparisons, checked independently from workbook bytes). +Those older-vintage overlap cells remain preserved but are not emitted. Each +quarter/series is emitted once. No reconciliation, source arithmetic, annual +average, growth rate, aging factor or consumer target is constructed. + +Public/private sector columns, overtime R, percentage-change blocks below the +levels, and all other worksheets are preserved but not emitted. Footnote 1 +at B49 reads: “Average weekly earnings are calculated by dividing earnings by +the number of FTEs.” This is the publisher's denominator definition; Chronicle +reads the published average and performs no division. + +## Period, measurement basis and labels + +Facts use Chronicle's existing `period_type: quarter`, `period: YYYY-Qn` +convention (also used by `ofgem/energy_price_cap_q1_2024`), with calendar +quarter boundaries in period coverage. The QES source-period definition +supplied by the hub is the pay week ending on or before the 20th of the +quarter's middle month. It is recorded in period notes and is not substituted +for the published quarter. The staged Table 7 does not itself repeat that +methodological definition. + +Every record set explicitly declares `provenance_class: survey_aggregate`, +`survey_instrument: Quarterly Employment Survey (QES)` and +`assertion: observation`. Labels and dimensions retain series reference, +ordinary-time/total component, all-sector scope, FTE denominator and actual +(not seasonally adjusted) status. Selectors guard the table title, sector, +series prefix, dollar unit, level block, column codes/components, quarter, +year anchor, workbook vintage and FTE footnote. Independent literal cell +maps and source/YAML mutants cover their failure modes. + +## Licence and provenance limits + +Stats NZ CC BY 4.0 attribution is recorded in both manifests, using the +hub-supplied [Stats NZ copyright statement](https://www.stats.govt.nz/about-us/copyright/). +The build verified each committed XLSX's hash and length against the hub's +fetch receipt, whose URL, timestamp, length and SHA-256 the manifests record; +it did not fetch publication or licence pages. The publisher release pages are +linked in the manifests. The raw objects are on R2 and verified by SHA-256 +(2026-10-23). diff --git a/packages/stats_nz/qes_average_weekly_earnings_june_2026/source_package.yaml b/packages/stats_nz/qes_average_weekly_earnings_june_2026/source_package.yaml new file mode 100644 index 00000000..a19f0165 --- /dev/null +++ b/packages/stats_nz/qes_average_weekly_earnings_june_2026/source_package.yaml @@ -0,0 +1,1510 @@ +schema_version: ledger.source_package.v1 +package_id: stats-nz-qes-average-weekly-earnings-june-2026 +label: Stats NZ QES all-sector average weekly earnings per FTE, June 2026 vintage +dimension_labels: + earnings_sector: QES sector + earnings_series_reference: QES series reference + earnings_component: Earnings component + earnings_denominator: QES earnings denominator + seasonal_adjustment: Seasonal adjustment +dimension_value_labels: + earnings_sector: + all_sectors: All sectors + earnings_denominator: + fte: Full-time equivalent employees (FTEs) + seasonal_adjustment: + actual: Actual (not seasonally adjusted) + earnings_series_reference: + QEMQ.SBSZ9A: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not + seasonally adjusted) + QEMQ.SBSZ9Z: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + earnings_component: + ordinary_time: Ordinary time + total: Total (ordinary time and overtime) +artifact: + source_name: stats_nz + source_table: 'Quarterly Employment Survey June 2026 quarter, Table 7: Average weekly earnings for + FTEs, by sector' + resource_package: db + resource_directory: data/stats_nz/qes_average_weekly_earnings_june_2026 + manifest: manifest.yaml + vintage: stats_nz_qes_june_2026 + extracted_at: '2026-10-22' + extraction_method: Full XLSX used-range preservation; direct Table 7 published level cells only + parser: xlsx_used_range + artifact_year: 2026 +record_sets: +- record_set_id: stats_nz.qes.awe.2024q2 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2024q2.v1 + source_record_id_prefix: stats_nz.qes.awe.2024q2 + sheet_name: Table 7 + period_type: quarter + period: 2024-Q2 + period_coverage: + start_date: '2024-04-01' + end_date: '2024-06-30' + basis: calendar + source_period_label: Jun 2024 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 13 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Jun + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2024q3 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2024q3.v1 + source_record_id_prefix: stats_nz.qes.awe.2024q3 + sheet_name: Table 7 + period_type: quarter + period: 2024-Q3 + period_coverage: + start_date: '2024-07-01' + end_date: '2024-09-30' + basis: calendar + source_period_label: Sep 2024 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 14 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Sep + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2024q4 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2024q4.v1 + source_record_id_prefix: stats_nz.qes.awe.2024q4 + sheet_name: Table 7 + period_type: quarter + period: 2024-Q4 + period_coverage: + start_date: '2024-10-01' + end_date: '2024-12-31' + basis: calendar + source_period_label: Dec 2024 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 15 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Dec + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2025q1 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2025q1.v1 + source_record_id_prefix: stats_nz.qes.awe.2025q1 + sheet_name: Table 7 + period_type: quarter + period: 2025-Q1 + period_coverage: + start_date: '2025-01-01' + end_date: '2025-03-31' + basis: calendar + source_period_label: Mar 2025 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 16 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Mar + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + - column: A + row: 16 + expected_value: '2025' + label: Published year anchor + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2025q2 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2025q2.v1 + source_record_id_prefix: stats_nz.qes.awe.2025q2 + sheet_name: Table 7 + period_type: quarter + period: 2025-Q2 + period_coverage: + start_date: '2025-04-01' + end_date: '2025-06-30' + basis: calendar + source_period_label: Jun 2025 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 17 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Jun + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + - column: A + row: 16 + expected_value: '2025' + label: Published year anchor + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2025q3 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2025q3.v1 + source_record_id_prefix: stats_nz.qes.awe.2025q3 + sheet_name: Table 7 + period_type: quarter + period: 2025-Q3 + period_coverage: + start_date: '2025-07-01' + end_date: '2025-09-30' + basis: calendar + source_period_label: Sep 2025 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 18 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Sep + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + - column: A + row: 16 + expected_value: '2025' + label: Published year anchor + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2025q4 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2025q4.v1 + source_record_id_prefix: stats_nz.qes.awe.2025q4 + sheet_name: Table 7 + period_type: quarter + period: 2025-Q4 + period_coverage: + start_date: '2025-10-01' + end_date: '2025-12-31' + basis: calendar + source_period_label: Dec 2025 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 19 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Dec + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + - column: A + row: 16 + expected_value: '2025' + label: Published year anchor + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2026q1 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2026q1.v1 + source_record_id_prefix: stats_nz.qes.awe.2026q1 + sheet_name: Table 7 + period_type: quarter + period: 2026-Q1 + period_coverage: + start_date: '2026-01-01' + end_date: '2026-03-31' + basis: calendar + source_period_label: Mar 2026 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 20 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Mar + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + - column: A + row: 20 + expected_value: '2026' + label: Published year anchor + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector +- record_set_id: stats_nz.qes.awe.2026q2 + provenance_class: survey_aggregate + survey_instrument: Quarterly Employment Survey (QES) + assertion: observation + record_set_spec_id: stats_nz.qes.awe.2026q2.v1 + source_record_id_prefix: stats_nz.qes.awe.2026q2 + sheet_name: Table 7 + period_type: quarter + period: 2026-Q2 + period_coverage: + start_date: '2026-04-01' + end_date: '2026-06-30' + basis: calendar + source_period_label: Jun 2026 quarter + notes: QES reference period is the pay week ending on or before the 20th of the quarter’s middle + month (hub-supplied source-period definition); the fact period is the published quarter, not + the pay week. Actual, not seasonally adjusted. No annual averaging or period alignment. + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: person + entity_role: full_time_equivalent_employee + domain: employment_earnings + groupby_dimension: earnings_sector + shared_filters: + earnings_denominator: fte + seasonal_adjustment: actual + earnings_sector: all_sectors + rows: + - value_id: all_sectors + label: All sectors + ordinal: 0 + row_number: 21 + table_record_kind: detail + expected_row_header_column: C + expected_row_header: Jun + guard_cells: + - column: A + row: 1 + expected_value: Table 7 + label: Source table + - column: A + row: 3 + expected_value: Average weekly earnings for FTEs(1) + label: FTE earnings measure + - column: A + row: 4 + expected_value: By sector + label: Sector breakdown + - column: A + row: 8 + expected_value: 'Series ref: QEMQ' + label: Series reference prefix + - column: A + row: 10 + expected_value: ($) + label: Published dollar unit + - column: A + row: 12 + expected_value: Quarter + label: Quarter level block + - column: P + row: 6 + expected_value: Total + label: All-sector column group + - column: P + row: 7 + expected_value: Ordinary time + label: Ordinary-time component + - column: T + row: 7 + expected_value: Total + label: Total component + - column: B + row: 49 + expected_value: Average weekly earnings are calculated by dividing earnings by the number of + FTEs. + label: FTE denominator footnote + - column: A + row: 13 + expected_value: '2024' + label: Workbook vintage first level year + - column: A + row: 20 + expected_value: '2026' + label: Published year anchor + measures: + - measure_id: SBSZ9A + label: QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 0 + column: P + source_column_id: SBSZ9A + concept: stats_nz.qes.average_weekly_earnings.ordinary_time + source_concept: stats_nz.qes.average_weekly_earnings.ordinary_time + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector ordinary time average weekly earnings for + FTEs, series QEMQ.SBSZ9A. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9A + filters: + earnings_series_reference: QEMQ.SBSZ9A + earnings_component: ordinary_time + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9A + label: QES series reference + - variable: earnings_component + operator: == + value: ordinary_time + label: Earnings component + - measure_id: SBSZ9Z + label: QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally + adjusted) + ordinal: 1 + column: T + source_column_id: SBSZ9Z + concept: stats_nz.qes.average_weekly_earnings.total + source_concept: stats_nz.qes.average_weekly_earnings.total + concept_relation: source_label + concept_authority: stats_nz + concept_evidence_url: https://www.stats.govt.nz/information-releases/labour-market-statistics-june-2026-quarter/ + concept_evidence_notes: 'Table 7 publishes all-sector total average weekly earnings for FTEs, + series QEMQ.SBSZ9Z. Footnote 1: Average weekly earnings are calculated by dividing earnings + by the number of FTEs. Actual (not seasonally adjusted); one unchanged published level cell + per fact.' + unit: nzd_per_week + aggregation: mean + expected_cell_type: number + expected_column_header_row: 8 + expected_column_header: SBSZ9Z + filters: + earnings_series_reference: QEMQ.SBSZ9Z + earnings_component: total + constraints: + - variable: earnings_series_reference + operator: == + value: QEMQ.SBSZ9Z + label: QES series reference + - variable: earnings_component + operator: == + value: total + label: Earnings component + shared_constraints: + - variable: earnings_denominator + operator: == + value: fte + label: QES earnings denominator + - variable: seasonal_adjustment + operator: == + value: actual + label: QES adjustment status + - variable: earnings_sector + operator: == + value: all_sectors + label: QES sector diff --git a/packages/treasury/prefu26_economic_assumptions/evidence.md b/packages/treasury/prefu26_economic_assumptions/evidence.md new file mode 100644 index 00000000..0392688f --- /dev/null +++ b/packages/treasury/prefu26_economic_assumptions/evidence.md @@ -0,0 +1,62 @@ +The unchanged `prefu26-charts-data.xlsx` is Treasury's *Data and Charts – +Pre-election Economic and Fiscal Update 2026*. `Index!A2` states publication +on 29 September 2026; `Index!A4:A6` identifies Treasury and the publication +pages. The hub receipt records the source URL +, +664,670 bytes, fetched `2026-10-22T07:57:29Z`, SHA-256 +`e2486375dde515d0722f8c3022f481804bb014beb83c81b8bfc99bc9426544d9`. +The source was copied byte for byte and its manifest R2 key was generated by +`chronicle.artifacts.build_r2_key`; the hub published that object to R2 on +2026-10-23 and verified it by SHA-256 read-back. + +The publication page's CC BY 4.0 licence is corroborated by `Index!A13:A14`: +written attribution to the Crown is required; emblems, logos and the Coat of +Arms have additional restrictions. The manifest attributes the Crown / New +Zealand Treasury and records both the publication page and workbook evidence. + +The parser preserves the complete used ranges of the `Index` and `Table 4.1` +worksheets, following the named-sheet convention used by the merged Stats NZ +population package. All other sheets remain in the immutable original +workbook, and produce no facts. There are exactly seven facts, one per +`Table 4.1!C17:I17` cell; no calculation produces a fact. + +`Table 4.1!B1` names *Key economic assumptions for fiscal forecasts*. +`B2` attributes the source to Treasury, Stats NZ and the Reserve Bank of New +Zealand. `B5` states **Year ending 30 June**. The source values are: + +| Cell | Ending year | Publisher column status | Annual percentage change | Assertion | +|---|---:|---|---:|---| +| C17 | 2025 | Actual | 4.2 | observation | +| D17 | 2026 | Forecast4 | 2.9 | observation | +| E17 | 2027 | Forecast | 2.7 | source_projection | +| F17 | 2028 | Forecast | 3 | source_projection | +| G17 | 2029 | Forecast | 3.2 | source_projection | +| H17 | 2030 | Forecast | 3.4 | source_projection | +| I17 | 2031 | Forecast | 3.4 | source_projection | + +`B17` is literally `Average weekly earnings3 (ann % chg)`. Footnote 3 at +`C21:D21` says **Ordinary time.** Footnote 4 at `C22:D22` says **Measures are +actuals except for real GDP and nominal GDP.** Therefore the 2026 earnings +cell is an actual, even though the encompassing column is headed `Forecast4`. +Every fact keeps that literal column status and both footnotes. This corrects +the preliminary scope description that treated every 2026 measure as a +forecast. No final-year low/central/high variants are published here or added. +The ordinary-time component and literal publication status are carried as +labelled dimensions with explicit equality constraints on those source scopes. + +Treasury's merged Estimates package uses `assertion: observation` for actuals +and `assertion: source_projection` for the publisher's estimates (see its +`evidence.md` and source-package record sets). This package follows that +assertion convention. `provenance_class: model_output` describes the Treasury +economic-assumption publication, as in the merged Treasury AN24-01 fiscal +totals and OBR economic-outlook packages, and is explicit in each record set. +The mixed-source table does not identify a survey instrument, so none is +invented or asserted here. + +Periods follow Treasury Estimates' opening-year `fiscal_year` convention: +year ending 30 June 2025 is `fiscal_year:2024` with coverage 1 July 2024 to +30 June 2025. Each later cell keeps its own published fiscal reference span +and ending-year label. `percent` with scale 1 preserves the publisher's +annual percentage changes. No growth rates from levels, annual averages, +factors, reconciliation, aging, imputation, consumer selection or measurement +bindings are constructed. diff --git a/packages/treasury/prefu26_economic_assumptions/source_package.yaml b/packages/treasury/prefu26_economic_assumptions/source_package.yaml new file mode 100644 index 00000000..239e8211 --- /dev/null +++ b/packages/treasury/prefu26_economic_assumptions/source_package.yaml @@ -0,0 +1,747 @@ +# Publisher cells only; footnote 4 makes 2026 earnings actual despite Forecast4. +# Each record set explicitly declares its provenance_class. +schema_version: ledger.source_package.v1 +package_id: treasury-prefu26-economic-assumptions +label: Treasury PREFU 2026 average ordinary-time weekly earnings, annual percentage change, years ending + 30 June 2025–2031 +dimension_labels: + treasury.prefu26.assumption: Economic assumption + earnings_component: Earnings component + publication_status: Publication status +dimension_value_labels: + earnings_component: + ordinary_time: Ordinary time + publication_status: + Actual: Actual + Forecast4: 'Forecast4 (footnote 4: earnings are actuals)' + Forecast: Forecast +artifact: + source_name: treasury + source_table: PREFU 2026 Table 4.1 - Key economic assumptions for fiscal forecasts + resource_package: db + resource_directory: data/treasury/prefu26_economic_assumptions + manifest: manifest.yaml + vintage: prefu_2026_09_29 + extracted_at: '2026-10-22' + extraction_method: Full used-range cell parse of Index and Table 4.1; seven published row 17 cells only, + no arithmetic + parser: xlsx_used_range + sheets: + - Index + - Table 4.1 + artifact_year: 2026 +record_sets: +- record_set_id: treasury.prefu26.average_weekly_earnings.fy2024 + provenance_class: model_output + assertion: observation + record_set_spec_id: treasury.prefu26.average_weekly_earnings.fy2024.v1 + source_record_id_prefix: treasury.prefu26.average_weekly_earnings.fy2024 + sheet_name: Table 4.1 + period_type: fiscal_year + period: 2024 + period_coverage: + basis: fiscal + source_period_label: Year ending 30 June 2025 + start_date: '2024-07-01' + end_date: '2025-06-30' + notes: 'Publisher Year ending 30 June 2025; Chronicle opening-year fiscal_year:2024. Publisher column + status is Actual. Footnote 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures + are actuals except for real GDP and nominal GDP. 2026 earnings are therefore actuals despite the + Forecast4 column heading; only 2027–2031 earnings are forecasts. The published annual percentage + change is retained unchanged; no annual average, level, factor or period alignment is calculated.' + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: government + entity_role: forecaster + domain: economic_outlook + groupby_dimension: treasury.prefu26.assumption + shared_filters: + earnings_component: ordinary_time + publication_status: Actual + rows: + - value_id: average_weekly_earnings_annual_percentage_change + label: Average weekly earnings (annual percentage change, ordinary time) + ordinal: 0 + row_number: 17 + expected_row_header_column: B + expected_row_header: Average weekly earnings3 (ann % chg) + table_record_kind: total + guard_cells: + - column: B + row: 1 + expected_value: Table 4.1 - Key economic assumptions for fiscal forecasts + label: table title + - column: B + row: 2 + expected_value: 'Sources: The Treasury, Stats NZ, Reserve Bank of New Zealand' + label: publisher source attribution + - column: B + row: 5 + expected_value: Year ending 30 June + label: publisher period basis + - column: C + row: 6 + expected_value: Actual + label: publisher status + - column: C + row: 21 + expected_value: 3 + label: ordinary-time footnote marker + - column: D + row: 21 + expected_value: Ordinary time. + label: ordinary-time footnote + - column: C + row: 22 + expected_value: 4 + label: actuals qualification marker + - column: D + row: 22 + expected_value: Measures are actuals except for real GDP and nominal GDP. + label: actuals qualification + measures: + - measure_id: average_weekly_earnings_annual_percentage_change + label: Average ordinary-time weekly earnings, annual percentage change, year ending 30 June 2025 (Actual) + ordinal: 0 + column: C + source_column_id: year_ending_30_june_2025 + expected_column_header_row: 5 + expected_column_header: 2025 + concept: treasury.average_weekly_earnings_annual_percentage_change + source_concept: treasury.prefu26.average_weekly_earnings_annual_percentage_change + concept_relation: source_label + concept_authority: treasury + concept_evidence_url: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 + concept_evidence_notes: 'Table 4.1 row 17, Average weekly earnings3 (ann % chg). Publisher Year ending + 30 June 2025; Chronicle opening-year fiscal_year:2024. Publisher column status is Actual. Footnote + 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures are actuals except for real + GDP and nominal GDP. 2026 earnings are therefore actuals despite the Forecast4 column heading; only + 2027–2031 earnings are forecasts. The published annual percentage change is retained unchanged; + no annual average, level, factor or period alignment is calculated.' + unit: percent + aggregation: sum + value_scale: 1 + expected_cell_type: number + shared_constraints: + - variable: earnings_component + operator: == + value: ordinary_time + label: Ordinary time + - variable: publication_status + operator: == + value: Actual + label: Actual +- record_set_id: treasury.prefu26.average_weekly_earnings.fy2025 + provenance_class: model_output + assertion: observation + record_set_spec_id: treasury.prefu26.average_weekly_earnings.fy2025.v1 + source_record_id_prefix: treasury.prefu26.average_weekly_earnings.fy2025 + sheet_name: Table 4.1 + period_type: fiscal_year + period: 2025 + period_coverage: + basis: fiscal + source_period_label: Year ending 30 June 2026 + start_date: '2025-07-01' + end_date: '2026-06-30' + notes: 'Publisher Year ending 30 June 2026; Chronicle opening-year fiscal_year:2025. Publisher column + status is Forecast4. Footnote 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures + are actuals except for real GDP and nominal GDP. 2026 earnings are therefore actuals despite the + Forecast4 column heading; only 2027–2031 earnings are forecasts. The published annual percentage + change is retained unchanged; no annual average, level, factor or period alignment is calculated.' + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: government + entity_role: forecaster + domain: economic_outlook + groupby_dimension: treasury.prefu26.assumption + shared_filters: + earnings_component: ordinary_time + publication_status: Forecast4 + rows: + - value_id: average_weekly_earnings_annual_percentage_change + label: Average weekly earnings (annual percentage change, ordinary time) + ordinal: 0 + row_number: 17 + expected_row_header_column: B + expected_row_header: Average weekly earnings3 (ann % chg) + table_record_kind: total + guard_cells: + - column: B + row: 1 + expected_value: Table 4.1 - Key economic assumptions for fiscal forecasts + label: table title + - column: B + row: 2 + expected_value: 'Sources: The Treasury, Stats NZ, Reserve Bank of New Zealand' + label: publisher source attribution + - column: B + row: 5 + expected_value: Year ending 30 June + label: publisher period basis + - column: D + row: 6 + expected_value: Forecast4 + label: publisher status + - column: C + row: 21 + expected_value: 3 + label: ordinary-time footnote marker + - column: D + row: 21 + expected_value: Ordinary time. + label: ordinary-time footnote + - column: C + row: 22 + expected_value: 4 + label: actuals qualification marker + - column: D + row: 22 + expected_value: Measures are actuals except for real GDP and nominal GDP. + label: actuals qualification + measures: + - measure_id: average_weekly_earnings_annual_percentage_change + label: Average ordinary-time weekly earnings, annual percentage change, year ending 30 June 2026 (Forecast4) + ordinal: 0 + column: D + source_column_id: year_ending_30_june_2026 + expected_column_header_row: 5 + expected_column_header: 2026 + concept: treasury.average_weekly_earnings_annual_percentage_change + source_concept: treasury.prefu26.average_weekly_earnings_annual_percentage_change + concept_relation: source_label + concept_authority: treasury + concept_evidence_url: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 + concept_evidence_notes: 'Table 4.1 row 17, Average weekly earnings3 (ann % chg). Publisher Year ending + 30 June 2026; Chronicle opening-year fiscal_year:2025. Publisher column status is Forecast4. Footnote + 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures are actuals except for real + GDP and nominal GDP. 2026 earnings are therefore actuals despite the Forecast4 column heading; only + 2027–2031 earnings are forecasts. The published annual percentage change is retained unchanged; + no annual average, level, factor or period alignment is calculated.' + unit: percent + aggregation: sum + value_scale: 1 + expected_cell_type: number + shared_constraints: + - variable: earnings_component + operator: == + value: ordinary_time + label: Ordinary time + - variable: publication_status + operator: == + value: Forecast4 + label: 'Forecast4 (footnote 4: earnings are actuals)' +- record_set_id: treasury.prefu26.average_weekly_earnings.fy2026 + provenance_class: model_output + assertion: source_projection + record_set_spec_id: treasury.prefu26.average_weekly_earnings.fy2026.v1 + source_record_id_prefix: treasury.prefu26.average_weekly_earnings.fy2026 + sheet_name: Table 4.1 + period_type: fiscal_year + period: 2026 + period_coverage: + basis: fiscal + source_period_label: Year ending 30 June 2027 + start_date: '2026-07-01' + end_date: '2027-06-30' + notes: 'Publisher Year ending 30 June 2027; Chronicle opening-year fiscal_year:2026. Publisher column + status is Forecast. Footnote 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures + are actuals except for real GDP and nominal GDP. 2026 earnings are therefore actuals despite the + Forecast4 column heading; only 2027–2031 earnings are forecasts. The published annual percentage + change is retained unchanged; no annual average, level, factor or period alignment is calculated.' + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: government + entity_role: forecaster + domain: economic_outlook + groupby_dimension: treasury.prefu26.assumption + shared_filters: + earnings_component: ordinary_time + publication_status: Forecast + rows: + - value_id: average_weekly_earnings_annual_percentage_change + label: Average weekly earnings (annual percentage change, ordinary time) + ordinal: 0 + row_number: 17 + expected_row_header_column: B + expected_row_header: Average weekly earnings3 (ann % chg) + table_record_kind: total + guard_cells: + - column: B + row: 1 + expected_value: Table 4.1 - Key economic assumptions for fiscal forecasts + label: table title + - column: B + row: 2 + expected_value: 'Sources: The Treasury, Stats NZ, Reserve Bank of New Zealand' + label: publisher source attribution + - column: B + row: 5 + expected_value: Year ending 30 June + label: publisher period basis + - column: E + row: 6 + expected_value: Forecast + label: publisher status + - column: C + row: 21 + expected_value: 3 + label: ordinary-time footnote marker + - column: D + row: 21 + expected_value: Ordinary time. + label: ordinary-time footnote + - column: C + row: 22 + expected_value: 4 + label: actuals qualification marker + - column: D + row: 22 + expected_value: Measures are actuals except for real GDP and nominal GDP. + label: actuals qualification + measures: + - measure_id: average_weekly_earnings_annual_percentage_change + label: Average ordinary-time weekly earnings, annual percentage change, year ending 30 June 2027 (Forecast) + ordinal: 0 + column: E + source_column_id: year_ending_30_june_2027 + expected_column_header_row: 5 + expected_column_header: 2027 + concept: treasury.average_weekly_earnings_annual_percentage_change + source_concept: treasury.prefu26.average_weekly_earnings_annual_percentage_change + concept_relation: source_label + concept_authority: treasury + concept_evidence_url: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 + concept_evidence_notes: 'Table 4.1 row 17, Average weekly earnings3 (ann % chg). Publisher Year ending + 30 June 2027; Chronicle opening-year fiscal_year:2026. Publisher column status is Forecast. Footnote + 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures are actuals except for real + GDP and nominal GDP. 2026 earnings are therefore actuals despite the Forecast4 column heading; only + 2027–2031 earnings are forecasts. The published annual percentage change is retained unchanged; + no annual average, level, factor or period alignment is calculated.' + unit: percent + aggregation: sum + value_scale: 1 + expected_cell_type: number + shared_constraints: + - variable: earnings_component + operator: == + value: ordinary_time + label: Ordinary time + - variable: publication_status + operator: == + value: Forecast + label: Forecast +- record_set_id: treasury.prefu26.average_weekly_earnings.fy2027 + provenance_class: model_output + assertion: source_projection + record_set_spec_id: treasury.prefu26.average_weekly_earnings.fy2027.v1 + source_record_id_prefix: treasury.prefu26.average_weekly_earnings.fy2027 + sheet_name: Table 4.1 + period_type: fiscal_year + period: 2027 + period_coverage: + basis: fiscal + source_period_label: Year ending 30 June 2028 + start_date: '2027-07-01' + end_date: '2028-06-30' + notes: 'Publisher Year ending 30 June 2028; Chronicle opening-year fiscal_year:2027. Publisher column + status is Forecast. Footnote 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures + are actuals except for real GDP and nominal GDP. 2026 earnings are therefore actuals despite the + Forecast4 column heading; only 2027–2031 earnings are forecasts. The published annual percentage + change is retained unchanged; no annual average, level, factor or period alignment is calculated.' + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: government + entity_role: forecaster + domain: economic_outlook + groupby_dimension: treasury.prefu26.assumption + shared_filters: + earnings_component: ordinary_time + publication_status: Forecast + rows: + - value_id: average_weekly_earnings_annual_percentage_change + label: Average weekly earnings (annual percentage change, ordinary time) + ordinal: 0 + row_number: 17 + expected_row_header_column: B + expected_row_header: Average weekly earnings3 (ann % chg) + table_record_kind: total + guard_cells: + - column: B + row: 1 + expected_value: Table 4.1 - Key economic assumptions for fiscal forecasts + label: table title + - column: B + row: 2 + expected_value: 'Sources: The Treasury, Stats NZ, Reserve Bank of New Zealand' + label: publisher source attribution + - column: B + row: 5 + expected_value: Year ending 30 June + label: publisher period basis + - column: F + row: 6 + expected_value: Forecast + label: publisher status + - column: C + row: 21 + expected_value: 3 + label: ordinary-time footnote marker + - column: D + row: 21 + expected_value: Ordinary time. + label: ordinary-time footnote + - column: C + row: 22 + expected_value: 4 + label: actuals qualification marker + - column: D + row: 22 + expected_value: Measures are actuals except for real GDP and nominal GDP. + label: actuals qualification + measures: + - measure_id: average_weekly_earnings_annual_percentage_change + label: Average ordinary-time weekly earnings, annual percentage change, year ending 30 June 2028 (Forecast) + ordinal: 0 + column: F + source_column_id: year_ending_30_june_2028 + expected_column_header_row: 5 + expected_column_header: 2028 + concept: treasury.average_weekly_earnings_annual_percentage_change + source_concept: treasury.prefu26.average_weekly_earnings_annual_percentage_change + concept_relation: source_label + concept_authority: treasury + concept_evidence_url: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 + concept_evidence_notes: 'Table 4.1 row 17, Average weekly earnings3 (ann % chg). Publisher Year ending + 30 June 2028; Chronicle opening-year fiscal_year:2027. Publisher column status is Forecast. Footnote + 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures are actuals except for real + GDP and nominal GDP. 2026 earnings are therefore actuals despite the Forecast4 column heading; only + 2027–2031 earnings are forecasts. The published annual percentage change is retained unchanged; + no annual average, level, factor or period alignment is calculated.' + unit: percent + aggregation: sum + value_scale: 1 + expected_cell_type: number + shared_constraints: + - variable: earnings_component + operator: == + value: ordinary_time + label: Ordinary time + - variable: publication_status + operator: == + value: Forecast + label: Forecast +- record_set_id: treasury.prefu26.average_weekly_earnings.fy2028 + provenance_class: model_output + assertion: source_projection + record_set_spec_id: treasury.prefu26.average_weekly_earnings.fy2028.v1 + source_record_id_prefix: treasury.prefu26.average_weekly_earnings.fy2028 + sheet_name: Table 4.1 + period_type: fiscal_year + period: 2028 + period_coverage: + basis: fiscal + source_period_label: Year ending 30 June 2029 + start_date: '2028-07-01' + end_date: '2029-06-30' + notes: 'Publisher Year ending 30 June 2029; Chronicle opening-year fiscal_year:2028. Publisher column + status is Forecast. Footnote 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures + are actuals except for real GDP and nominal GDP. 2026 earnings are therefore actuals despite the + Forecast4 column heading; only 2027–2031 earnings are forecasts. The published annual percentage + change is retained unchanged; no annual average, level, factor or period alignment is calculated.' + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: government + entity_role: forecaster + domain: economic_outlook + groupby_dimension: treasury.prefu26.assumption + shared_filters: + earnings_component: ordinary_time + publication_status: Forecast + rows: + - value_id: average_weekly_earnings_annual_percentage_change + label: Average weekly earnings (annual percentage change, ordinary time) + ordinal: 0 + row_number: 17 + expected_row_header_column: B + expected_row_header: Average weekly earnings3 (ann % chg) + table_record_kind: total + guard_cells: + - column: B + row: 1 + expected_value: Table 4.1 - Key economic assumptions for fiscal forecasts + label: table title + - column: B + row: 2 + expected_value: 'Sources: The Treasury, Stats NZ, Reserve Bank of New Zealand' + label: publisher source attribution + - column: B + row: 5 + expected_value: Year ending 30 June + label: publisher period basis + - column: G + row: 6 + expected_value: Forecast + label: publisher status + - column: C + row: 21 + expected_value: 3 + label: ordinary-time footnote marker + - column: D + row: 21 + expected_value: Ordinary time. + label: ordinary-time footnote + - column: C + row: 22 + expected_value: 4 + label: actuals qualification marker + - column: D + row: 22 + expected_value: Measures are actuals except for real GDP and nominal GDP. + label: actuals qualification + measures: + - measure_id: average_weekly_earnings_annual_percentage_change + label: Average ordinary-time weekly earnings, annual percentage change, year ending 30 June 2029 (Forecast) + ordinal: 0 + column: G + source_column_id: year_ending_30_june_2029 + expected_column_header_row: 5 + expected_column_header: 2029 + concept: treasury.average_weekly_earnings_annual_percentage_change + source_concept: treasury.prefu26.average_weekly_earnings_annual_percentage_change + concept_relation: source_label + concept_authority: treasury + concept_evidence_url: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 + concept_evidence_notes: 'Table 4.1 row 17, Average weekly earnings3 (ann % chg). Publisher Year ending + 30 June 2029; Chronicle opening-year fiscal_year:2028. Publisher column status is Forecast. Footnote + 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures are actuals except for real + GDP and nominal GDP. 2026 earnings are therefore actuals despite the Forecast4 column heading; only + 2027–2031 earnings are forecasts. The published annual percentage change is retained unchanged; + no annual average, level, factor or period alignment is calculated.' + unit: percent + aggregation: sum + value_scale: 1 + expected_cell_type: number + shared_constraints: + - variable: earnings_component + operator: == + value: ordinary_time + label: Ordinary time + - variable: publication_status + operator: == + value: Forecast + label: Forecast +- record_set_id: treasury.prefu26.average_weekly_earnings.fy2029 + provenance_class: model_output + assertion: source_projection + record_set_spec_id: treasury.prefu26.average_weekly_earnings.fy2029.v1 + source_record_id_prefix: treasury.prefu26.average_weekly_earnings.fy2029 + sheet_name: Table 4.1 + period_type: fiscal_year + period: 2029 + period_coverage: + basis: fiscal + source_period_label: Year ending 30 June 2030 + start_date: '2029-07-01' + end_date: '2030-06-30' + notes: 'Publisher Year ending 30 June 2030; Chronicle opening-year fiscal_year:2029. Publisher column + status is Forecast. Footnote 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures + are actuals except for real GDP and nominal GDP. 2026 earnings are therefore actuals despite the + Forecast4 column heading; only 2027–2031 earnings are forecasts. The published annual percentage + change is retained unchanged; no annual average, level, factor or period alignment is calculated.' + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: government + entity_role: forecaster + domain: economic_outlook + groupby_dimension: treasury.prefu26.assumption + shared_filters: + earnings_component: ordinary_time + publication_status: Forecast + rows: + - value_id: average_weekly_earnings_annual_percentage_change + label: Average weekly earnings (annual percentage change, ordinary time) + ordinal: 0 + row_number: 17 + expected_row_header_column: B + expected_row_header: Average weekly earnings3 (ann % chg) + table_record_kind: total + guard_cells: + - column: B + row: 1 + expected_value: Table 4.1 - Key economic assumptions for fiscal forecasts + label: table title + - column: B + row: 2 + expected_value: 'Sources: The Treasury, Stats NZ, Reserve Bank of New Zealand' + label: publisher source attribution + - column: B + row: 5 + expected_value: Year ending 30 June + label: publisher period basis + - column: H + row: 6 + expected_value: Forecast + label: publisher status + - column: C + row: 21 + expected_value: 3 + label: ordinary-time footnote marker + - column: D + row: 21 + expected_value: Ordinary time. + label: ordinary-time footnote + - column: C + row: 22 + expected_value: 4 + label: actuals qualification marker + - column: D + row: 22 + expected_value: Measures are actuals except for real GDP and nominal GDP. + label: actuals qualification + measures: + - measure_id: average_weekly_earnings_annual_percentage_change + label: Average ordinary-time weekly earnings, annual percentage change, year ending 30 June 2030 (Forecast) + ordinal: 0 + column: H + source_column_id: year_ending_30_june_2030 + expected_column_header_row: 5 + expected_column_header: 2030 + concept: treasury.average_weekly_earnings_annual_percentage_change + source_concept: treasury.prefu26.average_weekly_earnings_annual_percentage_change + concept_relation: source_label + concept_authority: treasury + concept_evidence_url: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 + concept_evidence_notes: 'Table 4.1 row 17, Average weekly earnings3 (ann % chg). Publisher Year ending + 30 June 2030; Chronicle opening-year fiscal_year:2029. Publisher column status is Forecast. Footnote + 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures are actuals except for real + GDP and nominal GDP. 2026 earnings are therefore actuals despite the Forecast4 column heading; only + 2027–2031 earnings are forecasts. The published annual percentage change is retained unchanged; + no annual average, level, factor or period alignment is calculated.' + unit: percent + aggregation: sum + value_scale: 1 + expected_cell_type: number + shared_constraints: + - variable: earnings_component + operator: == + value: ordinary_time + label: Ordinary time + - variable: publication_status + operator: == + value: Forecast + label: Forecast +- record_set_id: treasury.prefu26.average_weekly_earnings.fy2030 + provenance_class: model_output + assertion: source_projection + record_set_spec_id: treasury.prefu26.average_weekly_earnings.fy2030.v1 + source_record_id_prefix: treasury.prefu26.average_weekly_earnings.fy2030 + sheet_name: Table 4.1 + period_type: fiscal_year + period: 2030 + period_coverage: + basis: fiscal + source_period_label: Year ending 30 June 2031 + start_date: '2030-07-01' + end_date: '2031-06-30' + notes: 'Publisher Year ending 30 June 2031; Chronicle opening-year fiscal_year:2030. Publisher column + status is Forecast. Footnote 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures + are actuals except for real GDP and nominal GDP. 2026 earnings are therefore actuals despite the + Forecast4 column heading; only 2027–2031 earnings are forecasts. The published annual percentage + change is retained unchanged; no annual average, level, factor or period alignment is calculated.' + geography_id: NZ + geography_level: country + geography_name: New Zealand + geography_vintage: current + entity: government + entity_role: forecaster + domain: economic_outlook + groupby_dimension: treasury.prefu26.assumption + shared_filters: + earnings_component: ordinary_time + publication_status: Forecast + rows: + - value_id: average_weekly_earnings_annual_percentage_change + label: Average weekly earnings (annual percentage change, ordinary time) + ordinal: 0 + row_number: 17 + expected_row_header_column: B + expected_row_header: Average weekly earnings3 (ann % chg) + table_record_kind: total + guard_cells: + - column: B + row: 1 + expected_value: Table 4.1 - Key economic assumptions for fiscal forecasts + label: table title + - column: B + row: 2 + expected_value: 'Sources: The Treasury, Stats NZ, Reserve Bank of New Zealand' + label: publisher source attribution + - column: B + row: 5 + expected_value: Year ending 30 June + label: publisher period basis + - column: I + row: 6 + expected_value: Forecast + label: publisher status + - column: C + row: 21 + expected_value: 3 + label: ordinary-time footnote marker + - column: D + row: 21 + expected_value: Ordinary time. + label: ordinary-time footnote + - column: C + row: 22 + expected_value: 4 + label: actuals qualification marker + - column: D + row: 22 + expected_value: Measures are actuals except for real GDP and nominal GDP. + label: actuals qualification + measures: + - measure_id: average_weekly_earnings_annual_percentage_change + label: Average ordinary-time weekly earnings, annual percentage change, year ending 30 June 2031 (Forecast) + ordinal: 0 + column: I + source_column_id: year_ending_30_june_2031 + expected_column_header_row: 5 + expected_column_header: 2031 + concept: treasury.average_weekly_earnings_annual_percentage_change + source_concept: treasury.prefu26.average_weekly_earnings_annual_percentage_change + concept_relation: source_label + concept_authority: treasury + concept_evidence_url: https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026 + concept_evidence_notes: 'Table 4.1 row 17, Average weekly earnings3 (ann % chg). Publisher Year ending + 30 June 2031; Chronicle opening-year fiscal_year:2030. Publisher column status is Forecast. Footnote + 3 (Table 4.1!C21:D21): Ordinary time. Footnote 4 (C22:D22): Measures are actuals except for real + GDP and nominal GDP. 2026 earnings are therefore actuals despite the Forecast4 column heading; only + 2027–2031 earnings are forecasts. The published annual percentage change is retained unchanged; + no annual average, level, factor or period alignment is calculated.' + unit: percent + aggregation: sum + value_scale: 1 + expected_cell_type: number + shared_constraints: + - variable: earnings_component + operator: == + value: ordinary_time + label: Ordinary time + - variable: publication_status + operator: == + value: Forecast + label: Forecast diff --git a/tests/test_chronicle_artifacts.py b/tests/test_chronicle_artifacts.py index c389c63b..ff407ec5 100644 --- a/tests/test_chronicle_artifacts.py +++ b/tests/test_chronicle_artifacts.py @@ -190,7 +190,8 @@ def test_every_nz_suite_manifest_declares_its_default_canonical_raw_key(): checked.append(manifest["source_id"]) assert set(checked) == set(NZ_BUNDLE_SOURCE_PREFIXES) - assert checked.count("treasury") == 4 + # G8-d3 adds PREFU 2026 (treasury/prefu26_economic_assumptions). + assert checked.count("treasury") == 5 def test_all_desnz_manifests_use_canonical_uk_r2_keys_and_pinned_bytes(): diff --git a/tests/test_chronicle_bundle.py b/tests/test_chronicle_bundle.py index 79c202c1..809049e6 100644 --- a/tests/test_chronicle_bundle.py +++ b/tests/test_chronicle_bundle.py @@ -196,6 +196,9 @@ def test_build_bundle_dir_nz_suite_uses_curated_sources(tmp_path, fake_build_bun assert call["year"] == 2023 assert "treasury-an24-01-fiscal-totals" in call["sources"] assert "treasury-estimates-of-appropriations-2026-27" in call["sources"] + assert "treasury-prefu26-economic-assumptions" in call["sources"] + assert "stats-nz-qes-average-weekly-earnings-june-2025" in call["sources"] + assert "stats-nz-qes-average-weekly-earnings-june-2026" in call["sources"] assert "stats-nz-census-2023-households-by-region-rc-99" in call["sources"] assert not set(call["sources"]) & set(UK_BUNDLE_SOURCES) @@ -403,6 +406,10 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): # Standalone warnings/duplicates are zero. Comparing the declared names # with MBIE through the bundle warning function adds two geography-name # warnings (nz-ta-018 and nz-ta-027); both publisher spellings are kept. + # G8-d3: three separate single-source builds measure +33 facts: +26 + # Stats NZ QES people and +7 Treasury economic assumptions (government). + # Three packages/tables; existing country:NZ, publishers, entities and + # quarter/fiscal-year keys; no bundle warnings or duplicate keys. assert summary["counts"] == { "aggregate_duplicate_key_count": 0, "entity_count": 12, @@ -416,8 +423,9 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): # packages, and 91,982 net for the Stat-Xplore extracts (183,804 UC # area facts by Payment Indicator replace the 91,902 all-claims ones; # Move to UC adds 80). - # G8-d4 adds 17 CY2023 ERP cells to the existing Stats NZ package. - "fact_count": 1579280, + # G8-d4 adds 17 CY2023 ERP cells to the existing Stats NZ package; + # G8-d3 adds 33 (26 QES levels, 7 PREFU26 earnings assumptions). + "fact_count": 1579313, # The same change adds 82,064 geography keys: 46,363 Scottish 2022 # output areas (UV404), 35,673 LSOA-level keys from the DESNZ LSOA # workbooks (Scotland's data zones already exist), the 26 Northern @@ -452,7 +460,7 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): "source_count": 56, # chronicle#326/#339/#356/#357/#358 add 28 packages and retire the three # all-claims UC area packages. - "source_package_count": 405, + "source_package_count": 408, # 1 semantic-duplicate warning, plus the publisher wording Chronicle # keeps as published: values two packages word differently, groupby # rows that drift inside one package (chronicle#265, #266), and the @@ -492,14 +500,14 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): if row_count == 1: assert row["aggregate_fact_key"].startswith("ledger.aggregate_fact.v2:") assert row["semantic_fact_key"].startswith("ledger.semantic_fact.v2:") - assert row_count == 1579280 + assert row_count == 1579313 assert provenance_classes <= { "administrative", "census", "model_output", "survey_aggregate", } - assert source_packages["source_package_count"] == 405 + assert source_packages["source_package_count"] == 408 assert source_packages["skipped_source_count"] == 17 assert sorted(item["source"] for item in source_packages["skipped_sources"]) == [ "census-acs-s0101-congressional-district-age-2024", @@ -520,7 +528,7 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): "jct-obbba-revenue-estimates-2025", "jct-tax-expenditures-2024", ] - assert coverage["fact_count"] == 1579280 + assert coverage["fact_count"] == 1579313 assert coverage["counts"]["by_source"] == { "bea": 446, "bfp_economic_outlook": 5, @@ -573,14 +581,14 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): "statbel_fiscal_income": 565, "statbel_fiscal_income_distribution": 14600, "statbel_population_structure": 36, - "treasury": 139, - "stats_nz": 2032, + "treasury": 146, + "stats_nz": 2058, "usda_snap": 852, "voa": 3001, "welshgov": 9567, } table_counts = coverage["counts"]["by_source_table"] - assert len(table_counts) == 347 + assert len(table_counts) == 350 assert ( table_counts["bea:NIPA Table 7.8. Supplements to Wages and Salaries by Type"] == 1 @@ -618,6 +626,26 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): ) assert table_counts["ird:Working for Families statistics - September 2025"] == 330 assert table_counts["treasury:AN24-01 fiscal totals, TY2019"] == 27 + assert ( + table_counts[ + "stats_nz:Quarterly Employment Survey June 2025 quarter, " + "Table 7: Average weekly earnings for FTEs, by sector" + ] + == 8 + ) + assert ( + table_counts[ + "stats_nz:Quarterly Employment Survey June 2026 quarter, " + "Table 7: Average weekly earnings for FTEs, by sector" + ] + == 18 + ) + assert ( + table_counts[ + "treasury:PREFU 2026 Table 4.1 - Key economic assumptions for fiscal forecasts" + ] + == 7 + ) assert ( table_counts[ "treasury:Expenditure - Budget 2026 Data from the Estimates of " @@ -1904,13 +1932,25 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): uk_feed_period_increments[f"fiscal_year:{year}"] += 7 for key, count in uk_feed_period_increments.items(): expected_period_counts[key] = expected_period_counts.get(key, 0) + count + # G8-d3: QES published quarters and PREFU opening-year fiscal periods. + for year, quarters in ( + (2023, (2, 3, 4)), + (2024, (1, 2, 3, 4)), + (2025, (1, 2, 3, 4)), + (2026, (1, 2)), + ): + for quarter in quarters: + expected_period_counts[f"quarter:{year}-Q{quarter}"] += 2 + for fiscal_year in range(2024, 2031): + expected_period_counts[f"fiscal_year:{fiscal_year}"] += 1 assert coverage["counts"]["by_period"] == expected_period_counts # country:NZ: 330 WFF (#209) + 5 national population (#211) + 27 Treasury # (#321) + 3,522 IRD I1 (#318) + 510 IRD I2 (#210) + 103 MSD (#319) # + 84 MBIE (#320) + 112 Treasury Budget 2026 expenses (B7 part 2) # + 1,413 Stats NZ household net worth + 16 B5 national census - # + nine G8-d1 national weekly-rent facts + one G8-d4 ERP fact = 6,132. - assert coverage["counts"]["by_geography"]["country:NZ"] == 6132 + # + nine G8-d1 national weekly-rent facts + one G8-d4 ERP fact + # + 33 G8-d3 earnings facts = 6,165. + assert coverage["counts"]["by_geography"]["country:NZ"] == 6165 for regional_council in (*range(1, 10), *range(12, 19)): assert ( coverage["counts"]["by_geography"][f"region:{regional_council:02d}"] == 31 @@ -1980,11 +2020,11 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): "dwelling": 274367, "family": 1700, "firm": 1440, - "government": 3562, + "government": 3569, "household": 676320, "institutional_sector": 6654, "pension_plan": 2, - "person": 521336, + "person": 521362, "return": 14952, "social_protection_scheme": 36, "tax_unit": 45268, diff --git a/tests/test_chronicle_nz_prefu_earnings.py b/tests/test_chronicle_nz_prefu_earnings.py new file mode 100644 index 00000000..9d2c110c --- /dev/null +++ b/tests/test_chronicle_nz_prefu_earnings.py @@ -0,0 +1,317 @@ +"""Literal-cell fidelity for Treasury PREFU 2026 earnings assumptions.""" + +from __future__ import annotations + +import hashlib +import re +from dataclasses import replace +from decimal import Decimal +from functools import lru_cache +from pathlib import Path + +import openpyxl +import pytest +import yaml + +from chronicle.artifacts import build_r2_key +from chronicle.bundle import _dimension_label_reports, build_bundle_coverage +from chronicle.consumer_contract import ( + consumer_fact_rows, + validate_consumer_fact_contract, +) +from chronicle.core import validate_facts +from chronicle.source_package import ( + SOURCE_PACKAGE_ALIASES, + load_source_package, + validate_source_package, +) +from chronicle.sources import build_source_cell_key, validate_source_cells +from chronicle.sources.specs import resolve_source_record + +ROOT = Path(__file__).resolve().parents[1] +DIRECTORY = Path("treasury/prefu26_economic_assumptions") +PACKAGE = ROOT / "packages" / DIRECTORY +DATA = ROOT / "db/data" / DIRECTORY +ALIAS = "treasury-prefu26-economic-assumptions" +WORKBOOK = "prefu26-charts-data.xlsx" +SHA256 = "e2486375dde515d0722f8c3022f481804bb014beb83c81b8bfc99bc9426544d9" +URL = ( + "https://www.treasury.govt.nz/sites/default/files/2026-09/prefu26-charts-data.xlsx" +) +PAGE = "https://www.treasury.govt.nz/publications/efu/pre-election-economic-and-fiscal-update-2026" +SHEET = "Table 4.1" + +# This independent literal map is not derived from source-package declarations. +# Footnote 4 qualifies D6: earnings are actual, although the column says Forecast4. +PUBLISHED_CELLS = ( + ("C17", 2025, "Actual", "4.2", "observation"), + ("D17", 2026, "Forecast4", "2.9", "observation"), + ("E17", 2027, "Forecast", "2.7", "source_projection"), + ("F17", 2028, "Forecast", "3", "source_projection"), + ("G17", 2029, "Forecast", "3.2", "source_projection"), + ("H17", 2030, "Forecast", "3.4", "source_projection"), + ("I17", 2031, "Forecast", "3.4", "source_projection"), +) + + +@lru_cache +def _package(): + return load_source_package(PACKAGE) + + +@lru_cache +def _cells(): + return _package().build_source_cells(2026) + + +@lru_cache +def _facts(): + return _package().build_facts(2026, cells=_cells()) + + +@lru_cache +def _specs(): + return _package().build_source_record_specs(2026) + + +def _sheet_cells(): + return {cell.address: cell for cell in _cells() if cell.sheet_name == SHEET} + + +def test_prefu_alias_and_package_validation(): + assert SOURCE_PACKAGE_ALIASES[ALIAS] == DIRECTORY + assert _package().artifact.artifact_year == 2026 + assert _package().artifact.sheets == ("Index", SHEET) + report = validate_source_package(PACKAGE, year=2026) + assert report.valid, report.to_dict() + assert not report.warnings + assert report.counts == { + "record_set_count": 7, + "row_count": 7, + "measure_count": 7, + "source_record_count": 7, + "source_region_count": 7, + } + + +def test_prefu_unchanged_workbook_receipt_license_and_canonical_r2_key(): + manifest = yaml.safe_load((DATA / "manifest.yaml").read_text()) + entry = manifest["files"][2026] + content = (DATA / WORKBOOK).read_bytes() + assert manifest["source_id"] == "treasury" + assert manifest["package_id"] == ALIAS + assert manifest["published_at"] == "2026-09-29" + assert manifest["source_page"] == manifest["license_url"] == PAGE + assert manifest["license"] == "CC BY 4.0" + assert "Crown" in manifest["attribution"] + assert entry["filename"] == WORKBOOK + assert entry["source_url"] == URL + assert entry["sha256"] == hashlib.sha256(content).hexdigest() == SHA256 + assert entry["size_bytes"] == len(content) == 664_670 + assert entry["fetched_at"] == "2026-10-22T07:57:29Z" + key = build_r2_key( + source_id="treasury", + package_id=ALIAS, + year=2026, + sha256=SHA256, + filename=WORKBOOK, + ) + assert entry["storage"]["r2"] == { + "provider": "r2", + "bucket": "ledger-raw", + "key": key, + "uri": f"r2://ledger-raw/{key}", + } + + +def test_prefu_complete_declared_sheet_ranges_and_publisher_footnotes(): + book = openpyxl.load_workbook(DATA / WORKBOOK, data_only=True, read_only=True) + try: + assert {cell.sheet_name for cell in _cells()} == {"Index", SHEET} + for name in ("Index", SHEET): + parsed = { + cell.address: cell for cell in _cells() if cell.sheet_name == name + } + sheet = book[name] + assert len(parsed) == sheet.max_row * sheet.max_column + for row in sheet.iter_rows(): + for cell in row: + # ReadOnly EmptyCell has no coordinate; its grid address + # is nevertheless counted by the complete-range check. + if cell.value is not None: + assert parsed[cell.coordinate].raw_value == cell.value + finally: + book.close() + assert validate_source_cells(_cells()).valid + cells = _sheet_cells() + assert cells["B17"].raw_value == "Average weekly earnings3 (ann % chg)" + assert cells["C21"].raw_value == 3 + assert cells["D21"].raw_value == "Ordinary time." + assert cells["C22"].raw_value == 4 + assert cells["D22"].raw_value == ( + "Measures are actuals except for real GDP and nominal GDP." + ) + index = {cell.address: cell for cell in _cells() if cell.sheet_name == "Index"} + assert index["A2"].raw_value == "Published 29 September 2026" + assert "Creative Commons Attribution 4.0" in index["A13"].raw_value + assert "Attribution to the Crown" in index["A14"].raw_value + + +@pytest.mark.parametrize("address,year,status,value,assertion", PUBLISHED_CELLS) +def test_prefu_every_published_earnings_cell_exactly_once( + address, year, status, value, assertion +): + cell = _sheet_cells()[address] + assert Decimal(str(cell.raw_value)) == Decimal(value) + facts = [fact for fact in _facts() if fact.period.value == year - 1] + assert len(facts) == 1 + fact = facts[0] + assert Decimal(str(fact.value)) == Decimal(value) + assert fact.assertion == assertion + assert fact.provenance_class == "model_output" + assert fact.survey_instrument is None + assert fact.period.type == "fiscal_year" + assert fact.period_coverage.basis == "fiscal" + assert fact.period_coverage.source_period_label == f"Year ending 30 June {year}" + assert fact.period_coverage.start_date == f"{year - 1}-07-01" + assert fact.period_coverage.end_date == f"{year}-06-30" + assert "Ordinary time." in fact.period_coverage.notes + assert "Measures are actuals except for real GDP and nominal GDP." in ( + fact.period_coverage.notes + ) + assert fact.filters["earnings_component"] == "ordinary_time" + assert fact.filters["publication_status"] == status + assert { + (constraint.variable, constraint.operator, constraint.value) + for constraint in fact.constraints + } == { + ("earnings_component", "==", "ordinary_time"), + ("publication_status", "==", status), + } + assert fact.measure.unit == "percent" + assert fact.measure.source_concept == ( + "treasury.prefu26.average_weekly_earnings_annual_percentage_change" + ) + assert build_source_cell_key(cell) in fact.source_cell_keys + selected = [spec for spec in _specs() if spec.period == year - 1] + assert len(selected) == 1 + assert selected[0].selector.address == address + assert selected[0].selector.expected_row_header_address == "B17" + assert selected[0].selector.expected_column_header_address == f"{address[0]}5" + + +def test_prefu_fact_boundary_labels_and_independent_coverage(): + assert len(_facts()) == 7 + assert validate_facts(_facts()).valid + rows = consumer_fact_rows(_facts()) + assert validate_consumer_fact_contract(_facts()).valid + assert _dimension_label_reports(ALIAS, rows) == ([], []) + for fact in _facts(): + assert fact.source.source_name == "treasury" + assert fact.geography.id == "NZ" + assert fact.geography.name == "New Zealand" + assert fact.entity.name == "government" + assert fact.layout.groupby_dimension_label == "Economic assumption" + assert fact.layout.groupby_value_label == ( + "Average weekly earnings (annual percentage change, ordinary time)" + ) + assert "ordinary-time" in fact.layout.measure_label + assert set(fact.dimension_labels) == { + *fact.filters, + fact.layout.groupby_dimension, + } + for dimension, value in fact.filters.items(): + assert fact.dimension_labels[dimension] + assert fact.dimension_value_labels[dimension][str(value)] + coverage = build_bundle_coverage(rows) + assert coverage["fact_count"] == 7 + assert coverage["counts"]["by_source"] == {"treasury": 7} + assert coverage["counts"]["by_geography"] == {"country:NZ": 7} + assert coverage["counts"]["by_entity"] == {"government": 7} + assert coverage["counts"]["by_period"] == { + "fiscal_year:2024": 1, + "fiscal_year:2025": 1, + "fiscal_year:2026": 1, + "fiscal_year:2027": 1, + "fiscal_year:2028": 1, + "fiscal_year:2029": 1, + "fiscal_year:2030": 1, + } + assert coverage["duplicates"] == { + "aggregate_fact_keys": [], + "semantic_fact_keys": [], + } + + +# Each authored guard is probed on a selected spec. Keep this map independent +# of the YAML so deleting a declaration makes its regression fail. +GUARD_CASES = ( + (0, "B17", "row header"), + *((index, f"{column}5", "column header") for index, column in enumerate("CDEFGHI")), + (0, "B1", "table title"), + (0, "B2", "publisher source attribution"), + (0, "B5", "publisher period basis"), + *( + (index, f"{column}6", "publisher status") + for index, column in enumerate("CDEFGHI") + ), + (0, "C21", "ordinary-time footnote marker"), + (0, "D21", "ordinary-time footnote"), + (0, "C22", "actuals qualification marker"), + (0, "D22", "actuals qualification"), +) + + +def test_prefu_every_authored_guard_has_an_independent_regression(): + declared = set() + for spec in _specs(): + selector = spec.selector + declared.add(selector.expected_row_header_address) + declared.add(selector.expected_column_header_address) + declared.update(guard.address for guard in selector.guard_cells) + assert declared == {address for _, address, _ in GUARD_CASES} + assert len(GUARD_CASES) == 22 + + +@pytest.mark.parametrize( + "spec_index,address,message", + GUARD_CASES, + ids=[address for _, address, _ in GUARD_CASES], +) +def test_prefu_each_guard_rejects_publisher_drift(spec_index, address, message): + changed = [ + replace(cell, raw_value="unexpected publisher layout") + if cell.sheet_name == SHEET and cell.address == address + else cell + for cell in _cells() + ] + with pytest.raises(ValueError, match=re.escape(message)): + resolve_source_record(changed, _specs()[spec_index]) + + +def test_prefu_row_shift_is_rejected_before_emitting_facts(tmp_path): + payload = yaml.safe_load((PACKAGE / "source_package.yaml").read_text()) + payload["record_sets"][0]["rows"][0]["row_number"] = 16 + path = tmp_path / "source_package.yaml" + path.write_text(yaml.safe_dump(payload, sort_keys=False)) + with pytest.raises(ValueError, match="row header"): + load_source_package(path).build_facts(2026, cells=_cells()) + + +@pytest.mark.parametrize("address", (cell[0] for cell in PUBLISHED_CELLS)) +def test_prefu_each_selected_value_requires_a_numeric_publisher_cell(address): + spec = next(spec for spec in _specs() if spec.selector.address == address) + changed = [ + replace(cell, cell_type="text", raw_value="suppressed") + if cell.sheet_name == SHEET and cell.address == address + else cell + for cell in _cells() + ] + with pytest.raises(ValueError, match="expected cell type 'number'"): + resolve_source_record(changed, spec) + + +def test_prefu_build_year_does_not_relabel_published_reference_periods(): + for year in (2023, 2032): + facts = _package().build_facts(year, cells=_cells()) + assert facts == _facts() diff --git a/tests/test_chronicle_nz_qes_earnings.py b/tests/test_chronicle_nz_qes_earnings.py new file mode 100644 index 00000000..faaa8917 --- /dev/null +++ b/tests/test_chronicle_nz_qes_earnings.py @@ -0,0 +1,506 @@ +"""Literal publisher-cell and layout gates for Stats NZ's QES weekly earnings.""" + +from __future__ import annotations + +from collections import Counter +from copy import deepcopy +from dataclasses import replace +from functools import lru_cache +import hashlib +import os +from pathlib import Path +import re + +import pytest +import yaml + +from chronicle.artifacts import build_r2_key +from chronicle.bundle import _dimension_label_reports, build_bundle_coverage +from chronicle.consumer_contract import ( + consumer_fact_rows, + validate_consumer_fact_contract, +) +from chronicle.core import validate_facts +from chronicle.source_package import ( + SOURCE_PACKAGE_ALIASES, + load_source_package, + validate_source_package, +) +from chronicle.sources import build_source_cell_key, validate_source_cells +from chronicle.sources.specs import ( + build_cells_by_sheet_address, + resolve_source_record, +) +from chronicle.suite import build_source_suite + +ROOT = Path(__file__).resolve().parents[1] +SHEET = "Table 7" +ALIASES = { + 2025: "stats-nz-qes-average-weekly-earnings-june-2025", + 2026: "stats-nz-qes-average-weekly-earnings-june-2026", +} +DIRECTORIES = { + year: Path(f"stats_nz/qes_average_weekly_earnings_june_{year}") for year in ALIASES +} +ARTIFACTS = { + 2025: ( + "25053dcbd343320cad72e2896475eaebaf5f5bb0b5965ca788506ca15efcea30", + 135_784, + ), + 2026: ( + "1af2e7e37f1c108a2656842cf1f519c903e1a982bcdc03ee02d0ad888ebc3a97", + 124_556, + ), +} + +# Audited from the two publisher workbooks independently of package YAML. +# A vintage, quarter, series, address and literal value identify each fact. +EXPECTED_CELLS = ( + (2025, "2023-Q2", "QEMQ.SBSZ9A", "P13", 1502.27), + (2025, "2023-Q2", "QEMQ.SBSZ9Z", "T13", 1530.82), + (2025, "2023-Q3", "QEMQ.SBSZ9A", "P14", 1528.92), + (2025, "2023-Q3", "QEMQ.SBSZ9Z", "T14", 1557.93), + (2025, "2023-Q4", "QEMQ.SBSZ9A", "P15", 1556.16), + (2025, "2023-Q4", "QEMQ.SBSZ9Z", "T15", 1587.94), + (2025, "2024-Q1", "QEMQ.SBSZ9A", "P16", 1563.54), + (2025, "2024-Q1", "QEMQ.SBSZ9Z", "T16", 1593), + (2026, "2024-Q2", "QEMQ.SBSZ9A", "P13", 1586.32), + (2026, "2024-Q2", "QEMQ.SBSZ9Z", "T13", 1612.27), + (2026, "2024-Q3", "QEMQ.SBSZ9A", "P14", 1595.11), + (2026, "2024-Q3", "QEMQ.SBSZ9Z", "T14", 1620.53), + (2026, "2024-Q4", "QEMQ.SBSZ9A", "P15", 1622.73), + (2026, "2024-Q4", "QEMQ.SBSZ9Z", "T15", 1651.31), + (2026, "2025-Q1", "QEMQ.SBSZ9A", "P16", 1637.2), + (2026, "2025-Q1", "QEMQ.SBSZ9Z", "T16", 1665.72), + (2026, "2025-Q2", "QEMQ.SBSZ9A", "P17", 1652.72), + (2026, "2025-Q2", "QEMQ.SBSZ9Z", "T17", 1678.9), + (2026, "2025-Q3", "QEMQ.SBSZ9A", "P18", 1661.12), + (2026, "2025-Q3", "QEMQ.SBSZ9Z", "T18", 1687.51), + (2026, "2025-Q4", "QEMQ.SBSZ9A", "P19", 1681.06), + (2026, "2025-Q4", "QEMQ.SBSZ9Z", "T19", 1712.05), + (2026, "2026-Q1", "QEMQ.SBSZ9A", "P20", 1685.39), + (2026, "2026-Q1", "QEMQ.SBSZ9Z", "T20", 1715.66), + (2026, "2026-Q2", "QEMQ.SBSZ9A", "P21", 1700.68), + (2026, "2026-Q2", "QEMQ.SBSZ9Z", "T21", 1729.95), +) +EXPECTED_COVERAGE = { + "2023-Q2": ("2023-04-01", "2023-06-30"), + "2023-Q3": ("2023-07-01", "2023-09-30"), + "2023-Q4": ("2023-10-01", "2023-12-31"), + "2024-Q1": ("2024-01-01", "2024-03-31"), + "2024-Q2": ("2024-04-01", "2024-06-30"), + "2024-Q3": ("2024-07-01", "2024-09-30"), + "2024-Q4": ("2024-10-01", "2024-12-31"), + "2025-Q1": ("2025-01-01", "2025-03-31"), + "2025-Q2": ("2025-04-01", "2025-06-30"), + "2025-Q3": ("2025-07-01", "2025-09-30"), + "2025-Q4": ("2025-10-01", "2025-12-31"), + "2026-Q1": ("2026-01-01", "2026-03-31"), + "2026-Q2": ("2026-04-01", "2026-06-30"), +} +FOOTNOTE = ( + "Average weekly earnings are calculated by dividing earnings by the number of FTEs." +) +COMMON_GUARDS = { + "A1": "Table 7", + "A3": "Average weekly earnings for FTEs(1)", + "A4": "By sector", + "A8": "Series ref: QEMQ", + "A10": "($)", + "A12": "Quarter", + "P6": "Total", + "P7": "Ordinary time", + "T7": "Total", + "P8": "SBSZ9A", + "T8": "SBSZ9Z", + "B49": FOOTNOTE, +} +# Coordinates and values are independent of YAML: dropping a guard does not +# remove its mutation regression case. +EXPECTED_GUARDS = { + 2025: { + **COMMON_GUARDS, + "A13": "2023", + "A16": "2024", + "C13": "Jun", + "C14": "Sep", + "C15": "Dec", + "C16": "Mar", + }, + 2026: { + **COMMON_GUARDS, + "A13": "2024", + "A16": "2025", + "A20": "2026", + "C13": "Jun", + "C14": "Sep", + "C15": "Dec", + "C16": "Mar", + "C17": "Jun", + "C18": "Sep", + "C19": "Dec", + "C20": "Mar", + "C21": "Jun", + }, +} +GUARD_CASES = tuple( + (year, address) for year, guards in EXPECTED_GUARDS.items() for address in guards +) + + +@lru_cache +def _package(year): + return load_source_package( + os.environ.get(f"CHRONICLE_NZ_QES_{year}_TEST_PACKAGE", ALIASES[year]) + ) + + +@lru_cache +def _cells(year): + return _package(year).build_source_cells(year) + + +@lru_cache +def _cell_index(year): + return build_cells_by_sheet_address(_cells(year)) + + +@lru_cache +def _specs(year): + return _package(year).build_source_record_specs(year) + + +@lru_cache +def _facts(year): + return _package(year).build_facts(year, cells=_cells(year)) + + +def _assert_expected_publisher_map(year, specs): + expected = { + (period, series): (SHEET, address) + for vintage, period, series, address, _value in EXPECTED_CELLS + if vintage == year + } + actual = { + (spec.period, spec.filters["earnings_series_reference"]): ( + spec.selector.sheet_name, + spec.selector.address, + ) + for spec in specs + } + assert len(specs) == len(actual) == len(expected), "publisher cell count drift" + assert actual == expected, ( + f"selected publisher cells {actual!r}; expected {expected!r}" + ) + + +@lru_cache +def _guard_index(year): + guards = {} + for spec in _specs(year): + selector = spec.selector + entries = ( + ( + selector.expected_row_header_address, + selector.expected_row_header, + "row header", + ), + ( + selector.expected_column_header_address, + selector.expected_column_header, + "column header", + ), + *( + (item.address, item.expected_value, item.label) + for item in selector.guard_cells + ), + ) + assert selector.sheet_name == SHEET + assert not selector.range_label_guards + for address, expected, label in entries: + if address is None: + continue + if address in guards: + assert guards[address][1] == expected + else: + guards[address] = (spec, expected, label) + return guards + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_alias_and_package_validation(year): + assert SOURCE_PACKAGE_ALIASES[ALIASES[year]] == DIRECTORIES[year] + report = validate_source_package(ALIASES[year], year=year) + assert report.valid, report.to_dict() + assert not report.warnings + count = 8 if year == 2025 else 18 + assert report.counts["source_record_count"] == count + assert report.counts["record_set_count"] == (4 if year == 2025 else 9) + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_publisher_bytes_and_country_storage_are_pinned(year): + directory = ROOT / "db/data" / DIRECTORIES[year] + manifest = yaml.safe_load((directory / "manifest.yaml").read_text()) + entry = manifest["files"][year] + filename = f"quarterly-employment-survey-june-{year}-quarter.xlsx" + content = (directory / filename).read_bytes() + sha256, size = ARTIFACTS[year] + source_url = ( + "https://www.stats.govt.nz/assets/Uploads/Labour-market-statistics/" + f"Labour-market-statistics-June-{year}-quarter/Download-data/{filename}" + ) + assert hashlib.sha256(content).hexdigest() == entry["sha256"] == sha256 + assert len(content) == entry["size_bytes"] == size + assert manifest["license"]["url"] == "https://creativecommons.org/licenses/by/4.0/" + assert manifest["license"]["evidence_url"] == ( + "https://www.stats.govt.nz/about-us/copyright/" + ) + assert entry["filename"] == filename + assert entry["source_url"] == source_url + assert entry["fetched_at"] == "2026-10-22T07:57:28Z" + key = build_r2_key( + source_id="stats_nz", + package_id=DIRECTORIES[year].name, + year=year, + sha256=sha256, + filename=filename, + ) + assert key.startswith(f"raw/nz/stats_nz/{DIRECTORIES[year].name}/{year}/{sha256}/") + assert entry["storage"]["r2"] == { + "provider": "r2", + "bucket": "ledger-raw", + "key": key, + "uri": f"r2://ledger-raw/{key}", + } + assert {fact.source.raw_r2_uri for fact in _facts(year)} == { + entry["storage"]["r2"]["uri"] + } + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_preserves_all_worksheets_and_nonemitted_blocks(year): + cells = _cells(year) + sizes = { + "Contents": 41 * 9, + "Table 1": 54 * 9, + "Table 2": 54 * 9, + "Table 3": (75 if year == 2025 else 74) * 13, + "Table 4": 53 * 9, + "Table 5": 53 * 9, + "Table 6": 55 * 21, + "Table 7": 51 * 21, + "Table 8": 51 * 21, + "Table 9": 51 * 21, + "Table 10": (79 if year == 2025 else 78) * 29, + "Table 11": (79 if year == 2025 else 78) * 29, + "Table 12": (80 if year == 2025 else 79) * 29, + "Table 13": (80 if year == 2025 else 79) * 29, + "Table 14": 31 * 9, + "Table 15": 32 * 9, + } + assert Counter(cell.sheet_name for cell in cells) == sizes + assert validate_source_cells(cells).valid + assert _cell_index(year)[(SHEET, "R8")].raw_value == "SBSZ9B" + assert _cell_index(year)[(SHEET, "D6")].raw_value == "Public sector" + assert _cell_index(year)[(SHEET, "J6")].raw_value == "Private sector" + assert _cell_index(year)[(SHEET, "A23")].raw_value == ( + "Percentage change from the same quarter of previous year" + ) + assert _cell_index(year)[(SHEET, "A36")].raw_value == ( + "Percentage change from previous quarter" + ) + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_every_published_value_matches_literal_cell_map(year): + _assert_expected_publisher_map(year, _specs(year)) + facts = { + (fact.period.value, fact.filters["earnings_series_reference"]): fact + for fact in _facts(year) + } + expected = [entry for entry in EXPECTED_CELLS if entry[0] == year] + assert len(facts) == len(_facts(year)) == len(expected) + for _vintage, period, series, address, value in expected: + fact = facts[(period, series)] + cell = _cell_index(year)[(SHEET, address)] + assert cell.raw_value == fact.value == value + assert build_source_cell_key(cell) == fact.source_cell_keys[0] + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_one_published_cell_per_fact_without_arithmetic(year): + for fact, spec in zip(_facts(year), _specs(year), strict=True): + assert spec.value_scale == 1 + assert spec.divisor_selector is None + assert spec.round_to is None + assert spec.selector.end_address is None + assert spec.selector.expected_cell_type == "number" + assert spec.selector.address.startswith(("P", "T")) + assert 13 <= int(spec.selector.address[1:]) <= (16 if year == 2025 else 21) + assert fact.measure.unit == "nzd_per_week" + assert fact.aggregation.method == "mean" + assert fact.aggregation.denominator is None + assert fact.source.source_sha256 == ARTIFACTS[year][0] + assert fact.source_record_id == spec.source_record_id + assert fact.layout.source_column_id in {"SBSZ9A", "SBSZ9Z"} + assert build_source_cell_key(_cell_index(year)[(SHEET, "B49")]) in ( + fact.source_cell_keys + ) + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_periods_and_publisher_observation_scope(year): + facts = _facts(year) + assert validate_facts(facts).valid + assert validate_consumer_fact_contract(facts).valid + for fact in facts: + assert fact.period.type == "quarter" + coverage = fact.period_coverage + assert (coverage.start_date, coverage.end_date) == EXPECTED_COVERAGE[ + fact.period.value + ] + assert coverage.basis == "calendar" + assert (fact.geography.level, fact.geography.id, fact.geography.name) == ( + "country", + "NZ", + "New Zealand", + ) + assert (fact.entity.name, fact.entity.role) == ( + "person", + "full_time_equivalent_employee", + ) + assert fact.provenance_class == "survey_aggregate" + assert fact.survey_instrument == "Quarterly Employment Survey (QES)" + assert fact.assertion == "observation" + notes = coverage.notes + assert "20th" in notes and "middle month" in notes + assert "pay week" in notes.lower() + assert _package(year).build_facts(2031, cells=_cells(year)) == facts + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_every_dimension_and_value_has_a_label(year): + facts = _facts(year) + assert _dimension_label_reports(ALIASES[year], consumer_fact_rows(facts)) == ( + [], + [], + ) + for fact in facts: + ordinary = fact.filters["earnings_series_reference"] == "QEMQ.SBSZ9A" + assert fact.filters == { + "earnings_denominator": "fte", + "seasonal_adjustment": "actual", + "earnings_sector": "all_sectors", + "earnings_series_reference": "QEMQ.SBSZ9A" if ordinary else "QEMQ.SBSZ9Z", + "earnings_component": "ordinary_time" if ordinary else "total", + } + assert fact.layout.groupby_dimension == "earnings_sector" + assert fact.layout.groupby_value_label == "All sectors" + for dimension, value in fact.filters.items(): + assert fact.dimension_labels[dimension] + assert fact.dimension_value_labels[dimension][str(value)] + label = fact.layout.measure_label + assert fact.filters["earnings_series_reference"] in label + assert "FTE" in label + assert "actual" in label.lower() + assert "not seasonally adjusted" in label.lower() + assert ("ordinary" if ordinary else "total") in label.lower() + + +def test_qes_shared_quarters_agree_and_each_quarter_is_emitted_once(): + # Five identical shared quarters are evidence about these publisher + # vintages; no values are reconciled, averaged or computed from them. + for earlier_row, later_row in ((17, 13), (18, 14), (19, 15), (20, 16), (21, 17)): + for column in ("P", "T"): + assert _cell_index(2025)[(SHEET, f"{column}{earlier_row}")].raw_value == ( + _cell_index(2026)[(SHEET, f"{column}{later_row}")].raw_value + ) + facts = [*_facts(2025), *_facts(2026)] + assert len(facts) == 26 + assert ( + len( + { + (fact.period.value, fact.filters["earnings_series_reference"]) + for fact in facts + } + ) + == 26 + ) + assert Counter(fact.period.value for fact in facts) == { + period: 2 for period in EXPECTED_COVERAGE + } + coverage = build_bundle_coverage(consumer_fact_rows(facts)) + assert coverage["fact_count"] == 26 + assert coverage["counts"]["by_geography"] == {"country:NZ": 26} + assert not coverage["duplicates"]["aggregate_fact_keys"] + assert not coverage["duplicates"]["semantic_fact_keys"] + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_every_required_guard_is_declared(year): + # The workbook stores year anchors as strings; Chronicle's YAML compiler + # normalizes numeric-looking guard values to integers before comparison. + assert { + address: str(item[1]) for address, item in _guard_index(year).items() + } == EXPECTED_GUARDS[year] + + +@pytest.mark.parametrize(("year", "address"), GUARD_CASES) +def test_qes_each_guard_rejects_mutated_publisher_cell(year, address): + assert address in _guard_index(year), f"Missing publisher guard: {SHEET}!{address}" + spec, expected, label = _guard_index(year)[address] + coordinate = (SHEET, address) + assert _cell_index(year)[coordinate].raw_value == EXPECTED_GUARDS[year][address] + assert str(expected) == EXPECTED_GUARDS[year][address] + resolve_source_record(_cells(year), spec, cells_by_sheet_address=_cell_index(year)) + changed_index = { + **_cell_index(year), + coordinate: replace( + _cell_index(year)[coordinate], raw_value="unexpected publisher layout" + ), + } + with pytest.raises(ValueError, match=re.escape(label)): + resolve_source_record(_cells(year), spec, cells_by_sheet_address=changed_index) + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_column_shift_yaml_mutant_is_rejected(year): + package = _package(year) + changed_sets = [] + for declared in package.record_sets: + payload = deepcopy(declared.payload) + for measure in payload["measures"]: + if measure["column"] == "P": + measure.update(column="R", expected_column_header="SBSZ9B") + changed_sets.append(replace(declared, payload=payload)) + changed = replace(package, record_sets=tuple(changed_sets)) + with pytest.raises(AssertionError, match="selected publisher cells"): + _assert_expected_publisher_map(year, changed.build_source_record_specs(year)) + + +def test_qes_duplicate_quarter_from_earlier_vintage_yaml_mutant_is_rejected(): + package = _package(2025) + previous = package.record_sets[-1] + payload = deepcopy(previous.payload) + payload.update( + record_set_id="stats_nz.qes.awe.2024q2", + source_record_id_prefix="stats_nz.qes.awe.2024q2", + period="2024-Q2", + ) + payload["rows"][0].update(row_number=17, expected_row_header="Jun") + extra_quarter = replace(previous, payload=payload) + changed = replace(package, record_sets=(*package.record_sets, extra_quarter)) + with pytest.raises(AssertionError, match="publisher cell count drift"): + _assert_expected_publisher_map(2025, changed.build_source_record_specs(2025)) + + +@pytest.mark.parametrize("year", ALIASES) +def test_qes_build_suite_passes_source_acceptance(year, tmp_path): + report = build_source_suite(ALIASES[year], tmp_path / "suite", year=year) + assert report.valid + assert report.agent_acceptance.valid + assert all(report.agent_acceptance.checks.values()) + assert report.source_records.resolved_count == (8 if year == 2025 else 18) + assert report.source_records.lineage_coverage == 1 + assert not report.agent_acceptance.errors diff --git a/tests/test_source_package_alias_drift.py b/tests/test_source_package_alias_drift.py index 0e9cf838..cc74f947 100644 --- a/tests/test_source_package_alias_drift.py +++ b/tests/test_source_package_alias_drift.py @@ -163,7 +163,8 @@ def test_nz_bundle_sources_match_nz_prefixed_aliases(): ) assert NZ_BUNDLE_SOURCE_PREFIXES == ("ird", "mbie", "msd", "stats_nz", "treasury") - assert len(NZ_BUNDLE_SOURCES) == 67 + # G8-d3 adds two Stats NZ QES vintages and Treasury PREFU 2026. + assert len(NZ_BUNDLE_SOURCES) == 70 assert NZ_BUNDLE_SOURCES == expected == nz_bundle_sources_from_aliases() assert_nz_bundle_sources_match_aliases() @@ -193,7 +194,7 @@ def test_nz_bundle_sources_cover_every_nz_package_on_disk(): for manifest in (root / prefix).rglob("source_package.yaml") } - assert len(on_disk) == 67 + assert len(on_disk) == 70 assert on_disk == {SOURCE_PACKAGE_ALIASES[alias] for alias in NZ_BUNDLE_SOURCES}