# F2-dev-01 — Two-way fixed-effects slope with firm-clustered uncertainty ## Question Estimate β in y_it = a_i + g_t + β x_it + u_it, the within-firm, within-year association of y with x. Firm effects a_i and year effects g_t are unrestricted. Inference allows arbitrary dependence of u_it within a firm over time and assumes independence across firms. The data are simulated. ## Data and exclusions `data/firm_panel.csv` (SHA-256 ae54378f…72e0) has 1200 rows (`n_input_rows`). It is a balanced panel: 100 firms (`n_firms`) × 12 years, 2008–2019 (`n_years`). There are no missing values, no duplicate rows and no duplicate firm–year keys, so `data_issues` is empty. The exclusion rules (missing values, exact duplicates, conflicting firm–year keys) removed 0 rows, so `n_analysed` = 1200 (see `out/exclusions.csv`). Full audit: `out/state/data_audit.md`. ## Method - Baseline: pooled OLS of y on x with an intercept and no fixed effects (`beta_pooled`). - Main estimate: two-way fixed effects estimated by least-squares dummy variables (LSDV), i.e. OLS of y on x plus firm and year dummies, 112 parameters in total (`n_params_lsdv`). As a cross-check, the slope from two-way within-demeaning (which is exact because the panel is balanced) matches to within 1e-8 (`beta_fe_within_check`). - `se_conventional`: the classical homoskedastic OLS standard error from the LSDV regression, with N − K = 1088 degrees of freedom. - `se_cluster`: a cluster-robust sandwich standard error clustered by `firm_id`, with the CR1 small-sample factor G/(G−1)·(N−1)/(N−K). Here K counts all 112 LSDV parameters (Stata `areg` convention), which is the more conservative choice. - 95% CI: `beta_fe` ± t(0.975, G−1 = 99) × `se_cluster`. The critical value is `ci_critical_value_t_Gminus1` = 1.984. - The method uses no randomness (`random_seed` = null). ## Results - Pooled OLS baseline: `beta_pooled` = 1.268 (conventional SE 0.028, `baseline_se_pooled_conventional`). - TWFE estimate: `beta_fe` = 0.6045. - The TWFE slope is about half the pooled slope. This pattern fits firm and/or year effects that are positively correlated with x and inflate the naïve estimate. The difference does not by itself identify which effects cause it. ## Uncertainty - `se_conventional` = 0.0326; `se_cluster` = 0.0471. The ratio is 1.44 (`se_ratio_cluster_to_conventional`), which fits positive within-firm dependence of the residuals and x over time. The conventional SE therefore understates uncertainty. - 95% firm-clustered CI: [`beta_ci_low`, `beta_ci_high`] = [0.511, 0.698]. It excludes 0 and also excludes the pooled estimate 1.268. - Sensitivity to the degrees-of-freedom convention: if the firm dummies are not counted in K, because they are nested within clusters (`xtreg, fe` convention), the clustered SE is 0.0451 (`se_cluster_sensitivity_firmFE_not_counted`). With no small-sample correction (CR0) it is 0.0446 (`se_cluster_CR0_no_correction`). The conclusions do not change. ## Limitations and open issues - β is a causal effect only under strict exogeneity of x given a_i and g_t; with simulated data, β is simply the parameter of the stated model. - Cluster-robust inference relies on asymptotics in the number of firms. G = 100 is a reasonable number of clusters, but the SE depends slightly on the small-sample convention (see Uncertainty). I report the conservative LSDV-K version as the primary result. - I found no data problems, and the task was completed in full (`feasibility` = "complete").