feat: results.aggregate('total') - estimator-owned totals for CS/EDiD/Imputation/TwoStage + MMM no-scale admission - #770
Conversation
…outcome (CS/EDiD/Imputation/TwoStage) + MMM no-scale admission
Promote "total" into AGGREGATION_VOCABULARY: a single target="total" row,
the exact relay C x overall CONDITIONAL on the realized aggregation mass
(att/se/CI scaled by C; t/p/df inherited; bootstrap-safe RELAY with NaN df),
where C is each estimator's finite-masked complete-case aggregation support:
- CallawaySantAnna: replay of _aggregate_simple's cell selection over a new
immutable fit-time kit snapshot (agg_gt_cells + is_survey_fit, direct
bookkeeping assigns in _build_aggregation_kit); the cohort-mass branch
(bare cluster=) is admitted only when it coincides with the complete-case
count (divergent incomplete-cell fits fail closed).
- ImputationDiD: finite-tau support (total_support, snapshot at kit build -
the kit frame is a live _fit_data reference), so C x overall = sum(tau)
exactly, fixing the documented raw-support overcount of scale="auto" for
total exports.
- TwoStageDiD: post-filter treatment-indicator support from the kit's
private frame copy.
- EfficientDiD: integer sum of kept cells' n_treated from the kit's
deep-copied snapshot (never the non-integral n_units x fractions product).
Scope is PANEL NON-SURVEY fits, fail-closed with the reason elsewhere:
repeated-cross-section routings (RC-first gate order; a balanced panel with
allow_unbalanced_panel=True stays admitted), fits declaring a survey_design=
(any weight type; gates read immutable kit provenance, so post-fit mutation
of survey_metadata cannot bypass them; explicit unweighted SurveyDesign(psu=)
fits fail closed BY DECLARATION), the CS divergent bare-cluster corner, and
pre-upgrade pickled kits (refit message; no fallback replay). NaN rules:
C=NaN or true overflow blanks the whole row; otherwise the relay is verbatim
and inherited NaNs pass through (att/n never blanked - the repo's
non-estimable-row convention).
MMM: both exporters admit a total container ALONE (any scale rejected as
double-counting); level gate, hints, docstrings, and errors swept; for
overall-total exports aggregate('total') supersedes scale="auto" (which
remains the group-container route).
Docs: v4-design section 6 amendment + v4-deprecations M-020..M-027 and
M-117..M-120 note updates; REGISTRY CS total Note (a)-(g) + EDiD/Imputation/
TwoStage (f) subclauses + MMM scale-contract/auto-allowlist/total-admission
Notes; DEFERRED row split into the StackedDiD remainder (Parked) and the
survey/RC remainder incl. the att*dC variance term (moved to Paper-gated);
survey-roadmap Current Limitations entry; migration-4.0/r_comparison/
troubleshooting/CONTRIBUTING sweeps; api rst pages (mmm.rst executed blocks
teach the total route first); guides (llms/llms-full/llms-practitioner) +
practitioner.py runtime strings; CHANGELOG entry + three falsified Unreleased
sentences fixed; tutorial 02/15 markdown cells.
Tests: TestTotal* batteries (identity + independent frame-derived mass
oracles per estimator; fail-closed routing arms incl. analytic/replicate/
unweighted-psu/fweight designs, combined survey+RC order pin, balanced-flag
admission; gate-immutability mutation arms on all four; CS/EDiD/Imputation
snapshot-isolation arms; zero-support and degenerate-inference pass-through
arms; per-field overflow blanking; legacy-kit refit arms; bootstrap relay;
pickle; constant-tau estimand check), design-sweep "total" arms +
_assert_level_matches branch, vocabulary/n_kind/balance_e enrollment,
Wooldridge custom-aggregate arm, MMM TestTotalContainerAdmission + hint pins.
Deliberate no-ops (verified): README.md:94 (heterogeneity-level bullet;
'total' is not a heterogeneity level), docs/references.rst (blanket doc-deps
entry; no new citation), docs/tutorials/16_survey_did.ipynb (no level
enumeration prose), tutorials 02 (:1154) and 09 code-cell comments +
frozen FutureWarning output cells (still-true text; editing executed cells
would force re-execution), tests/test_aggregate_contract.py:260 (simple-relay
docstring, still true), llms-autonomous.txt (zero aggregate() occurrences).
MC coverage for the total CI is deliberately omitted: C.lo <= tau*C <= C.hi
iff lo <= tau <= hi, so coverage is mathematically identical to the overall
CI's, which is the estimator's already-validated surface.
Overall assessmentExecutive summary
Methodology
Code Quality
PerformanceNo findings. MaintainabilityNo additional findings. Tech Debt
SecurityNo findings or apparent secrets. Documentation/Tests
Path to Approval
|
- MMM total admission is now provenance-gated like scale="auto": a
level='total' container is accepted only from the four audited adopters
(_TOTAL_ESTIMATORS = CS/EfficientDiD/ImputationDiD/TwoStageDiD), and the
full producer contract is validated (label='total', n_kind='obs',
weight=[1.0]) - a hand-built or altered container with StackedDiD/unknown/
missing provenance or drifted schema fails closed instead of being
silently exported as already-scaled. Rejection + all-four-admitted +
drifted-contract tests added; _make_agg gains weight support; REGISTRY
total-admission Note and CHANGELOG updated.
- tests: anticipation=1 mass pins for ImputationDiD and TwoStageDiD
(total.n grows by exactly the frame-derived anticipation-window
observations - their masses come from anticipation-adjusted masks).
- tutorial 02 cell 20: the code comment and the STORED FutureWarning output
now match the new runtime catalog text (".aggregate('simple') /
.aggregate('total')"), verified byte-identical against the emitted string;
comment-only source change, no executable statements touched.
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall assessment✅ Looks good — no unmitigated P0/P1 findings. Executive summary
Methodology
Code Quality
PerformanceNo findings. MaintainabilityNo findings. The shared relay builder avoids four separate inference implementations. Tech Debt
SecurityNo findings or apparent secrets. Documentation/TestsNo unmitigated findings. The prior stale tutorial text is updated, and anticipation tests now cover all four adopters ( |
Summary
"total"intoAGGREGATION_VOCABULARY:results.aggregate('total')is the estimator-owned total incremental outcome on CallawaySantAnna, EfficientDiD, ImputationDiD, and TwoStageDiD - a singletarget="total"row, the exact relayC x overallCONDITIONAL on the realized aggregation mass (att/se/CI scaled byC;t/p/dfinherited; bootstrap-safe RELAY with a NaN df column per the M-027 per-level policy).C(finite-masked complete-case support): CS replays_aggregate_simple's cell selection over a new immutable fit-time kit snapshot (agg_gt_cells+is_survey_fit); ImputationDiD uses the finite-tau support (total_support, snapshot at kit build), soC x overall = sum(tau)exactly - fixing the documented raw-support overcount of the MMMscale="auto"route for total exports; TwoStageDiD uses the post-filter treatment-indicator support from its private kit frame copy; EfficientDiD uses the integer sum of kept cells'n_treatedfrom its deep-copied kit snapshot.survey_design=(any weight type; gates read immutable kit provenance, so post-fit mutation ofsurvey_metadatacannot bypass them; explicit unweightedSurveyDesign(psu=)fits fail closed by declaration), the CS bare-cluster=divergent corner (cohort-mass weighting vs complete-case count), and - on CS/ImputationDiD, whose masses need the new fit-time snapshots - pre-upgrade pickled kits.totalcontainer ALONE (anyscalerejected as double-counting); level gate/hints/docstrings/errors swept; for overall-total exportsaggregate('total')supersedesscale="auto", which remains thegroup-container route.Methodology references (required if estimator / math changes)
C x overallconditional on the realized aggregation mass. See the REGISTRY post-fitaggregate('total')Notes for each estimator.att*dCvariance term is deliberately out of scope - tracked in DEFERRED.md with the survey/RC remainder); documented with reviewer-recognized- **Note (...)**labels in REGISTRY.md for all four estimators and the MMM section.Validation
tests/test_aggregate_contract.py(newTestTotal*batteries: relay identity with independent frame-derived mass oracles per estimator; fail-closed routing arms incl. analytic/replicate/unweighted-psu/fweight survey designs, combined survey+RC gate-order pin, balanced-panel-flag admission; gate-immutability mutation arms on all four; snapshot-isolation arms; zero-support and degenerate-inference pass-through arms; per-field overflow blanking; legacy-kit refit arms; bootstrap relays on all four; anticipation-mass pins for CS and EDiD; TwoStage post-filter divergence; pickle; constant-tau estimand check; design-sweeptotalarms +_assert_level_matchesbranch; vocabulary/n_kind/balance_e enrollment; Wooldridge custom-aggregate arm),tests/test_mmm.py(TestTotalContainerAdmission+ hint pins + end-to-end fit->aggregate('total')->export).C*lo <= tau*C <= C*hiifflo <= tau <= hi, so coverage is mathematically identical to the overall CI's, the estimator's already-validated surface. Tutorials 02/15 markdown enumerations updated (no executed cells touched).Security / privacy