p21-triage
Triage layer for Pinnacle 21 Community validation reports.
You run P21. It hands you an Excel report with 2,000 findings. p21-triage reads that report and tells you, in plain English, what each finding means, which ones share a root cause, which ones threaten your submission, and what to do about each — then tracks your decisions run-over-run and writes your SDRG summary.
This is not a validator: it never runs checks and never reads study datasets. Its only input is the P21 Excel report.
Install
pip install cdisc-p21-triage
(Requires Python 3.9+. Only dependency: openpyxl.)
Quick start
# Explain and cluster a report's findings
p21-triage triage pinnacle21-report-2022-10-20T17-56-05-191.xlsx
# Record decisions (persisted in <report>.triage.json)
p21-triage disposition report.xlsx --key "SD1076|AE|AELAT" \
--status document --note "AELAT added for laterality; permissible per SDTMIG"
p21-triage disposition report.xlsx --list
# Compare two runs
p21-triage diff old-report.xlsx new-report.xlsx
# Annotated Excel + SDRG-ready Markdown
p21-triage export report.xlsx --xlsx annotated.xlsx --md sdrg-section5.md
# Explain one rule
p21-triage explain report.xlsx --rule CT2001
Disposition statuses: open (default), fix, document, waive.
Carry decisions into the next run with --disposition-file old-report.xlsx.triage.json.
Python API
from p21_triage import (
parse_report, cluster_findings, enrich_clusters,
diff_reports, export_excel, export_markdown,
save_disposition, apply_dispositions,
)
report = parse_report("pinnacle21-report-....xlsx")
clusters = enrich_clusters(cluster_findings(report), report.meta.engine)
for c in clusters:
print(c.rule_id, c.domain, c.risk_level, c.record_count)
print(" ", c.explanation)
# decisions persist in a JSON sidecar
save_disposition("report.xlsx", clusters[0].key, "waive", "sponsor decision")
# run-over-run
delta = diff_reports(parse_report("old.xlsx"), parse_report("new.xlsx"))
print(len(delta.added), "new clusters,", len(delta.resolved), "resolved")
export_excel(report, clusters, "annotated.xlsx", delta)
export_markdown(report, clusters, "sdrg.md", delta)
How it works
- Parse — tabs and columns are detected by name (alias lists cover version variants), never by position. Unknown format → clear error naming what's missing. See FORMAT.md.
- Explain — every finding gets a plain-English explanation: the report's own Rules tab first, then a built-in knowledge base of common rules (written in our own words from public rule docs), then an honest "not covered" fallback.
- Cluster — findings collapse by
RULE_ID|DOMAIN|VARIABLESinto root-cause clusters. One missing codelist → one cluster, not 500 rows. - Risk — severity mapped to submission risk (FDA and PMDA semantics).
- Decide —
fix/document/waiveper cluster, stored in a JSON sidecar; stable cluster keys carry decisions across runs. - Diff — run-over-run: new, resolved, and persistent clusters plus finding-level signature counts.
- Export — annotated Excel (findings + clusters + rules + optional delta sheets) and SDRG Section 5–ready Markdown.
Report format support
Built from public documentation of the P21 Community Excel report
(Datasets Summary / Issue Summary / Details / Rules tabs).
Version differences (renamed tabs/columns, missing Severity column in newer
versions) are handled by name-based detection — see FORMAT.md
for the spec and confidence levels.
Clean-room note
Built only from Pinnacle 21's public report format and published rule
documentation. No proprietary code or data was used; all test reports are
synthetically generated in tests/make_sample.py.
License
MIT — see LICENSE.
Metadata
Release files for cdisc-p21-triage 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cdisc_p21_triage-0.1.0.tar.gz | 21.7 kB | Without provenance | Details for cdisc_p21_triage-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cdisc_p21_triage-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for cdisc_p21_triage-0.1.0-py3-none-any.whl |
Total release size: 44.2 kB
Release files / cdisc_p21_triage-0.1.0.tar.gz
| Download URL | cdisc_p21_triage-0.1.0.tar.gz |
|---|---|
| Size | 21.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
de8a624781bf1bd902a02287479654bcd79a9de6fa8e2f213db2c5677d1985bd
|
|
BLAKE2b-256 checksum How to use checksums |
b16718cec23805cc50f39720c3d85cf130e2e79783f8a00ec049ff84211467b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / cdisc_p21_triage-0.1.0-py3-none-any.whl
| Download URL | cdisc_p21_triage-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e3775181c51345a54c35f809f7728171dded192233ca210cc8e0b3add8d0060b
|
|
BLAKE2b-256 checksum How to use checksums |
b2b13a576cc8d2da006bf3f6ce7cd23fdc81f7df6a7958a9e7e131dc102ad8ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for cdisc-p21-triage 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.