Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Profile a medical-imaging dataset before any modelling decision is made — the acquisition grid, voxel spacing and orientation spread, the intensity domain, which label values are actually present, how much of the volume the target occupies, and how large the target is in millilitres — then gate that profile against the researcher's declared plan. Catches, at the point where it is still cheap, the dataset facts that otherwise surface after a training run: a "test set" that carries no ground truth
.claude/skills/aperivue-profile-imaging/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 44% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 70% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 73% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 149% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 119% | 0% |
A dataset decides more of a study than the architecture does, and it decides it first. Before anything is preprocessed, split, or trained, a handful of facts are already true about the data, and each one closes off or opens up a research plan:
everywhere scores 99.6 %.
accept quietly; it is the most consequential preprocessing choice in the study, and it is also the axis along which an external dataset will differ.
imagesTs has no labels, it is not a test set, and the held-out set has tocome from somewhere else — better known before training than after.
that a subgroup analysis should be pre-specified for, rather than discovered post hoc.
None of that requires a model, a GPU, or an engineer. It requires reading every file once and writing down what is there. This skill does that, and then audits the plan against it.
It is the front door of the model-engineering lane: profile-imaging (describe) → /design-study + /architecture-zoo (decide) → /preprocess-imaging (plan the pipeline) → /model-scaffold (build) → /model-validation → /model-evaluation.
committing to a plan.
label values as declared) before anyone trains on it.
/generate-codebook (data dictionary) and /clean-data./preprocess-imaging (it consumes what this skill describes).
/model-validation./architecture-zoo. Building the repo → /model-scaffold./model-evaluation then /analyze-stats.bashpython3 scripts/profile_imaging_dataset.py \ --split train:imagesTr:labelsTr \ --split test:imagesTs \ --dataset "MSD Task09 Spleen" \ --declared-labels 0=background,1=spleen \ --target-label 1 \ --plan resample=true,reorient=false,loss=dice_ce,metrics=dice+hd95 \ --out eda/profile.json
One record per case: grid, spacing, orientation, intensity percentiles, the label values actually present, foreground fraction, and target volume in mL. A --split given no label directory is recorded as unlabelled — which is itself a finding.
--target-label on a multi-structure atlas. Foreground defaults to every non-zero index, which is the whole annotated anatomy. Run a single-organ study against a 15-organ atlas and the reported fraction describes the upper abdomen, not the target — measured on AMOS22 that is 3.2 % rather than the spleen's 0.2 %, so the pooled number sits above the 1 % imbalance threshold while the real target sits far below it, and the imbalance verdicts go quiet exactly where the risk is. Naming the target also makes LABEL_EMPTY mean this case has no spleen, which a multi-organ label file otherwise hides behind the other organs. Pass --target-label all for a genuinely multi-class study; leave it out on a multi-structure atlas and the gate raises TARGET_LABEL_UNDECLARED.
Requires nibabel + numpy (it has to open images). The gate below does not.
bashpython3 scripts/check_dataset_profile.py --profile eda/profile.json \ --out qc/dataset_profile.json --strict
Stdlib-only, so the audit re-runs anywhere the JSON travels. Verdicts:
| Verdict | Severity | Fires when | |---|---|---| | LABEL_SHAPE_MISMATCH | Major | label grid ≠ image grid | | LABEL_EMPTY | Major | a labelled case has zero foreground | | LABEL_VALUE_UNEXPECTED | Major | label values outside the declared set | | TEST_SET_UNLABELLED | Major | a split whose name contains test/held-out/external/eval carries no labels | | ACCURACY_UNDER_IMBALANCE | Major | accuracy is planned while the target is a sliver of the volume | | LABEL_MISSING | Minor | a case in a labelled split has no label file | | SPACING_HETEROGENEOUS | Minor | spacing spans ≥ ratio on an axis and no resampling is declared | | ORIENTATION_MIXED | Minor | >1 orientation code and no reorientation declared | | INTENSITY_SCALE_INCONSISTENT | Minor | some cases sit on the HU scale and others do not | | EXTREME_IMBALANCE | Minor | median foreground below the threshold with no Dice-family loss | | TARGET_LABEL_UNDECLARED | Minor | >1 structure declared but no target named, so foreground pools them all |
The gate flags an undeclared decision, not variability itself. A dataset with 5× spacing spread and two orientation codes passes cleanly once resampling and reorientation are declared — heterogeneity that has been dealt with is not a defect. That distinction is what the challenge card's clean fixture exists to prove.
--spacing-ratio (default 2.0) and --imbalance-frac (default 0.01) are screening defaults, not published cut-points: 2× through-plane spacing changes what a fixed-size patch sees, and 1 % foreground is roughly where plain accuracy stops carrying information. Both are adjustable and both are printed in the output, so a reader knows what was applied.
The profile is evidence; the decisions are yours, and the ones worth writing down are:
/preprocess-imaging as a declared transform.
boundary metric per structure (/model-evaluation); accuracy is not on the list.
slice thickness, modality). Pre-specifying them here is what separates a subgroup finding from a post-hoc one.
honest seed of the Limitations paragraph, written before the results can bias it.
Record these in the study record so /design-study, /preprocess-imaging, and eventually /write-paper inherit them rather than re-deriving them.
eda/profile.json — per-case dataset profile (the artifact downstream skills read).qc/dataset_profile.json — deterministic audit with verdicts.subgroups, held-out provenance, cohort limitations).
assumed label indices — open the labels and look).
--spacing-ratio / --imbalance-frac defaults as published thresholds.foreground fractions and organ volumes come from opening every image and label — not from a dataset's documentation, not from what a similar dataset looked like, and not from memory. A dataset's README can be wrong about its own label indices; the labels cannot.
check_dataset_profile.py. The verdictsare re-derived from the profile JSON by rule and arithmetic; a prose claim that the data "looks fine" is not the audit.
held-out metric can come from it, however the directory is named.
--spacing-ratio / --imbalance-frac as published cut-points. They arescreening defaults; the values applied are printed in the output and belong in the Methods.
bashpython3 scripts/check_dataset_profile.py --profile <profile.json> --strict bash scripts/check_dataset_profile_challenge/verify.sh # deterministic, network-free bash tests/test_dataset_profile.sh
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 28,090 | 14,960 | -47% | 1 | 1 | 0% | 6,248 | 2,435 | -61% | 0 | 0 | — |
case-02 | fail→fail | 29,283 | 4,401 | -85% | 1 | 1 | 0% | 6,233 | 2,443 | -61% | 0 | 0 | — |
case-03 | fail→fail | 24,756 | 4,380 | -82% | 1 | 1 | 0% | 5,489 | 2,409 | -56% | 0 | 0 | — |
case-04 | pass→pass | 16,653 | 3,360 | -80% | 1 | 1 | 0% | 2,904 | 2,754 | -5% | 0 | 0 | — |
case-05 | pass→fail | 20,982 | 16,017 | -24% | 1 | 1 | 0% | 4,336 | 4,915 | +13% | 0 | 0 | — |
case-06 | pass→pass | 11,341 | 5,314 | -53% | 1 | 1 | 0% | 1,757 | 3,095 | +76% | 0 | 0 | — |
case-07 | fail→pass | 13,724 | 6,121 | -55% | 1 | 1 | 0% | 2,323 | 3,350 | +44% | 0 | 0 | — |
case-08 | fail→pass | 12,975 | 7,398 | -43% | 1 | 1 | 0% | 2,010 | 3,427 | +70% | 0 | 0 | — |
case-09 | fail→pass | 10,814 | 3,637 | -66% | 1 | 1 | 0% | 1,631 | 2,827 | +73% | 0 | 0 | — |
case-10 | fail→pass | 6,955 | 2,861 | -59% | 1 | 1 | 0% | 1,063 | 2,649 | +149% | 0 | 0 | — |
case-11 | pass→pass | 7,324 | 3,940 | -46% | 1 | 1 | 0% | 1,139 | 2,880 | +153% | 0 | 0 | — |
case-12 | fail→pass | 7,206 | 2,846 | -61% | 1 | 1 | 0% | 1,216 | 2,657 | +119% | 0 | 0 | — |
case-13 | fail→pass | 5,766 | 2,223 | -61% | 1 | 1 | 0% | 984 | 2,598 | +164% | 0 | 0 | — |
case-14 | pass→pass | 16,742 | 2,763 | -83% | 1 | 1 | 0% | 2,778 | 2,765 | -0% | 0 | 0 | — |
case-15 | pass→pass | 12,512 | 3,124 | -75% | 1 | 1 | 0% | 1,926 | 2,753 | +43% | 0 | 0 | — |
case-16 | pass→pass | 8,682 | 5,186 | -40% | 1 | 1 | 0% | 1,401 | 3,139 | +124% | 0 | 0 | — |
case-17 | pass→pass | 11,968 | 3,883 | -68% | 1 | 1 | 0% | 1,881 | 2,784 | +48% | 0 | 0 | — |
case-18 | fail→pass | 8,045 | 4,784 | -41% | 1 | 1 | 0% | 1,385 | 3,031 | +119% | 0 | 0 | — |
case-19 | pass→pass | 9,818 | 2,553 | -74% | 1 | 1 | 0% | 1,717 | 2,618 | +52% | 0 | 0 | — |
case-20 | fail→pass | 8,590 | 4,574 | -47% | 1 | 1 | 0% | 1,520 | 3,020 | +99% | 0 | 0 | — |
case-21 | pass→pass | 9,811 | 2,102 | -79% | 1 | 1 | 0% | 1,623 | 2,556 | +57% | 0 | 0 | — |
case-22 | pass→pass | 11,842 | 4,843 | -59% | 1 | 1 | 0% | 1,863 | 2,949 | +58% | 0 | 0 | — |
case-23 | fail→pass | 6,434 | 3,175 | -51% | 1 | 1 | 0% | 1,100 | 2,831 | +157% | 0 | 0 | — |
case-24 | pass→pass | 13,394 | 7,022 | -48% | 1 | 1 | 0% | 2,043 | 3,251 | +59% | 0 | 0 | — |
case-25 | pass→pass | 18,494 | 12,491 | -32% | 1 | 1 | 0% | 2,945 | 4,176 | +42% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted, and 22 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +32 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.