model-card
Generate the documentation an engineer-built medical-imaging model must carry — a Model Card (Mitchell et al. 2019), a Datasheet for its dataset (Gebru et al. 2021), and a METRIC-informed data-quality pass — filled from user-supplied facts, then verify every required section is p
Install
npx skills add https://github.com/Aperivue/medsci-skills/tree/main/skills/model-card
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install aperivue-medsci-skills@llmmart
git clone https://github.com/Aperivue/medsci-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole aperivue/medsci-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Model-Card Skill
Purpose
This skill produces the documentation an engineer-built medical-imaging model must carry: a
Model Card (intended use, out-of-scope use, training data, per-subgroup performance, caveats), a
Datasheet for its dataset (provenance, composition, collection, labelling, consent), and a
METRIC-informed data-quality pass. It fills the templates from facts the user supplies — it
never invents a number, a provenance detail, a consent status, or a licence — and ships a deterministic
gate that no required section is missing or left as an unfilled [NEEDS INPUT] placeholder.
It is the reporting seam of the model-engineering lane: after /model-validation audits the design
and /model-evaluation produces the numbers, this skill records them in a portable, auditable card that
/write-paper and /check-reporting consume. It mirrors /version-dataset structurally (generate +
deterministic verify).
When to use
- A trained model needs a Model Card / Datasheet for a repo, Hugging Face card, or manuscript supplement.
When NOT to use
- Auditing the validation design / metrics →
/model-validation,/model-evaluation. - Versioning the dataset bytes →
/version-dataset; tabular variable docs →/generate-codebook. - Item-by-item reporting-guideline compliance of the manuscript →
/check-reporting. - Building / training the model →
/model-scaffold.
Workflow
Phase 1 — Collect the facts
Gather, from the user / the model's developers: task + architecture + provenance + licence; intended use
and out-of-scope use; training and evaluation cohorts; the reference standard and inter-reader agreement;
overall and per-subgroup performance; data collection, consent, and de-identification. Anything not
supplied stays [NEEDS INPUT] — never guess.
Phase 2 — Fill the Model Card
Copy ${CLAUDE_SKILL_DIR}/references/model_card_template.md to MODEL_CARD.md and fill each section
from the facts. Keep the headings. Numbers come only from /model-evaluation / executed results.
Phase 3 — Fill the Datasheet
Copy ${CLAUDE_SKILL_DIR}/references/datasheet_template.md to DATASHEET.md and fill the seven
question groups (Motivation, Composition, Collection, Preprocessing/Labeling, Uses, Distribution,
Maintenance).
Phase 4 — METRIC data-quality pass
Walk ${CLAUDE_SKILL_DIR}/references/metric_dimensions.md (completeness, correctness, consistency,
representativeness, timeliness, provenance, label provenance, fairness/coverage, leakage safety) and
record each finding in the Datasheet. Anything that affects the headline metric's validity is also a
/model-validation finding — cross-check there.
Phase 5 — Verify completeness (deterministic gate)
python3 ${CLAUDE_SKILL_DIR}/scripts/check_model_card_complete.py \
--card MODEL_CARD.md --datasheet DATASHEET.md --strict
MISSING_SECTION / EMPTY_REQUIRED_SECTION must be zero before the card ships.
Phase 6 — Hand off
Carry the card into /write-paper (the Methods / supplement reference it), /check-reporting
(CLAIM 2024 / TRIPOD+AI item audit of the manuscript), and /self-review.
Anti-Hallucination
- Never invent evaluation numbers, subgroup results, or dataset provenance. Every figure comes from
/model-evaluationor the user's executed results; every provenance / consent / licence statement is user-confirmed. Unknown →[NEEDS INPUT], which the gate flags. - Never mark a section complete without user-supplied content, and never auto-fill a placeholder to pass the gate.
- Never assert a licence or consent status the user did not confirm.
- The gate checks presence, not truth — a complete card can still contain a wrong number; validity
is
/model-validationand the human's responsibility.
Deterministic gate
scripts/check_model_card_complete.py — verifies every required Model Card / Datasheet section is
present and non-empty (stdlib, network-free). Reproducible challenge:
bash ${CLAUDE_SKILL_DIR}/scripts/check_model_card_complete_challenge/verify.sh.
Note on classification
Model Cards (Mitchell et al. 2019) and Datasheets (Gebru et al. 2021) are documentation standards,
not clinical reporting guidelines, so they live here as references/ templates (uncounted), not in
/check-reporting's counted checklist set — the same way appraisal_tools/METRICS.md is kept separate.
/check-reporting still owns the manuscript-level CLAIM 2024 / TRIPOD+AI item audit.
Boundaries
model-validation (audit design) + model-evaluation (metrics)
└─ model-card (this skill: Model Card + Datasheet + METRIC pass, completeness-gated)
└─ write-paper + check-reporting (manuscript) ; version-dataset (dataset bytes)
Files (medsci-skills)
-
references
-
datasheet_template.md 2.2 KB
<!-- Datasheet template (model-card skill). Question groups follow Gebru et al., "Datasheets for Datasets," Communications of the ACM 2021 (arXiv:1803.09010), adapted for a clinical imaging dataset. Fill every [NEEDS INPUT] from user-supplied facts; never fabricate provenance, consent, or composition details. Keep the section headings (check_model_card_complete.py verifies they are present and non-empty). Put all answers inside the [NEEDS INPUT: ...] brackets so an unfilled field reads as unfilled. --> # Datasheet: [NEEDS INPUT: dataset name + version] ## Motivation - **Purpose and creators**: [NEEDS INPUT: why the dataset was created, for what task, by whom, funded by whom] ## Composition - **Instance**: [NEEDS INPUT: what one instance represents — a patient, a study, an image, a lesion] - **Size and split**: [NEEDS INPUT: number of instances and the patient-level train/validation/test split] - **Label / target**: [NEEDS INPUT: the label and how it was derived — the reference standard] - **Modalities / acquisition**: [NEEDS INPUT: scanners, vendors, protocols, sites] - **Known imbalance / missingness / errors**: [NEEDS INPUT] ## Collection Process - **Acquisition**: [NEEDS INPUT: consecutive, sampled, or selected on an optional modality — selection on availability is a spectrum bias to disclose] - **Time frame**: [NEEDS INPUT: collection dates] - **Consent / IRB / governance**: [NEEDS INPUT] ## Preprocessing / Cleaning / Labeling - **Preprocessing and order vs split**: [NEEDS INPUT: what preprocessing was applied, and whether normalisation / harmonisation was fit on the training fold only] - **Annotation protocol**: [NEEDS INPUT: annotators, qualifications, adjudication, blinding, inter-reader agreement] - **De-identification**: [NEEDS INPUT] ## Uses - **Appropriate and inappropriate uses**: [NEEDS INPUT: tasks the dataset is suitable for, and what it must NOT be used for] - **Risks**: [NEEDS INPUT: bias, re-identification] ## Distribution - **Availability and licence**: [NEEDS INPUT: restricted / on request / public, the confirmed licence, and access conditions] ## Maintenance - **Maintainer and versioning**: [NEEDS INPUT: who maintains it, contact, versioning, how updates / errata are communicated] -
metric_dimensions.md 3 KB
# Data-quality audit dimensions (model-card) A short, defensible data-quality checklist to run alongside the Model Card + Datasheet, informed by the **METRIC framework** for assessing data quality for trustworthy medical AI (Schwabe et al., *npj Digital Medicine* 2024) and **Datasheets for Datasets** (Gebru et al., *Commun. ACM* 2021). It is an **appraisal reference** (it is deliberately *not* a counted reporting guideline). For each dimension, record a finding in the Datasheet rather than a score; the goal is disclosure, not a number. > Verify the exact dimension list / wording against the METRIC paper before quoting it as a > formal instrument; the dimensions below are the well-established data-quality axes the > framework and Datasheets converge on, phrased for medical imaging. | Dimension | What to check | Where it surfaces | |---|---|---| | **Completeness** | Missing images / labels / fields; missingness pattern (MCAR/MAR/MNAR) and how handled. | Datasheet Composition / Preprocessing | | **Correctness / plausibility** | Implausible values, mislabeled cases, label noise; reference-standard quality and inter-reader agreement. | Datasheet Preprocessing/Labeling; Model Card Training Data | | **Consistency** | Same definition / units / protocol across sites and time; harmonisation applied **after** the split. | Datasheet Collection / Preprocessing | | **Representativeness / spectrum** | Does the cohort match the deployment population (age, sex, severity, scanner/vendor, site)? Selection on an optional modality is a spectrum bias. | Datasheet Collection; Model Card Factors | | **Timeliness / recency** | Acquisition time frame; drift vs. current practice/scanners; temporal split if a temporal claim is made. | Datasheet Collection; Model Card Evaluation Data | | **Provenance / traceability** | Where each instance came from; can the dataset version be reproduced (pair with `/version-dataset`)? | Datasheet Motivation / Maintenance | | **Label provenance** | Human vs. automated / model-derived ("silver") labels; circularity if model-derived labels evaluate the same model. | Datasheet Preprocessing/Labeling | | **Fairness / subgroup coverage** | Are protected / clinically-relevant subgroups represented enough to estimate per-subgroup performance? | Model Card Quantitative Analyses; defer depth to `/model-validation` + equity probe | | **Leakage safety** | Patient-level disjoint split; preprocessing fit on the training fold only; no site/scanner shortcut. | Model Card Evaluation Data; verify with `/model-validation` `check_split_leakage` | ## How to use 1. Walk the table; for each dimension, write the relevant fact into the **Datasheet** (or note it as a Model Card caveat). Unknown → `[NEEDS INPUT]`, never a guess. 2. Anything that affects the validity of the headline metric (leakage, representativeness, label provenance) is also a `/model-validation` finding — cross-check there. 3. The audit is **disclosure-oriented**: the deliverable is a complete, honest Datasheet + Model Card, not a quality score. -
model_card_template.md 3.2 KB
<!-- Model Card template (model-card skill). Structure follows Mitchell et al., "Model Cards for Model Reporting," ACM FAccT 2019 (arXiv:1810.03993), adapted for a clinical medical-imaging model. Fill every [NEEDS INPUT] from user-supplied facts — never fabricate a number, a dataset detail, or a performance result. Keep the section headings (check_model_card_complete.py verifies they are present and non-empty). --> # Model Card: [NEEDS INPUT: model name + version] ## Model Details - **Developed by**: [NEEDS INPUT: people / organisation] - **Model date / version**: [NEEDS INPUT] - **Model type / architecture**: [NEEDS INPUT: e.g. 3-D U-Net (nnU-Net v2)] - **Task**: [NEEDS INPUT: segmentation / classification / detection] - **Provenance**: [NEEDS INPUT: in-house / vendor / open-weights + version] - **License**: [NEEDS INPUT — state the licence the user confirmed; do not assume] - **Citation / contact**: [NEEDS INPUT] ## Intended Use - **Primary intended use**: [NEEDS INPUT: the clinical task + decision the model supports] - **Intended users**: [NEEDS INPUT: e.g. radiologists as a second reader] - **Deployment horizon**: [NEEDS INPUT: screening / triage / pre-procedure / post-hoc] ## Out-of-Scope Use - [NEEDS INPUT: uses the model must NOT be put to; populations / modalities / scanners it was not validated on; autonomous use if not validated for it] ## Factors - **Relevant factors / subgroups**: [NEEDS INPUT: age, sex, scanner/vendor, site, disease severity — the axes performance is expected to vary along] ## Training Data - **Source / cohort**: [NEEDS INPUT] - **Size**: [NEEDS INPUT: patients and images/structures] - **Label / reference standard**: [NEEDS INPUT: who labelled, annotator count, adjudication, inter-reader agreement; flag any model-derived "silver" labels] - **Preprocessing**: [NEEDS INPUT — note whether fit on the training fold only] ## Evaluation Data - **Source / cohort**: [NEEDS INPUT] - **Validation tier**: [NEEDS INPUT: internal split / cross-validation / temporal / external (site/scanner/vendor) — be honest; CV is not external validation] - **Split**: [NEEDS INPUT: patient-level, seed-locked? reference splits/split_assignment.csv] - **Test-set size**: [NEEDS INPUT: events / structures per class, not just patients] ## Metrics - **Metrics reported**: [NEEDS INPUT: segmentation → Dice + HD95/NSD per structure; classification → AUROC + AUPRC + sensitivity/specificity, with 95% CIs; detection → FROC/mAP] - **Operating point / threshold**: [NEEDS INPUT — fixed on train/tuning folds only] - **Run variance**: [NEEDS INPUT: mean ± SD over >= 3 seeds, or fixed seed + determinism caveat] ## Quantitative Analyses - **Overall performance**: [NEEDS INPUT — numbers from executed evaluation only] - **Disaggregated / subgroup performance**: [NEEDS INPUT: performance by the Factors above — the fairness-relevant breakdown] ## Ethical Considerations - [NEEDS INPUT: risks of error in this clinical context, automation bias, equity concerns, consent / governance of the data] ## Caveats and Recommendations - [NEEDS INPUT: known limitations, conditions for safe use, what further validation is needed before deployment]
-
-
scripts
-
check_model_card_complete_challenge
-
fixture
-
complete
-
DATASHEET.md 2.1 KB
# Datasheet: HepaSeg multiphase-CT dataset v1.0 (synthetic example) ## Motivation - **Purpose and creators**: created to train and evaluate liver-lesion segmentation; assembled by the imaging-AI group at a tertiary-care hospital, funded by an internal research grant. ## Composition - **Instance**: one instance is a single patient's portal-venous-phase CT volume with a lesion mask. - **Size and split**: 600 patients, split at the patient level into 384 train / 96 validation / 120 test. - **Label / target**: a binary lesion mask, derived from manual radiologist segmentation (reference standard). - **Modalities / acquisition**: multiphase abdominal CT from two scanner vendors, standard institutional protocol. - **Known imbalance / missingness / errors**: small lesions (under 1 cm) are under-represented; 4 studies excluded for motion artefact. ## Collection Process - **Acquisition**: consecutive eligible patients undergoing multiphase abdominal CT in the period. - **Time frame**: 2018-2024. - **Consent / IRB / governance**: IRB-approved retrospective study with a waiver of consent. ## Preprocessing / Cleaning / Labeling - **Preprocessing and order vs split**: resampling to 1 mm isotropic and intensity normalisation, with normalisation statistics fit on the training fold only. - **Annotation protocol**: two abdominal radiologists annotated independently; disagreements adjudicated by a third; inter-reader Dice 0.86. - **De-identification**: DICOM headers stripped of identifiers; pixel data checked for burned-in PHI. ## Uses - **Appropriate and inappropriate uses**: appropriate for liver-lesion segmentation research; must not be used to claim performance on non-contrast CT or other organs. - **Risks**: single-centre composition limits generalisability; re-identification risk considered low after de-identification. ## Distribution - **Availability and licence**: available to collaborators on request under a data-use agreement; not public; licence CC BY-NC 4.0. ## Maintenance - **Maintainer and versioning**: maintained by the imaging-AI group; contact data-steward@example.org; versioned, with errata communicated to data-use-agreement holders. -
MODEL_CARD.md 2.7 KB
# Model Card: HepaSeg-UNet v1.2 (synthetic example) ## Model Details - **Developed by**: the imaging-AI group at a tertiary-care hospital - **Model date / version**: 2026-03, v1.2 - **Model type / architecture**: 3-D residual U-Net (MONAI SegResNet backbone) - **Task**: liver-lesion segmentation on multiphase CT - **Provenance**: in-house, trained from scratch - **License**: CC BY-NC 4.0 (confirmed by the developing group) - **Citation / contact**: imaging-ai@example.org ## Intended Use - **Primary intended use**: second-reader assistance for delineating liver lesions on portal-venous CT - **Intended users**: board-certified radiologists reviewing abdominal CT - **Deployment horizon**: post-acquisition decision support, not autonomous reporting ## Out-of-Scope Use - Not validated for non-contrast CT, for paediatric patients, or for scanners outside the two vendors in the training set; must not be used autonomously without a radiologist in the loop. ## Factors - **Relevant factors / subgroups**: scanner vendor (two vendors), lesion size (under vs over 2 cm), and presence of cirrhosis. ## Training Data - **Source / cohort**: 480 patients with multiphase abdominal CT from a single tertiary centre, 2018-2023. - **Size**: 480 patients, 612 annotated lesions. - **Label / reference standard**: manual segmentation by two abdominal radiologists with disagreements adjudicated by a third; inter-reader Dice 0.86. - **Preprocessing**: HU windowing and z-score normalisation fit on the training fold only. ## Evaluation Data - **Source / cohort**: a temporally held-out cohort of 120 patients from the same centre, 2024. - **Validation tier**: temporal internal validation (single centre); no external-site test. - **Split**: patient-level, seed-locked (see splits/split_assignment.csv, seed 42). - **Test-set size**: 120 patients, 158 lesions. ## Metrics - **Metrics reported**: Dice and HD95 per lesion, plus per-patient mean Dice, with 95% CIs. - **Operating point / threshold**: probability threshold 0.5, fixed on the training fold. - **Run variance**: mean +/- SD over 3 seeds. ## Quantitative Analyses - **Overall performance**: mean Dice 0.81 (95% CI 0.78-0.84), HD95 7.2 mm, on the held-out cohort. - **Disaggregated / subgroup performance**: Dice 0.74 for lesions under 2 cm vs 0.85 over 2 cm; comparable across the two scanner vendors. ## Ethical Considerations - Errors could lead to missed lesions; automation bias is a risk if used without independent review. The training cohort is single-centre and may not represent other populations. ## Caveats and Recommendations - Single-centre, temporally validated only; external multi-site validation is required before deployment. Performance on small lesions is weaker and should be communicated to users.
-
-
incomplete
-
MODEL_CARD.md 880 B
# Model Card: HepaSeg-UNet v1.2 (synthetic, incomplete) ## Model Details - **Model type / architecture**: 3-D residual U-Net - **Task**: liver-lesion segmentation on multiphase CT ## Intended Use - **Primary intended use**: second-reader assistance for delineating liver lesions <!-- NOTE: the "Out-of-Scope Use" section is missing entirely -> MISSING_SECTION --> ## Training Data - **Source / cohort**: 480 patients from a single tertiary centre. ## Evaluation Data - **Validation tier**: temporal internal validation, single centre. ## Metrics - **Metrics reported**: Dice and HD95 with 95% CIs. ## Quantitative Analyses - **Overall performance**: mean Dice 0.81 (95% CI 0.78-0.84). ## Ethical Considerations - Errors could lead to missed lesions; automation bias is a risk. ## Caveats and Recommendations - [NEEDS INPUT: known limitations and conditions for safe use]
-
-
-
problem.md 1.8 KB
# Challenge card — Model Card / Datasheet completeness (model-card) ## Problem A clinician who receives an engineer-built model is expected to ship a **Model Card** (Mitchell et al., *FAccT* 2019) and a dataset **Datasheet** (Gebru et al., *CACM* 2021) for the repo / Hugging Face card / manuscript supplement. The common failure is a card that *looks* complete but quietly omits the load-bearing sections — Intended Use, Out-of-Scope Use, the subgroup analysis, Caveats — or leaves them as unfilled `[NEEDS INPUT]` placeholders. A reviewer (or a deployer) then cannot tell what the model is for or where it must not be used. ## What the gate does `scripts/check_model_card_complete.py` verifies that every **required** Model Card and Datasheet section is **present** and **non-empty** — not missing, and not left as an unfilled placeholder. It is a presence check (the documentation analogue of `check_disclosure_availability`); it does **not** judge whether a stated fact is true (that is `/model-validation` and the human). It never fills a section itself — the deliverable is a card the user completed from real facts. ## Fixture (synthetic only — no real model, no PII) - `fixture/complete/MODEL_CARD.md` + `fixture/complete/DATASHEET.md` — a fully filled, synthetic example (a tertiary-care-hospital liver-lesion segmentation model). - `fixture/incomplete/MODEL_CARD.md` — omits **Out-of-Scope Use** entirely and leaves **Caveats and Recommendations** as `[NEEDS INPUT]`. ## Expected (`verify.sh`, network-free) 1. the complete card + datasheet **pass** (exit 0). 2. the incomplete card **fails** with `MISSING_SECTION` (Out-of-Scope Use) + `EMPTY_REQUIRED_SECTION` (Caveats). 3. the **unfilled template** itself fails — the gate exists precisely to force the user to fill every section before the card is shipped. -
verify.sh 1.8 KB
#!/usr/bin/env bash # Deterministic verifier for the Model Card / Datasheet completeness challenge. # Network-free, stdlib-only. Exit 0 = the gate passes a complete card+datasheet and # flags an incomplete one (missing section + unfilled placeholder). set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" DET="$HERE/../check_model_card_complete.py" TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT # (1) complete card + datasheet -> OK, exit 0 python3 "$DET" --card "$HERE/fixture/complete/MODEL_CARD.md" \ --datasheet "$HERE/fixture/complete/DATASHEET.md" --strict --quiet \ || { echo "FAIL: a complete Model Card + Datasheet should pass (exit 0)" >&2; exit 1; } # (2) incomplete card -> exit 1 with MISSING_SECTION (Out-of-Scope) + EMPTY (Caveats) python3 "$DET" --card "$HERE/fixture/incomplete/MODEL_CARD.md" --out "$TMP/inc.json" --strict --quiet \ && { echo "FAIL: an incomplete Model Card should exit 1 under --strict" >&2; exit 1; } || true python3 - "$TMP/inc.json" <<'PY' || exit 1 import json, sys d = json.load(open(sys.argv[1])) v = {c["verdict"] for c in d["claims"]} assert "MISSING_SECTION" in v, "expected MISSING_SECTION (Out-of-Scope Use absent)" assert "EMPTY_REQUIRED_SECTION" in v, "expected EMPTY_REQUIRED_SECTION (Caveats unfilled)" det = " ".join(c["detail"] for c in d["claims"]) assert "Out-of-Scope Use" in det and "Caveats" in det, det print(" incomplete card flagged: MISSING(Out-of-Scope) + EMPTY(Caveats)") PY # (3) the unfilled templates themselves must fail (the gate exists to force filling) python3 "$DET" --card "$HERE/../../references/model_card_template.md" --strict --quiet \ && { echo "FAIL: the unfilled template should not pass" >&2; exit 1; } || true echo " unfilled template correctly fails" echo "PASS: completeness gate accepts a filled Model Card+Datasheet and flags missing/unfilled sections."
-
-
check_model_card_complete.py 8.7 KB
#!/usr/bin/env python3 """Model Card / Datasheet completeness gate (model-card). A documentation-completeness linter for an AI model's Model Card (Mitchell et al., ACM FAccT 2019) and, optionally, its dataset Datasheet (Gebru et al., Commun. ACM 2021). It verifies that every required section is **present** and **non-empty** — i.e. not missing and not left as an unfilled `[NEEDS INPUT]` / TODO placeholder. It is a presence check (the documentation analogue of check_disclosure_availability / check_summary_box); it does NOT judge whether a stated fact is true (that is /model-validation and the human). CHECKS (verdicts): 1. MISSING_SECTION (Major) a required section heading is absent. 2. EMPTY_REQUIRED_SECTION (Major) a required section is present but has no real content — empty, or every content line is an unfilled placeholder ([NEEDS INPUT] / TODO / [VERIFY] / XXXX / <...>). Required Model Card sections: Model Details, Intended Use, Out-of-Scope Use, Training Data, Evaluation Data, Metrics, Quantitative Analyses, Ethical Considerations, Caveats and Recommendations. Required Datasheet sections (with --datasheet): Motivation, Composition, Collection Process, Preprocessing / Cleaning / Labeling, Uses, Distribution, Maintenance. INPUTS --card MODEL_CARD.md (required). --datasheet DATASHEET.md (optional; if given, its sections are checked too). OUTPUT A table (stdout) and, with --out, a JSON artifact: {card, datasheet, claims[{verdict, severity, detail, where}], summary} Both verdicts are Major. Stdlib-only (re / json / argparse / pathlib). Exit codes: 0 clean (or report-only), 1 Major claim(s) found (with --strict), 2 input/usage error. """ from __future__ import annotations import argparse import json import re import sys from pathlib import Path # A full unfilled-placeholder SPAN: the entire `[NEEDS INPUT ...]` / `[VERIFY ...]` bracket # (so the descriptive hint inside it is removed too), plus standalone TODO / TBD / <...> / XXXX. PLACEHOLDER_SPAN = re.compile( r"\[(?:NEEDS INPUT|VERIFY)[^\]]*\]|<[^>]*>|\bTODO\b|\bTBD\b|X{4,}", re.IGNORECASE) # canonical key -> (display label, [alias regexes on the normalized heading]) MODEL_CARD_REQUIRED = [ ("model_details", "Model Details", [r"model details"]), ("intended_use", "Intended Use", [r"intended use"]), ("out_of_scope", "Out-of-Scope Use", [r"out of scope"]), ("training_data", "Training Data", [r"training data"]), ("evaluation_data", "Evaluation Data", [r"evaluation data", r"eval data", r"test data"]), ("metrics", "Metrics", [r"^metrics$", r"^metrics "]), ("quant", "Quantitative Analyses", [r"quantitative analys[ie]s"]), ("ethics", "Ethical Considerations", [r"ethical considerations", r"^ethics"]), ("caveats", "Caveats and Recommendations", [r"caveats"]), ] DATASHEET_REQUIRED = [ ("motivation", "Motivation", [r"^motivation"]), ("composition", "Composition", [r"^composition"]), ("collection", "Collection Process", [r"collection"]), ("preprocessing", "Preprocessing / Cleaning / Labeling", [r"preprocessing", r"cleaning", r"labeling", r"labelling"]), ("uses", "Uses", [r"^uses$", r"^uses "]), ("distribution", "Distribution", [r"^distribution"]), ("maintenance", "Maintenance", [r"^maintenance"]), ] def _norm_heading(text: str) -> str: t = text.lower() t = re.sub(r"[*_`#]", "", t) t = re.sub(r"[^a-z0-9 /]+", " ", t) return re.sub(r"\s+", " ", t).strip() def parse_sections(text: str) -> list[tuple[str, str]]: """Return [(normalized_heading, body_text)] for each ATX heading in order.""" lines = text.splitlines() sections = [] cur_h, cur_body = None, [] for ln in lines: m = re.match(r"^(#{1,6})\s+(.*)$", ln) if m: if cur_h is not None: sections.append((cur_h, "\n".join(cur_body))) cur_h = _norm_heading(m.group(2)) cur_body = [] elif cur_h is not None: cur_body.append(ln) if cur_h is not None: sections.append((cur_h, "\n".join(cur_body))) return sections def _has_real_content(body: str) -> bool: """True if the section carries a filled value — not empty and not only unfilled placeholders / field labels. The body is flattened (so a placeholder wrapped across lines is still removed as one span), HTML comments are dropped, then unfilled-placeholder spans and bold field-labels ('**Source**:') are removed; what remains is the real value.""" body = re.sub(r"<!--.*?-->", " ", body, flags=re.DOTALL) # drop HTML comments text = " ".join(body.split()) # flatten line wraps if not text: return False text = PLACEHOLDER_SPAN.sub(" ", text) # remove [NEEDS INPUT ...] etc. text = re.sub(r"\*\*[^*]+\*\*:?", " ", text) # remove bold field labels text = re.sub(r"[*_`>#]+", " ", text) # strip residual markdown low = text.lower() if re.search(r"\b(n/?a|none|not applicable|not collected|nil|waived)\b", low): return True # an explicit "empty" answer is filled core = re.sub(r"[^a-z0-9]+", "", low) return len(core) >= 3 # a real value remains def _check_doc(path: Path, required, label: str) -> list[dict]: claims = [] sections = parse_sections(path.read_text(encoding="utf-8")) for key, disp, aliases in required: match = None for norm_h, body in sections: if any(re.search(a, norm_h) for a in aliases): match = (norm_h, body) break if match is None: claims.append({ "verdict": "MISSING_SECTION", "severity": "Major", "detail": f"{label}: required section '{disp}' is absent", "where": path.name, }) elif not _has_real_content(match[1]): claims.append({ "verdict": "EMPTY_REQUIRED_SECTION", "severity": "Major", "detail": f"{label}: section '{disp}' is present but empty / only an unfilled " f"placeholder ([NEEDS INPUT] etc.)", "where": path.name, }) return claims def analyze(card: str, datasheet: str | None) -> dict: claims = _check_doc(Path(card), MODEL_CARD_REQUIRED, "Model Card") if datasheet: claims += _check_doc(Path(datasheet), DATASHEET_REQUIRED, "Datasheet") n_major = sum(1 for c in claims if c["severity"] == "Major") return { "card": card, "datasheet": datasheet, "claims": claims, "summary": {"n_claims": len(claims), "n_major": n_major, "verdict": "MAJOR_CANDIDATE" if n_major else "OK"}, } def render(result: dict) -> str: lines = ["| Check | Severity | Detail |", "|---|---|---|"] for c in result["claims"]: lines.append(f"| {c['verdict']} | {c['severity']} | {c['detail']} |") if len(lines) == 2: lines.append("| (none) | — | all required sections present and filled |") return "\n".join(lines) def main() -> int: ap = argparse.ArgumentParser(description="Model Card / Datasheet completeness gate.") ap.add_argument("--card", required=True, help="MODEL_CARD.md") ap.add_argument("--datasheet", help="DATASHEET.md (optional)") ap.add_argument("--out", help="write JSON artifact to this path") ap.add_argument("--strict", action="store_true", help="exit 1 if any Major claim exists") ap.add_argument("--quiet", action="store_true", help="suppress stdout table") args = ap.parse_args() for label, p in (("--card", args.card), ("--datasheet", args.datasheet)): if p and not Path(p).is_file(): sys.stderr.write(f"ERROR: {label} not found: {p}\n") return 2 result = analyze(args.card, args.datasheet) if not args.quiet: print("=" * 41) print(" Model Card / Datasheet Completeness") print("=" * 41) print(render(result)) print() s = result["summary"] print(f"MAJOR candidate: {s['n_major']} incomplete-documentation issue(s)." if s["n_major"] else "OK: all required Model Card / Datasheet sections present and filled.") if args.out: Path(args.out).parent.mkdir(parents=True, exist_ok=True) Path(args.out).write_text(json.dumps({"detector": "check_model_card_complete", **result}, indent=2), encoding="utf-8") if not args.quiet: print(f"\nwrote {args.out}") return 1 if (args.strict and result["summary"]["n_major"]) else 0 if __name__ == "__main__": sys.exit(main())
-
-
tests
-
test_model_card_complete.sh 2.7 KB
#!/usr/bin/env bash # Regression test for the Model Card / Datasheet completeness gate (model-card). # Synthetic, PII-free. Stdlib-only (python3). set -u HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DET="$HERE/../scripts/check_model_card_complete.py" CH="$HERE/../scripts/check_model_card_complete_challenge" REF="$HERE/../references" OUT="$(mktemp -t mcc_XXXX).json" trap 'rm -f "$OUT"' EXIT fail=0 check() { local label="$1"; shift if "$@" >/dev/null 2>&1; then printf ' PASS %s\n' "$label" else printf ' FAIL %s\n' "$label"; fail=$((fail+1)); fi } has() { python3 -c " import json d=json.load(open('$OUT')) assert any(c['verdict']=='$1' for c in d['claims']), '$1 not found'"; } count() { python3 -c " import json d=json.load(open('$OUT')) assert len(d['claims'])==$1, f\"{len(d['claims'])} != $1\""; } [[ -f "$DET" ]] || { echo "ENV-ERR: detector missing" >&2; exit 2; } # (1) complete card + datasheet -> OK, exit 0 python3 "$DET" --card "$CH/fixture/complete/MODEL_CARD.md" --datasheet "$CH/fixture/complete/DATASHEET.md" --strict --quiet >/dev/null 2>&1 check "complete card+datasheet passes (exit 0)" test "$?" -eq 0 # (2) incomplete card -> exit 1, MISSING + EMPTY python3 "$DET" --card "$CH/fixture/incomplete/MODEL_CARD.md" --out "$OUT" --strict --quiet >/dev/null 2>&1 check "incomplete card exits 1" test "$?" -eq 1 check "MISSING_SECTION detected" has MISSING_SECTION check "EMPTY_REQUIRED_SECTION detected" has EMPTY_REQUIRED_SECTION # (3) unfilled Model Card template -> all 9 required sections empty python3 "$DET" --card "$REF/model_card_template.md" --out "$OUT" --strict --quiet >/dev/null 2>&1 check "unfilled card template exits 1" test "$?" -eq 1 check "9 empty sections in unfilled card template" count 9 # (4) unfilled card + datasheet templates -> 9 + 7 = 16 empty python3 "$DET" --card "$REF/model_card_template.md" --datasheet "$REF/datasheet_template.md" --out "$OUT" --quiet >/dev/null 2>&1 check "16 empty sections across both unfilled templates" count 16 # (5) "N/A" / "None" count as a filled answer (not flagged empty) TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"; rm -f "$OUT"' EXIT cat > "$TMP/card.md" <<'MD' # Model Card: t ## Model Details - **Type**: U-Net ## Intended Use - triage ## Out-of-Scope Use - N/A ## Training Data - 100 patients ## Evaluation Data - internal split ## Metrics - Dice with CI ## Quantitative Analyses - Dice 0.8 ## Ethical Considerations - None ## Caveats and Recommendations - single centre MD python3 "$DET" --card "$TMP/card.md" --out "$OUT" --strict --quiet >/dev/null 2>&1 check "N/A and None count as filled (exit 0)" test "$?" -eq 0 echo "fail=$fail"; [[ "$fail" -eq 0 ]] && echo "ALL PASS" || echo "FAILURES: $fail" exit "$fail"
-
-
SKILL.md 5.7 KB
--- name: model-card description: > Generate the documentation an engineer-built medical-imaging model must carry — a Model Card (Mitchell et al. 2019), a Datasheet for its dataset (Gebru et al. 2021), and a METRIC-informed data-quality pass — filled from user-supplied facts, then verify every required section is present and non-empty before the card ships to a repo, Hugging Face card, or manuscript supplement. Never fabricates numbers, provenance, consent, or licence; unfilled fields stay flagged. Ships a deterministic completeness gate. Model Card and Datasheet are documentation standards vendored here as templates, not counted reporting checklists. triggers: model card, model cards, datasheet, datasheet for datasets, dataset documentation, model documentation, hugging face card, model metadata, intended use, out-of-scope, data quality, METRIC framework, model reporting, document a model tools: Read, Write, Edit, Bash, Grep, Glob model: inherit --- # Model-Card Skill ## Purpose This skill produces the **documentation an engineer-built medical-imaging model must carry**: a **Model Card** (intended use, out-of-scope use, training data, per-subgroup performance, caveats), a **Datasheet** for its dataset (provenance, composition, collection, labelling, consent), and a **METRIC-informed data-quality pass**. It fills the templates **from facts the user supplies** — it never invents a number, a provenance detail, a consent status, or a licence — and ships a deterministic gate that no required section is missing or left as an unfilled `[NEEDS INPUT]` placeholder. It is the **reporting** seam of the model-engineering lane: after `/model-validation` audits the design and `/model-evaluation` produces the numbers, this skill records them in a portable, auditable card that `/write-paper` and `/check-reporting` consume. It mirrors `/version-dataset` structurally (generate + deterministic verify). ## When to use - A trained model needs a Model Card / Datasheet for a repo, Hugging Face card, or manuscript supplement. ## When NOT to use - Auditing the validation design / metrics → `/model-validation`, `/model-evaluation`. - Versioning the dataset bytes → `/version-dataset`; tabular variable docs → `/generate-codebook`. - Item-by-item reporting-guideline compliance of the manuscript → `/check-reporting`. - Building / training the model → `/model-scaffold`. ## Workflow ### Phase 1 — Collect the facts Gather, from the user / the model's developers: task + architecture + provenance + licence; intended use and out-of-scope use; training and evaluation cohorts; the reference standard and inter-reader agreement; overall and **per-subgroup** performance; data collection, consent, and de-identification. Anything not supplied stays `[NEEDS INPUT]` — never guess. ### Phase 2 — Fill the Model Card Copy `${CLAUDE_SKILL_DIR}/references/model_card_template.md` to `MODEL_CARD.md` and fill each section from the facts. Keep the headings. Numbers come only from `/model-evaluation` / executed results. ### Phase 3 — Fill the Datasheet Copy `${CLAUDE_SKILL_DIR}/references/datasheet_template.md` to `DATASHEET.md` and fill the seven question groups (Motivation, Composition, Collection, Preprocessing/Labeling, Uses, Distribution, Maintenance). ### Phase 4 — METRIC data-quality pass Walk `${CLAUDE_SKILL_DIR}/references/metric_dimensions.md` (completeness, correctness, consistency, representativeness, timeliness, provenance, label provenance, fairness/coverage, leakage safety) and record each finding in the Datasheet. Anything that affects the headline metric's validity is also a `/model-validation` finding — cross-check there. ### Phase 5 — Verify completeness (deterministic gate) ```bash python3 ${CLAUDE_SKILL_DIR}/scripts/check_model_card_complete.py \ --card MODEL_CARD.md --datasheet DATASHEET.md --strict ``` `MISSING_SECTION` / `EMPTY_REQUIRED_SECTION` must be zero before the card ships. ### Phase 6 — Hand off Carry the card into `/write-paper` (the Methods / supplement reference it), `/check-reporting` (CLAIM 2024 / TRIPOD+AI item audit of the manuscript), and `/self-review`. ## Anti-Hallucination - **Never invent evaluation numbers, subgroup results, or dataset provenance.** Every figure comes from `/model-evaluation` or the user's executed results; every provenance / consent / licence statement is user-confirmed. Unknown → `[NEEDS INPUT]`, which the gate flags. - **Never mark a section complete without user-supplied content**, and never auto-fill a placeholder to pass the gate. - **Never assert a licence or consent status the user did not confirm.** - The gate checks **presence**, not truth — a complete card can still contain a wrong number; validity is `/model-validation` and the human's responsibility. ## Deterministic gate `scripts/check_model_card_complete.py` — verifies every required Model Card / Datasheet section is present and non-empty (stdlib, network-free). Reproducible challenge: `bash ${CLAUDE_SKILL_DIR}/scripts/check_model_card_complete_challenge/verify.sh`. ## Note on classification Model Cards (Mitchell et al. 2019) and Datasheets (Gebru et al. 2021) are **documentation standards**, not clinical reporting guidelines, so they live here as `references/` **templates** (uncounted), not in `/check-reporting`'s counted checklist set — the same way `appraisal_tools/METRICS.md` is kept separate. `/check-reporting` still owns the manuscript-level CLAIM 2024 / TRIPOD+AI item audit. ## Boundaries ``` model-validation (audit design) + model-evaluation (metrics) └─ model-card (this skill: Model Card + Datasheet + METRIC pass, completeness-gated) └─ write-paper + check-reporting (manuscript) ; version-dataset (dataset bytes) ``` -
skill.yml 2.8 KB
schema_version: 2 name: model-card layer: C owner_domain: model_reporting maturity: official when_to_use: "Generate the documentation an engineer-built medical-imaging model must carry — a Model Card (Mitchell et al. 2019), a Datasheet for its dataset (Gebru et al. 2021), and a METRIC-informed data-quality pass — filled from user-supplied facts, and verify every required section is present and non-empty before the card ships to a repo, Hugging Face card, or manuscript supplement." when_NOT_to_use: "Auditing the validation design or metrics (use model-validation); versioning the dataset bytes (use version-dataset); documenting variables in a tabular dataset (use generate-codebook); item-by-item reporting-guideline compliance of the manuscript (use check-reporting); building or training the model (use model-scaffold)." inputs: - "model metadata (task, architecture, training-data provenance, intended use, licence)" - "evaluation results (performance overall + by subgroup) and dataset description (collection, labelling, consent, de-identification)" outputs: - "MODEL_CARD.md (filled, sectioned)" - "DATASHEET.md (filled, sectioned) + a METRIC data-quality pass recorded in it" - "model-card completeness audit JSON (deterministic)" deterministic_scripts: - scripts/check_model_card_complete.py side_effects: - writes_documentation_artifacts downstream_consumers: - check-reporting - write-paper - self-review forbidden_actions: - invent_evaluation_numbers_subgroup_results_or_dataset_provenance - mark_a_section_complete_without_user_supplied_content - assert_a_licence_or_consent_status_the_user_did_not_confirm # v2.1 quality card purpose: "Produce an auditable Model Card + Datasheet so an engineer-built model carries its intended-use, out-of-scope, training-data, per-subgroup-performance, and limitations record into clinical evaluation and publication — with a deterministic gate that no required section is missing or left as an unfilled placeholder." safety_boundaries: - "Templates are filled only from user-supplied facts; an empty required field stays [NEEDS INPUT] and is flagged, never auto-filled or guessed." - "Completeness is reproduced by a stdlib script; it checks presence, not the truth of a stated fact (that is model-validation / check-reporting)." known_limitations: - "Documents what is supplied; it cannot verify that a stated performance number or provenance claim is real." - "Model Card / Datasheet are documentation standards, not clinical reporting guidelines — they are vendored as templates here, not counted reporting checklists." validation_commands: - "python3 scripts/check_model_card_complete.py --card MODEL_CARD.md --datasheet DATASHEET.md --strict" - "bash scripts/check_model_card_complete_challenge/verify.sh # deterministic, network-free" evidence_surface: ci_validator
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.