Skip to content

refactor(analysis): consolidate null summary + type asymmetry boundary#32

Merged
project-navi-bot merged 3 commits intomainfrom
refactor/null-summary-consolidation
Mar 29, 2026
Merged

refactor(analysis): consolidate null summary + type asymmetry boundary#32
project-navi-bot merged 3 commits intomainfrom
refactor/null-summary-consolidation

Conversation

@Fieldnote-Echo
Copy link
Copy Markdown
Member

Summary

PR 1A from the debt reduction plan. Eliminates duplicated null-summary logic and fixes an untyped boundary.

  • Shared _compute_distribution_stats() — single implementation replacing both compute_null_result() inline stats and the separate _null_summary() function. Population std (ddof=0), nearest-rank percentiles. Cannot silently diverge anymore.
  • NullDistributionSummary frozen dataclass — replaces the untyped dict[str, float] in AsymmetryNullResult.null_signed_excess_summary. Fixed schema with to_dict() serialization.
  • PermutationNullResult unchanged — flat public fields populated from shared computation internally. No report/serialization churn.
  • CANONICAL_LABELS unified — single definition in analysis/types.py, imported by recurrence.py and eligibility.py. Pilot schema's broader VALID_LABELS stays separate.

Verification

Golden values captured pre-refactor on main (8a24c77), asserted post-refactor:

  • compute_null_result() p-values, mean, std, min, max, percentiles — exact match across all three tail modes
  • run_asymmetry_null() p-values, signed excess, null summary — exact match on pinned seed/fixture

Test plan

  • 9 new tests (401 → 410), all passing
  • Golden-value regression tests prove numeric identity
  • Lint clean (ruff check + format)
  • Type-check clean (mypy)
  • Pre-commit hooks pass
  • CI passes

🤖 Generated with Claude Code

Extract _compute_distribution_stats() -> NullDistributionSummary as
single shared implementation for null distribution summaries. Replaces
both the inline stats in compute_null_result() and the separate
_null_summary() function, eliminating duplicated logic that could
silently diverge.

- Add NullDistributionSummary frozen dataclass (mean, std ddof=0,
  min_val, max_val, nearest-rank percentiles, n)
- AsymmetryNullResult.null_signed_excess_summary typed from
  dict[str, float] to NullDistributionSummary
- PermutationNullResult keeps flat public shape; populated from
  shared summary computation internally
- Unify CANONICAL_LABELS: single definition in analysis/types.py,
  imported by recurrence.py and eligibility.py
- Golden-value regression tests prove exact numeric identity on
  pinned seed (captured pre-refactor on main at 8a24c77)

Tests: 401 -> 410 (+9). Lint, format, mypy clean.
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

The std computation produces platform-dependent last-digit rounding
(0.9707728879609279 local vs 0.9707728879609274 CI). Use
pytest.approx with rel=1e-12 tolerance — tight enough to catch
real divergence, loose enough for IEEE 754 platform variance.
F-01: AsymmetryNullResult.to_dict() now flattens
NullDistributionSummary back to the legacy {mean, std, min, max,
p5, p25, ...} shape for JSON artifact compatibility. Internal type
is NullDistributionSummary; serialized shape is unchanged.

F-02: Golden regression test now asserts full summary contract
(percentiles + n), plus a to_dict() test proving the legacy flat
shape is preserved (no nested "percentiles" key, no "min_val").
@project-navi-bot project-navi-bot merged commit 58e0217 into main Mar 29, 2026
5 checks passed
@project-navi-bot project-navi-bot deleted the refactor/null-summary-consolidation branch March 29, 2026 03:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants