# Data audit (P1) File: `data/firms.csv` — SHA-256 `34aa682e59ef64cfc56931ea33bb809797cd53eca83edfe370c31aeaa8e8b7df` (matches bundle.json). 1200 rows (header excluded) × 4 columns. Types: firm_id int64; skill_index, training_hours, productivity_growth float64. No dates in file; timing per TASK.md: skill_index = year before programme (pre-treatment), training_hours = programme year, productivity_growth = year after. | column | mean | sd | min | max | missing | |---|---|---|---|---|---| | firm_id | 1600.5 | 346.6 | 1001 | 2200 | 0 (unique, 1001..2200) | | skill_index (std. index) | -0.001 | 0.995 | -3.828 | 2.962 | 0 | | training_hours (h/employee) | 19.946 | 8.244 | -7.585 | 51.770 | 0 | | productivity_growth (%) | 7.083 | 4.020 | -4.038 | 19.389 | 0 | Duplicates: 0 full-row duplicates, 0 duplicated firm_id. No zero hours; no heaping (max multiplicity of any value = 2). Anomalies: - **12 rows with negative training_hours** (min -7.585). Impossible values. All have low skill_index (-3.0 to -1.0), consistent with an unclipped generating process at the low end. Decision: exclude from main analysis (exclusion ledger step 3), report sensitivity with them included. - Confounding: corr(skill_index, training_hours)=0.69, corr(skill_index, growth)=-0.79, corr(hours, growth)=-0.28. High-skill firms train more and grow less, so the unadjusted slope is biased downward. - Overlap: within each skill quintile, training hours span a wide range (quintile means 12.9 → 28.0 with substantial within-quintile spread), so conditional comparisons are supported. Information-availability: only file allowed is used; skill_index is pre-programme, so conditioning on it is legitimate. No input violates the rules.