Public Health Observatory Audit Skill
Overview
Solve algorithmic audit tasks against the Public Health Observatory data portal. Each task asks you to complete a registered multi-module evidence audit using only the read-only portal. You must return one JSON object conforming exactly to the supplied answer template.
Portal Access
The portal is a read-only Web application. All evidence comes from browse pages or CSV exports. Never modify data — every filter, release-resolution step, and quality exclusion must be reproducible from the portal alone.
Data Endpoints
| Endpoint |
Returns |
GET /geographies/states |
State reference: FIPS, abbreviation, name, region, census division |
GET /geographies/counties |
County reference: FIPS, state, name, region, RUCC, metro class |
GET /geographies/countries |
Country reference: ISO3, name, region |
GET /data/state-health |
State health observations: measure, value type, source type, value, SE, sample size, quality flags |
GET /data/state-socioeconomic |
State socioeconomic: poverty, income, education, unemployment, uninsured, etc. |
GET /data/county-health |
County health observations: same schema as state health |
GET /data/county-socioeconomic |
County socioeconomic: same fields as state |
GET /data/country-indicators |
Country indicators: indicator id, value, quality flag |
GET /data/revisions |
Revision notices: domain, entity, field, old/new value, status |
GET /download?dataset=X&format=csv |
Full CSV export of any dataset |
Data Pipeline
Step 1 — Release Resolution
For every analysis, you must resolve which release to use. The standard method is Registered Final Release Resolution:
- Restrict to rows where
release_status == "FINAL".
- Group by the natural entity key — for state health this is
(state_abbr, year, measure_id, value_type, source_type); for socioeconomic it is (state_abbr, year); for counties add county_fips.
- Within each group, pick the row with the highest revision number.
- Break ties by picking the latest
released_at timestamp.
Never average across releases or value-types. Always pick exactly one row per group.
Step 2 — Quality Exclusion
After resolution, exclude any row that meets any of these conditions:
quality_flag is INVALID_SCALE, INVALID, or WITHDRAWN
suppression_flag is "1" (suppressed)
- The
value field is empty, whitespace-only, or the literal string null
Suppressed, invalid, and blank values are unavailable — never zero-fill, never impute unless the module explicitly requires imputation.
Step 3 — Revision Application
The revisions table records post-publication corrections:
APPLIED revisions are already reflected in higher revision numbers of the same observation and do not require separate application after Step 1.
PENDING and WITHDRAWN revisions must not alter resolved values.
- For the country domain, revision events may document scale corrections (e.g., factor-of-10 errors). Use the
status field to decide whether an event affects the usable value.
Step 4 — Filter by Value Type and Source Type
Most protocols specify which combination to use. Common filters:
AGE_ADJUSTED_AND_DIRECT_SURVEY_AND_FINAL — use only value_type=AGE_ADJUSTED, source_type=DIRECT_SURVEY
CRUDE_AND_DIRECT_SURVEY_AND_FINAL — use only value_type=CRUDE, source_type=DIRECT_SURVEY
FINAL alone (for socioeconomic) — use only release_status=FINAL
Apply the filter after release resolution. Each measure in the analysis should use exactly one resolved value per geography-year.
Cohort Construction
Every module declares a cohort. Build them in order:
- Basic-complete — The core variables are all non-null, non-suppressed, and valid for a given geography-year.
- Primary cohort — Basic-complete in the reference year (e.g., 2023).
- Balanced panel cohort — Basic-complete in every requested year.
- Machine-learning / broad cohort — Primary-cohort members also complete for an extended set of features.
- Strict dual-source cohort — Complete for outcome, both exposure variants, and adjustments in every year.
Preserve the exact order of state codes, county FIPS codes, or ISO3 codes as they appear in the geography reference. Sorted ascending is the default unless the answer template specifies a different order.
Statistical Computation (Pure Python / JS)
When numpy/scipy are unavailable, implement the following from scratch:
Fixed Effects (Within-Transformation)
For two-way (state + year) FE:
- Compute state means, year means, and grand means for both outcome and each predictor.
- Transform:
y_tilde = y - y_bar_state - y_bar_year + y_bar_grand
- Run OLS on transformed data without intercept.
- Effective df =
n_obs - n_predictors - (n_states - 1) - (n_years - 1)
Ridge Regression
Closed form: beta = (X'X + lambda*I)^(-1) X'y. Standardize all features and the outcome before fitting. For nested CV, the outer loop leaves one group out; the inner loop does the same within the training set.
PCA
Via power iteration on the covariance matrix with deflation. Standardize features first. Use PCA on the covariance matrix (not correlation) when the protocol specifies "registered covariance PCA."
K-Means
Deterministic farthest-first initialization: start at the first data point, then pick each subsequent centroid as the point farthest from all existing centroids. Run Lloyd's algorithm to convergence.
Bootstrap
Implement the specified PRNG exactly (PCG32 or XorShift32). For wild cluster bootstrap-t:
- Fit the restricted-null model (coefficient of interest set to 0).
- Generate cluster-level wild weights from the specified distribution (Webb 6-point, Rademacher, etc.).
- Multiply restricted residuals by weights to generate bootstrap y*.
- Refit the full model on each bootstrap sample.
- Compute the t-statistic (coefficient / CR1 clustered SE) for each replicate.
Adjusted Rand Index
For clustering stability: build contingency table, compute (sum_comb - expected) / (max - expected).
Output Formatting
- Round all non-integer statistics to the declared decimal places.
- Use JSON
null only when a statistic is mathematically unavailable.
- Never output
NaN or Infinity.
- Preserve every declared array order — do not re-sort independently.
- Use uppercase two-letter state codes.
- Use portal division/region names exactly as they appear.
- Boolean fields must be JSON booleans, not strings.
Common Pitfalls
- Counting wrong observations: When a protocol specifies
AGE_ADJUSTED_AND_DIRECT_SURVEY_AND_FINAL, count only those rows — not CRUDE or COUNTY_ROLLUP rows.
- Release resolution order: Always revision DESC, then released_at DESC. Reversing this changes which value is selected.
- Suppressed ≠ missing: A suppressed value (suppression_flag=1) is intentionally unavailable. Do not use it.
- Cohort definitions: The balanced panel requires completeness in ALL years, not just the reference year.
- Within-transformation vs LSDV: Dummy-variable FE can produce numerical instability. Use within-transformation for cleaner results.
- Standardization scope: For ridge and PCA, standardize using training-set statistics only, then apply to test data.
Module Patterns
The five tasks share recurring analytical modules. Here is how to recognize and implement each:
Clustered Fixed-Effects + Jackknife
- Keywords:
delete_cluster, jackknife, TWO_WAY_FIXED_EFFECTS
- Fit the FE model on the full cohort, then delete one cluster at a time and refit.
- Report the full coefficient, all delete-one coefficients, jackknife SE (= sqrt((n-1)/n * sum of squared deviations)), bias-corrected coefficient (= 2*full - mean_delete), and min/max influence clusters.
Nested Cross-Validated Ridge / Elastic Net
- Keywords:
nested, leave_one_out, ridge, elastic_net
- Outer loop: leave one group (division, state) out.
- Inner loop: within training, leave one group out to select lambda/alpha/l1_ratio.
- Report outer fold sizes, selected hyperparameters per fold, inner grid RMSEs, outer RMSEs, and pooled metrics (RMSE, MAE, Q² or R²).
Wild Cluster Bootstrap
- Keywords:
wild, bootstrap, PCG32, XORSHIFT32, WEBB
- Implement the PRNG from its definition. PCI32 is a truncated 64-bit LCG; XorShift32 is a shift-register generator.
- For Webb 6-point: weights are ±√1.5 (prob 1/6 each), ±1 (prob 1/6 each), ±√0.5 (prob 1/6 each).
- Null restriction: set the target coefficient to zero, work with restricted residuals.
- Report observed statistic, quantiles, exceedance count, p-value (= (exceedance+1)/(replicates+1)), and batch exceedance counts.
Split / Grouped Conformal Prediction
- Keywords:
conformal, calibration, alpha, nominal_coverage
- Split data into proper training, calibration, and test sets.
- Fit on proper training, compute absolute residuals on calibration set.
- Threshold = ⌈(1-α)(n_cal+1)⌉-th smallest absolute calibration residual.
- Prediction interval = ŷ ± threshold. Coverage = fraction of test points within interval.
- Report per-fold and aggregate coverage and mean width.
Trajectory PCA + Clustering
- Keywords:
trajectory, covariance_pca, kmeans, leave_year_out
- Reshape panel data into wide format: one row per geography, columns = variables × years.
- Standardize, compute covariance matrix, extract top k eigenvectors via power iteration.
- Cluster on PC scores using farthest-first K-means.
- Leave-year-out stability: repeat PCA + clustering omitting each year, compute ARI against full clustering.
Source / Year Perturbation
- Keywords:
source_year, perturbation, exhaustive, SHAPLEY
- Fit baseline model, then iterate over subsets of years (or source variants).
- For each subset, refit and record coefficient, p-value, and percent shift vs baseline.
- Report same-sign fraction, median/max absolute percent shift, and worst-case subset.
Sensitivity Surface
- Keywords:
partial_r2, sensitivity, confounding
- Given baseline path coefficients and standard errors, compute how the indirect effect changes under hypothetical unobserved confounding.
- Grid over R² values for mediator-confounder and outcome-confounder relationships.
- Report baseline quantities, tipping point R² (equal-strength confounding that nullifies the effect), and full surface.
Execution Workflow
- Read the three inputs:
prompt.txt (task description), analysis_request.json (detailed spec), answer_template.json (output contract).
- Download all data from the portal using CSV exports — parse with a robust CSV reader.
- Resolve releases using the declared release method (almost always FINAL with max revision).
- Build cohorts in dependency order: basic-complete → primary → balanced → broad → strict.
- Implement modules in the declared order. Each module's
required_evidence field tells you exactly what to report.
- Compute decisions: Apply each gate formula exactly as written. Report PASS/FAIL, passed count, and the controlled classification.
- Format output: Match every required key, array length, cardinality rule, and precision specification from the answer template.
Self-Check Before Submission
Data-Only Modules (Highest Leverage)
Some answer fields depend only on correct data extraction and counting — no statistical computation needed. These are the highest-value targets for correctness:
- Publication/cohort audit sections: counts of resolved observations, cohort sizes, excluded geographies, year-by-year completeness counts. Get these right by carefully applying the declared filters (value_type, source_type, release_status) and quality exclusions.
- Reconciliation sections (country tasks): label-to-ISO3 resolution and alias counting. Build lookup tables from the geography reference, matching on canonical name, portal label, and alternate labels (semicolon-delimited).
- Revision audit sections: applied vs non-applied revision event IDs. Filter the revisions table by domain and status.
These sections are deterministic given correct data parsing and often account for a substantial fraction of the scored fields.
1---2name: reflect-3-attempt-01-633description: Public Health Observatory Audit Skill4---5# Public Health Observatory Audit Skill67## Overview89Solve algorithmic audit tasks against the Public Health Observatory data portal. Each task asks you to complete a registered multi-module evidence audit using only the read-only portal. You must return one JSON object conforming exactly to the supplied answer template.1011## Portal Access1213The portal is a read-only Web application. All evidence comes from browse pages or CSV exports. Never modify data — every filter, release-resolution step, and quality exclusion must be reproducible from the portal alone.1415### Data Endpoints1617| Endpoint | Returns |18|---|---|19| `GET /geographies/states` | State reference: FIPS, abbreviation, name, region, census division |20| `GET /geographies/counties` | County reference: FIPS, state, name, region, RUCC, metro class |21| `GET /geographies/countries` | Country reference: ISO3, name, region |22| `GET /data/state-health` | State health observations: measure, value type, source type, value, SE, sample size, quality flags |23| `GET /data/state-socioeconomic` | State socioeconomic: poverty, income, education, unemployment, uninsured, etc. |24| `GET /data/county-health` | County health observations: same schema as state health |25| `GET /data/county-socioeconomic` | County socioeconomic: same fields as state |26| `GET /data/country-indicators` | Country indicators: indicator id, value, quality flag |27| `GET /data/revisions` | Revision notices: domain, entity, field, old/new value, status |28| `GET /download?dataset=X&format=csv` | Full CSV export of any dataset |2930## Data Pipeline3132### Step 1 — Release Resolution3334For every analysis, you must resolve which release to use. The standard method is **Registered Final Release Resolution**:35361. Restrict to rows where `release_status == "FINAL"`.372. Group by the natural entity key — for state health this is `(state_abbr, year, measure_id, value_type, source_type)`; for socioeconomic it is `(state_abbr, year)`; for counties add `county_fips`.383. Within each group, pick the row with the **highest revision number**.394. Break ties by picking the **latest `released_at`** timestamp.4041Never average across releases or value-types. Always pick exactly one row per group.4243### Step 2 — Quality Exclusion4445After resolution, exclude any row that meets **any** of these conditions:4647- `quality_flag` is `INVALID_SCALE`, `INVALID`, or `WITHDRAWN`48- `suppression_flag` is `"1"` (suppressed)49- The `value` field is empty, whitespace-only, or the literal string `null`5051Suppressed, invalid, and blank values are **unavailable** — never zero-fill, never impute unless the module explicitly requires imputation.5253### Step 3 — Revision Application5455The revisions table records post-publication corrections:5657- `APPLIED` revisions are already reflected in higher revision numbers of the same observation and do **not** require separate application after Step 1.58- `PENDING` and `WITHDRAWN` revisions must **not** alter resolved values.59- For the country domain, revision events may document scale corrections (e.g., factor-of-10 errors). Use the `status` field to decide whether an event affects the usable value.6061### Step 4 — Filter by Value Type and Source Type6263Most protocols specify which combination to use. Common filters:6465- `AGE_ADJUSTED_AND_DIRECT_SURVEY_AND_FINAL` — use only `value_type=AGE_ADJUSTED, source_type=DIRECT_SURVEY`66- `CRUDE_AND_DIRECT_SURVEY_AND_FINAL` — use only `value_type=CRUDE, source_type=DIRECT_SURVEY`67- `FINAL` alone (for socioeconomic) — use only `release_status=FINAL`6869Apply the filter **after** release resolution. Each measure in the analysis should use exactly one resolved value per geography-year.7071## Cohort Construction7273Every module declares a cohort. Build them in order:74751. **Basic-complete** — The core variables are all non-null, non-suppressed, and valid for a given geography-year.762. **Primary cohort** — Basic-complete in the reference year (e.g., 2023).773. **Balanced panel cohort** — Basic-complete in **every** requested year.784. **Machine-learning / broad cohort** — Primary-cohort members also complete for an extended set of features.795. **Strict dual-source cohort** — Complete for outcome, both exposure variants, and adjustments in every year.8081Preserve the **exact order** of state codes, county FIPS codes, or ISO3 codes as they appear in the geography reference. Sorted ascending is the default unless the answer template specifies a different order.8283## Statistical Computation (Pure Python / JS)8485When numpy/scipy are unavailable, implement the following from scratch:8687### Fixed Effects (Within-Transformation)8889For two-way (state + year) FE:901. Compute state means, year means, and grand means for both outcome and each predictor.912. Transform: `y_tilde = y - y_bar_state - y_bar_year + y_bar_grand`923. Run OLS on transformed data **without intercept**.934. Effective df = `n_obs - n_predictors - (n_states - 1) - (n_years - 1)`9495### Ridge Regression9697Closed form: `beta = (X'X + lambda*I)^(-1) X'y`. Standardize all features and the outcome before fitting. For nested CV, the outer loop leaves one group out; the inner loop does the same within the training set.9899### PCA100101Via power iteration on the covariance matrix with deflation. Standardize features first. Use PCA on the covariance matrix (not correlation) when the protocol specifies "registered covariance PCA."102103### K-Means104105Deterministic farthest-first initialization: start at the first data point, then pick each subsequent centroid as the point farthest from all existing centroids. Run Lloyd's algorithm to convergence.106107### Bootstrap108109Implement the specified PRNG exactly (PCG32 or XorShift32). For wild cluster bootstrap-t:1101. Fit the restricted-null model (coefficient of interest set to 0).1112. Generate cluster-level wild weights from the specified distribution (Webb 6-point, Rademacher, etc.).1123. Multiply restricted residuals by weights to generate bootstrap y*.1134. Refit the full model on each bootstrap sample.1145. Compute the t-statistic (coefficient / CR1 clustered SE) for each replicate.115116### Adjusted Rand Index117118For clustering stability: build contingency table, compute `(sum_comb - expected) / (max - expected)`.119120## Output Formatting121122- Round all non-integer statistics to the declared decimal places.123- Use JSON `null` only when a statistic is mathematically unavailable.124- Never output `NaN` or `Infinity`.125- Preserve every declared array order — do not re-sort independently.126- Use uppercase two-letter state codes.127- Use portal division/region names exactly as they appear.128- Boolean fields must be JSON booleans, not strings.129130## Common Pitfalls1311321. **Counting wrong observations**: When a protocol specifies `AGE_ADJUSTED_AND_DIRECT_SURVEY_AND_FINAL`, count only those rows — not CRUDE or COUNTY_ROLLUP rows.1332. **Release resolution order**: Always revision DESC, then released_at DESC. Reversing this changes which value is selected.1343. **Suppressed ≠ missing**: A suppressed value (suppression_flag=1) is intentionally unavailable. Do not use it.1354. **Cohort definitions**: The balanced panel requires completeness in ALL years, not just the reference year.1365. **Within-transformation vs LSDV**: Dummy-variable FE can produce numerical instability. Use within-transformation for cleaner results.1376. **Standardization scope**: For ridge and PCA, standardize using training-set statistics only, then apply to test data.138139## Module Patterns140141The five tasks share recurring analytical modules. Here is how to recognize and implement each:142143### Clustered Fixed-Effects + Jackknife144- **Keywords**: `delete_cluster`, `jackknife`, `TWO_WAY_FIXED_EFFECTS`145- Fit the FE model on the full cohort, then delete one cluster at a time and refit.146- Report the full coefficient, all delete-one coefficients, jackknife SE (= sqrt((n-1)/n * sum of squared deviations)), bias-corrected coefficient (= 2*full - mean_delete), and min/max influence clusters.147148### Nested Cross-Validated Ridge / Elastic Net149- **Keywords**: `nested`, `leave_one_out`, `ridge`, `elastic_net`150- Outer loop: leave one group (division, state) out.151- Inner loop: within training, leave one group out to select lambda/alpha/l1_ratio.152- Report outer fold sizes, selected hyperparameters per fold, inner grid RMSEs, outer RMSEs, and pooled metrics (RMSE, MAE, Q² or R²).153154### Wild Cluster Bootstrap155- **Keywords**: `wild`, `bootstrap`, `PCG32`, `XORSHIFT32`, `WEBB`156- Implement the PRNG from its definition. PCI32 is a truncated 64-bit LCG; XorShift32 is a shift-register generator.157- For Webb 6-point: weights are ±√1.5 (prob 1/6 each), ±1 (prob 1/6 each), ±√0.5 (prob 1/6 each).158- Null restriction: set the target coefficient to zero, work with restricted residuals.159- Report observed statistic, quantiles, exceedance count, p-value (= (exceedance+1)/(replicates+1)), and batch exceedance counts.160161### Split / Grouped Conformal Prediction162- **Keywords**: `conformal`, `calibration`, `alpha`, `nominal_coverage`163- Split data into proper training, calibration, and test sets.164- Fit on proper training, compute absolute residuals on calibration set.165- Threshold = ⌈(1-α)(n_cal+1)⌉-th smallest absolute calibration residual.166- Prediction interval = ŷ ± threshold. Coverage = fraction of test points within interval.167- Report per-fold and aggregate coverage and mean width.168169### Trajectory PCA + Clustering170- **Keywords**: `trajectory`, `covariance_pca`, `kmeans`, `leave_year_out`171- Reshape panel data into wide format: one row per geography, columns = variables × years.172- Standardize, compute covariance matrix, extract top k eigenvectors via power iteration.173- Cluster on PC scores using farthest-first K-means.174- Leave-year-out stability: repeat PCA + clustering omitting each year, compute ARI against full clustering.175176### Source / Year Perturbation177- **Keywords**: `source_year`, `perturbation`, `exhaustive`, `SHAPLEY`178- Fit baseline model, then iterate over subsets of years (or source variants).179- For each subset, refit and record coefficient, p-value, and percent shift vs baseline.180- Report same-sign fraction, median/max absolute percent shift, and worst-case subset.181182### Sensitivity Surface183- **Keywords**: `partial_r2`, `sensitivity`, `confounding`184- Given baseline path coefficients and standard errors, compute how the indirect effect changes under hypothetical unobserved confounding.185- Grid over R² values for mediator-confounder and outcome-confounder relationships.186- Report baseline quantities, tipping point R² (equal-strength confounding that nullifies the effect), and full surface.187188## Execution Workflow1891901. **Read the three inputs**: `prompt.txt` (task description), `analysis_request.json` (detailed spec), `answer_template.json` (output contract).1912. **Download all data** from the portal using CSV exports — parse with a robust CSV reader.1923. **Resolve releases** using the declared release method (almost always FINAL with max revision).1934. **Build cohorts** in dependency order: basic-complete → primary → balanced → broad → strict.1945. **Implement modules** in the declared order. Each module's `required_evidence` field tells you exactly what to report.1956. **Compute decisions**: Apply each gate formula exactly as written. Report PASS/FAIL, passed count, and the controlled classification.1967. **Format output**: Match every required key, array length, cardinality rule, and precision specification from the answer template.197198## Self-Check Before Submission199200- [ ] Every array length matches the template's `array_lengths` specification201- [ ] State/county/country codes use the exact portal spelling and case202- [ ] Division and region names match the portal exactly203- [ ] All non-integer values are rounded to the declared decimal places204- [ ] No `NaN`, `Infinity`, or string-encoded numbers205- [ ] `null` only for mathematically unavailable statistics206- [ ] Decision enums use exactly the values listed in the template207- [ ] Array orderings match the declared order (feature order, state order, division order, year order)208- [ ] No fields from the template's `required_keys` are missing209210## Data-Only Modules (Highest Leverage)211212Some answer fields depend only on correct data extraction and counting — no statistical computation needed. These are the highest-value targets for correctness:213214- **Publication/cohort audit sections**: counts of resolved observations, cohort sizes, excluded geographies, year-by-year completeness counts. Get these right by carefully applying the declared filters (value_type, source_type, release_status) and quality exclusions.215- **Reconciliation sections** (country tasks): label-to-ISO3 resolution and alias counting. Build lookup tables from the geography reference, matching on canonical name, portal label, and alternate labels (semicolon-delimited).216- **Revision audit sections**: applied vs non-applied revision event IDs. Filter the revisions table by domain and status.217218These sections are deterministic given correct data parsing and often account for a substantial fraction of the scored fields.