Skip to content
Back to skills

Check Cell Order

ASecurity

Detect cell-ordering / enchainement problems in Jupyter notebooks (canonical-order slippage, misplaced or forgotten cells). Arguments: [target] [--severity HIGH|MED|LOW] [--json]

  • 16 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 20, 2026
educationpythongobashgit

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add jsboige/CoursIA --skill check-cell-order --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Check Cell Order?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Check Cell Order
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jsboige-check-cell-order/badge)](https://www.skillsdirectory.com/skills/jsboige-check-cell-order)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: check-cell-order
description: Detect cell-ordering / enchainement problems in Jupyter notebooks (canonical-order slippage, misplaced or forgotten cells). Arguments: [target] [--severity HIGH|MED|LOW] [--json]
---

# Check Cell Order

Scan notebooks for **cell-ordering and enchainement (flow) problems** — the class
friction reported after the SymbolicLearning session: *"certaines choses
n'étaient pas à leur place"* (canonical-order slippage and forgotten / misplaced
cells that slip through upstream review).

Backed by `scripts/notebook_tools/scan_cell_ordering.py`, which reads the
**beginning and the end of every cell** and reports graded findings, each citing
the offending text so it is spot-checkable. Epic #3240.

**Target**: `$ARGUMENTS`

## Arguments

- `target`: a notebook path, a family subpath (`--family SymbolicAI/SymbolicLearning`), or `--all`
- `--severity HIGH|MED|LOW`: only show findings at or above this level
- `--json`: machine-readable output (for piping / CI)
- `--fail-on HIGH|MED|LOW`: exit 1 if any finding at/above this level (default `HIGH`)

## What it detects

| Severity | Category | Meaning |
|----------|----------|---------|
| HIGH | `SECTION_ORDER` | numbered markdown headers go backwards under the same parent (`## 3.` then `## 2.`) |
| HIGH | `EXERCISE_ORDER` | `Exercice N` / `Exemple N` labels out of order |
| MED | `DANGLING_INTRO` | a markdown cell ends announcing imminent code, but the next cell is **not** code (forgotten / misplaced cell) |
| MED | `INTERP_BEFORE_CODE` | an interpretation markdown sits **before** the code it comments instead of after its output |
| LOW | `SECTION_GAP` | a numbered header skips a value (possible omission) |
| LOW | `CONSECUTIVE_CODE` | more than 3 code cells in a row with no markdown between |

Legitimate numbering is **silent by design**: a normal increment (1→2), a
sub-section open/close (3→3.1→4), a reset-to-1 group restart, a level-mixed H1
title (`# 13.` series number vs `## 1.` sections), fenced-code comments, and
TOC / overview cells listing ≥2 labels.

## Process

1. **Run the scanner** on the target:
   ```bash
   python scripts/notebook_tools/scan_cell_ordering.py <target> --severity HIGH
   # or a whole family:
   python scripts/notebook_tools/scan_cell_ordering.py --family SymbolicAI/SymbolicLearning
   # or the whole repo:
   python scripts/notebook_tools/scan_cell_ordering.py --all --severity HIGH
   ```
   On this machine the script needs a Python with the stdlib only; any of the
   notebook kernels works (e.g. `C:/Users/MYIA/AppData/Local/Programs/Python/Python310/python.exe`).

2. **Ground-truth every HIGH finding before acting** (rule G.1 — the finding is
   a *signal*, not a verdict). Dump the actual headers / labels in document
   order to confirm it is a true positive, e.g.:
   ```bash
   python - <<'PY'
   import json, re
   from pathlib import Path
   H = re.compile(r"^(#{1,6})\s+(\d+(?:\.\d+)*)\b")
   nb = json.loads(Path("<notebook>").read_text(encoding="utf-8"))
   for i, c in enumerate(nb["cells"]):
       if c.get("cell_type") != "markdown":
           continue
       for ln in "".join(c["source"]).splitlines():
           if H.match(ln.strip()):
               print(f"cell#{i}", ln.strip()[:70])
   PY
   ```

3. **Fix or justify**:
   - **True positive** → re-order the cells with `NotebookEdit` (work **bottom→top** to avoid index shift). Re-order **clears outputs**, so re-execute the affected notebook (Papermill, rule C.2) before commit.
   - **Defensible by design** (rare residual FP) → leave it; if recurrent, harden the scanner and add a regression case to `scripts/notebook_tools/tests/test_scan_cell_ordering.py`.

4. **Re-scan** the notebook / family to confirm 0 unjustified HIGH before commit.

## Conventions

- Canonical ordering convention: see `.claude/rules/notebook-conventions.md`
  ("Structure pédagogique" + "Enchaînement des cellules").
- Classification of Exercice vs Exemple is **content-based** — do NOT relabel to
  silence a finding (see `.claude/rules/exercise-example-labeling.md`).
- C.1/C.2/C.3 still apply: no `raise NotImplementedError` in stubs; commit with
  outputs; only stage notebooks whose source changed.

## CI

The scanner is wired into a per-PR gate that scans the notebooks changed by a PR
and fails on HIGH (`--fail-on HIGH`). Pre-existing findings in untouched
notebooks are tracked separately under Epic #3240 and do not block unrelated PRs.

## Notes

- The scanner is **read-only** — it never edits notebooks. Fixes are a separate,
  deliberate step.
- Exit codes: `0` clean / `1` finding at/above `--fail-on` / `2` usage or IO error.
- A malformed notebook prints `ERROR <path>: <reason>` and the scan continues.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…