$npx -y skills add probabl-ai/skills --skill test-ml-pipelineOwns the tests/ folder of an ML workspace and the pairing rule between an experiment and its tests. Lightweight router: every test category has its own subskill (smoke-test-ml-pipeline is the only one for v1; regression-test-ml-pipeline / distribution-test-ml-pipeline etc
| 1 | # Test ML Pipeline (router) |
| 2 | |
| 3 | Where tests for an ML workspace live, what gets paired with what, |
| 4 | and which subskill owns the body of each test category. |
| 5 | |
| 6 | ## First action (every turn) |
| 7 | |
| 8 | Before answering anything else: |
| 9 | |
| 10 | 1. **Confirm an approved design note exists** for the test |
| 11 | the user is asking about. The pairing rule is hard: |
| 12 | `tests/<category>/test_NN_<short_name>.py` only exists if |
| 13 | `journal/NN_<short_name>.md` is at least `approved` and |
| 14 | `experiments/NN_<short_name>.py` is the matching script. If |
| 15 | the design note doesn't exist, hand back to `iterate-ml-experiment`. |
| 16 | 2. **Emit the Pre-flight checklist** (below) as visible text in |
| 17 | your response, with each box marked. |
| 18 | 3. **Use the Dispatch table** to pick the subskill that owns the |
| 19 | test category, then hand off. |
| 20 | |
| 21 | ## Pre-flight — emit this checklist as visible text before any test work |
| 22 | |
| 23 | ``` |
| 24 | Pre-flight (test-ml-pipeline): |
| 25 | - [ ] `journal/NN_<short_name>.md` exists and is at least `approved` |
| 26 | (or confirmed n/a — about to hand off to `iterate-ml-experiment`) |
| 27 | - [ ] `experiments/NN_<short_name>.py` exists with the matching stem |
| 28 | (or confirmed n/a — about to hand off to `organize-ml-workspace`) |
| 29 | - [ ] Test category picked: smoke | regression | distribution | … |
| 30 | - [ ] Subskill dispatched: `smoke-test-ml-pipeline` | … |
| 31 | - [ ] Test file stem decided: `tests/<category>/test_NN_<short_name>.py` |
| 32 | - [ ] pytest is on the project's dependency manifest (per |
| 33 | `data-science-python-stack` § Tier 1) |
| 34 | ``` |
| 35 | |
| 36 | ## Stop conditions — read before anything else |
| 37 | |
| 38 | - **No test without an approved design note.** Never create |
| 39 | `tests/<category>/test_NN_*.py` if the matching `journal/NN_*.md` |
| 40 | isn't on disk and at least `approved`. The design note is the contract; |
| 41 | the test asserts the contract holds. Reverse order is incoherent. |
| 42 | - **The stem rule is hard.** Test file basename is |
| 43 | `test_NN_<short_name>.py` (with the `test_` prefix that pytest |
| 44 | expects); the `NN_<short_name>` portion matches the experiment |
| 45 | exactly. One experiment → one test file per category. No |
| 46 | `test_<NN>_v2.py`, no `test_NN_<short_name>_2.py`. If a test |
| 47 | needs to evolve, edit it in place; the pairing must stay 1:1. |
| 48 | - **One subskill per category.** This skill only places the empty |
| 49 | test file and hands off. Don't write assertion bodies, fixture |
| 50 | construction, or test-specific logic in this skill — that belongs |
| 51 | to the matching subskill (`smoke-test-ml-pipeline`, etc.). |
| 52 | - **pytest is the runner.** Tests are pytest tests, not |
| 53 | jupytext-style `# %%` scripts. The experiment scripts live in |
| 54 | `experiments/` and stay `# %%`-style for interactive iteration; |
| 55 | the tests are binary pass/fail and benefit from pytest's |
| 56 | reporting. Don't mix the two conventions. |
| 57 | |
| 58 | ## Layout this skill owns |
| 59 | |
| 60 | ``` |
| 61 | project/ |
| 62 | └── tests/ |
| 63 | ├── smoke/ |
| 64 | │ ├── test_01_baseline.py # ↔ experiments/01_baseline.py |
| 65 | │ ├── test_02_short_name.py |
| 66 | │ └── ... |
| 67 | └── (future: regression/, distribution/, …) |
| 68 | ``` |
| 69 | |
| 70 | The pairing rule: |
| 71 | |
| 72 | ``` |
| 73 | journal/NN_<short_name>.md |
| 74 | experiments/NN_<short_name>.py |
| 75 | tests/<category>/test_NN_<short_name>.py |
| 76 | ``` |
| 77 | |
| 78 | — same `NN_<short_name>` stem in all three. The `test_` prefix on |
| 79 | the test file basename is the pytest naming |