You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Findings from a three-agent deep audit (public API, internal code health, release readiness). These move the library from "ships" to "polished" — about a week of work distributed across post-release follow-ups before 0.2.0.
These are not blockers for 0.1.0. File Tier 1 (#80) first.
API contract hardening
Highest-ROI bucket: every item below caught the maintainer or audit by surprise at least once.
`get_statistics` shape inconsistency. `Histogram` returns `{mean, std, n}`; `X/mR/Xbar/S` return `{N, center, lpl, upl}`. `init.py`'s Quick Start says `stats['center']`. A user copy-pasting against a histogram gets `KeyError`. Fix: align Histogram to `{N, center, ...}` (center=mean, limits=None) OR document the shape difference and add a contract test enumerating shape per chart type.
`'N'`/`'lpl'`/`'upl'` become the string `'Varies'` when subgroup sizes differ. Type pollution: dict claims numeric shape but returns `Union[int|float, str]`. Any `stats['upl'] > x` crashes with `TypeError`.
Fix: keep numeric fields as `None` (or `float('nan')`) when variable; add a separate `'limits_vary': True` flag.
Stringly-typed enum parameters. `n_mode: str = 'actual'` accepts only `'actual'` or `'average'`, validated at runtime. Same pattern for `value` (response/R1-R6), `chart` (Xbar/S/X/mR/Histogram), `theme`, `plot(view=...)`. No IDE autocomplete.
Fix: `Literal["actual", "average"]` for `n_mode`; same treatment for `value`, `chart`, `view`. Pit of success.
`observed_design_state` typed as `SDSResult` but field is `SDSResult | None`. Type lies about the optional.
Where: `processbehavior/study.py:928, 1032-1043`.
Fix: narrow the field type (drop `None`), assert non-None in the property, or admit `Optional` in the signature.
`SDSResult` is a public return type but not in `all`. Users wanting `from processbehavior import SDSResult` for type hints must reach into `processbehavior.sds_detector` (also not declared public).
Where: `processbehavior/init.py:62-89` vs `study.py:1018, 1032, 1046`.
Fix: add `SDSResult` to top-level `all`; add `all` to `exceptions.py` and `sds_detector.py` to lock the public stability promise.
`name collision`: `study.factors` is `list[str] | None` while `DesignReport.factors` is `pd.DataFrame`. Same attribute name, different types depending on the object.
Where: `processbehavior/study.py:945-955` vs `study.py:151-183`.
Fix: rename `DesignReport.factors` to `factors_table` (or method `to_dataframe()`).
chart_info TypedDict-ification
The `chart_info` dict (`{data, statistics, metadata, strata}`) is the single biggest source of class-of-bug: the strata fix (f938fdf) and the Xbar-center dead branch (1444b63) were both producer/consumer disagreements about this contract.
Introduce `ChartPayload(TypedDict)` + `ChartMetadata(TypedDict, total=False)` in a shared `analysis_types.py` (or extend `processbehavior/plotting/contracts.py`).
Build payloads via the typed dict literal at every `return` site in `processbehavior/analysis.py` (~4 sites: `_calculate_mr_chart_from_precomputed`, `_calculate_mr_chart_stratified`, `_calculate_xbar`, etc.).
mypy then catches missing keys before runtime.
Pattern to copy: `plotting/contracts.py:ChartRenderSpec` is already done right (frozen dataclass with `post_init` validation).
GitHub front-door fix
The methodology validation is the marketing centerpiece and currently invisible.
Add a Validation section to `README.md` pointing at `validation/e2e_bishop_report.html` and the 280 numerical assertions passing for SDS 1-3. Show the SDS-1 capability table.
README quickstart should showcase the differentiator — SDS detection + a residual call (`study.execute(chart='Xbar', value='R5')`) — currently it reads like every other SPC wrapper.
Where: `processbehavior/init.py:11-26` (also rendered as PyPI landing).
Add Bishop-related keywords to pyproject: `"variance-analysis"`, `"bishop-vas"`, `"wheeler"`, `"design-of-experiments"`.
Where: `pyproject.toml:14`.
Documentation pruning
Remove or move six stale planning docs at `docs/release_gate_0_1_0.md`, `docs/pre_release_audit.md`, `docs/api_ux_review.md`, `docs/chart_statistics.md`, `docs/sampling_plan_design.md`, `docs/sds-detection.md`. They're not in `myst.yml` but MyST may publish them as orphan pages. Per CLAUDE.md anti-patterns: "Don't track planning docs at repo root."
Add missing tutorial notebooks to `docs/myst.yml:27-41`: `docs/tutorials/process-capability.ipynb` and `docs/tutorials/loss-function.ipynb` exist on disk but aren't in the TOC — they won't appear on the deployed site.
`docs/myst.yml:18` copyright = "2025" while date metadata is 2026 — cosmetic but visible on every doc page footer. Bump to `"2025-2026"`.
CI hardening
Notebook execution in CI — `pytest --nbmake docs/tutorials docs/getting-started` would have caught the `chart='Imr'` typo (Tier 1 item) months ago. Add the `nbmake` plugin to `[test]` extra and run notebooks in the test job.
publish.yml has no test gate — a tag triggers `build → twine check → publish` with no test step. A regression on `main` that `ci.yml` didn't catch publishes a broken wheel.
Where: `.github/workflows/publish.yml`.
Fix: `needs: [test, smoke-test]` from a triggered CI run, OR duplicate the smoke-test job into `publish.yml` before the upload step.
`pip-audit --skip-editable` silently tolerates CVEs attributed to the editable install path. After publishing 0.1.0, switch to installing the published wheel into a fresh venv and run `pip-audit --strict` against it. (CLAUDE.md anti-pattern flags this for revisit post-publish.)
Pre-commit pinned to ruff 0.6.4 while local is 0.14.9. New contributors get drift from their editors.
Where: `.pre-commit-config.yaml:3`.
Fix: bump rev; add `pre-commit` ecosystem entry to `dependabot.yml`.
Findings from a three-agent deep audit (public API, internal code health, release readiness). These move the library from "ships" to "polished" — about a week of work distributed across post-release follow-ups before 0.2.0.
These are not blockers for 0.1.0. File Tier 1 (#80) first.
API contract hardening
Highest-ROI bucket: every item below caught the maintainer or audit by surprise at least once.
`get_statistics` shape inconsistency. `Histogram` returns `{mean, std, n}`; `X/mR/Xbar/S` return `{N, center, lpl, upl}`. `init.py`'s Quick Start says `stats['center']`. A user copy-pasting against a histogram gets `KeyError`. Fix: align Histogram to `{N, center, ...}` (center=mean, limits=None) OR document the shape difference and add a contract test enumerating shape per chart type.
`'N'`/`'lpl'`/`'upl'` become the string `'Varies'` when subgroup sizes differ. Type pollution: dict claims numeric shape but returns `Union[int|float, str]`. Any `stats['upl'] > x` crashes with `TypeError`.
Stringly-typed enum parameters. `n_mode: str = 'actual'` accepts only `'actual'` or `'average'`, validated at runtime. Same pattern for `value` (response/R1-R6), `chart` (Xbar/S/X/mR/Histogram), `theme`, `plot(view=...)`. No IDE autocomplete.
`observed_design_state` typed as `SDSResult` but field is `SDSResult | None`. Type lies about the optional.
`SDSResult` is a public return type but not in `all`. Users wanting `from processbehavior import SDSResult` for type hints must reach into `processbehavior.sds_detector` (also not declared public).
`name collision`: `study.factors` is `list[str] | None` while `DesignReport.factors` is `pd.DataFrame`. Same attribute name, different types depending on the object.
chart_info TypedDict-ification
The `chart_info` dict (`{data, statistics, metadata, strata}`) is the single biggest source of class-of-bug: the strata fix (f938fdf) and the Xbar-center dead branch (1444b63) were both producer/consumer disagreements about this contract.
Pattern to copy: `plotting/contracts.py:ChartRenderSpec` is already done right (frozen dataclass with `post_init` validation).
GitHub front-door fix
The methodology validation is the marketing centerpiece and currently invisible.
```bash
gh repo edit cnicholas/processbehavior \
--description "Differentiated Python SPC implementing Bishop's Variance Analysis System (VAS)" \
--homepage "https://cnicholas.github.io/processbehavior/\" \
--add-topic spc --add-topic control-charts --add-topic statistics \
--add-topic bishop-vas --add-topic shewhart --add-topic process-behavior
```
Documentation pruning
CI hardening
Related
Filed from a multi-agent audit synthesizing public-API, code-health, and release-readiness findings against the current library state.