Skip to main content

Pre-flight environment-semantics linter for ML workloads — catches code/hardware mismatches (e.g. scikit-learn on a GPU runtime) before you occupy the hardware.

Project description

nocando

A pre-flight environment-semantics linter for ML workloads. It answers one question before you occupy hardware — in either direction:

Is the code you wrote coherent with the environment you declared?

That covers CPU-only workloads parked on GPUs (waste), unconditional .cuda() calls headed for a CPU runtime (crash at minute 40), CUDA-requiring libraries on Apple Silicon (import failure), and wrong-generation hardware (flash-attn needs compute capability >= 8.0; a Colab T4 is 7.5). The unit of analysis is the mismatch. Deliberate slow-on-CPU choices are not flagged — can't legislate morality.

Syntax linters know your language. Type checkers know your data shapes. Nothing knows that from sklearn.svm import SVC plus "Runtime: T4" is an incoherent sentence — the constraint lives at the intersection of library × hardware × platform, and nobody owns intersections. nocando owns this one. Zero LLM calls, zero telemetry, pure static analysis.

Certified by Ted (stoop tabby, QA).

Why

Wasted accelerator time is deadweight loss: a scikit-learn grid search on a Colab T4 produces heat, not gradients, for however many hours you sit there. The knowledge to prevent this already exists — scattered across Stack threads and subreddits, indexed by symptom, findable only after you've failed. nocando inverts the indexing: it audits your declared intent (code + runtime) at the moment of declaration.

Usage

python nocando.py train.py --runtime t4
python nocando.py analysis.ipynb --runtime a100
python nocando.py train.py                 # autodetect via nvidia-smi / MPS
python nocando.py train.py --runtime t4 --json   # machine-readable, for CI

In Colab, one cell before your run:

!wget -q https://<your-host>/nocando.py
!python nocando.py /content/drive/MyDrive/train.py --runtime t4

Verdicts

Verdict Exit Meaning
✓ CLEARED FOR TAKEOFF 0 Accelerator request is coherent with this code
△ WILL RUN, BUT 1 Runs, but the allocation is wasteful or unconfigured (e.g. torch imported, no .to(device); XGBoost without device='cuda')
✗ NO CAN DO 2 Nothing in this code can address the requested accelerator

Design constraint: the false-positive budget is ~zero (an advisor that interrupts wrongly gets disabled in a week). So verdicts are conservative:

  • BLOCK fires only on true incoherence: no GPU-capable library at all, a hard CUDA requirement in a non-CUDA environment, unguarded cuda placement on a CPU runtime, or a compute-capability generation mismatch.
  • A script that is one config line away from coherent (XGBoost, LightGBM, CatBoost, spaCy) gets ADVISE, never BLOCK.
  • numpy/scipy are treated as ancillary — present in everything, never the story — and can't independently drive a verdict.

Capability map

Hand-verified deterministic tier covering the common catastrophic cases: CPU-only libraries (scikit-learn, pandas, statsmodels, NLTK, gensim, Prophet…), conditionally-GPU libraries (XGBoost, LightGBM, CatBoost, spaCy), and native accelerator frameworks (PyTorch, TensorFlow, JAX, RAPIDS, transformers). Extend or override with --map your_map.json.

Intake: the constraint ledger (LEDGER.md)

The audit is only as good as the declared intent, so the package now fronts with a constraint-ledger protocol (LEDGER.md): goal, must-stay, must-not, and a disposability default stating that anything unlisted — including the entire current implementation — is negotiable. It prevents the failure mode where an assistant promotes your current attempt into a requirement.

Participation is optional by design. When no ledger is provided, inference mode applies: the auditor constructs a provisional ledger from evidence, tags every entry [inferred], and asks the single cheapest high-leverage ratification question before any expensive work. The declared and inferred ledgers are the same object at different confidence levels — participation buys speed, never access. (nocando already does this at the code layer: --runtime undeclared triggers autodetection.)

Roadmap (tier 2)

The deterministic tier handles "can it." The agent tier handles "should it":

  • workload sizing (dataset dims, params → rough FLOPs / VRAM estimate)
  • allocation options with time/energy tradeoffs ("your ask is X; options A/B/C")
  • syllabus/org aperture: audit a course's notebooks or a team's repo in batch
  • retrieval-grounded advisories synthesized from the distributed corpus, reserved for cases where being occasionally wrong is survivable
  • ledger-first sessions: intake (declared or inferred) -> coherence audit -> allocation options, in that order, always

Tests

tests/ contains the canonical fixtures:

  • tuesday_night.py — sklearn SVC + GridSearchCV on a declared T4 → BLOCK
  • torch_configured.py — torch with device placement → PASS
  • torch_forgot_device.py — torch, no device call → ADVISE
  • xgb_default.py — XGBoost with default (CPU) params → ADVISE
  • svm_demo.ipynb — notebook parsing incl. %magic/!shell stripping → BLOCK
  • cuda_on_cpu.py — unconditional .to("cuda") on a CPU runtime → BLOCK
  • guarded_cuda.py — cuda placement behind is_available() guard → PASS
  • flash_on_t4.py — flash-attn on a T4 (cc 7.5 < 8.0) → BLOCK; same file on A100 → PASS
  • bnb_on_mac.py — bitsandbytes on Apple Silicon (MPS) → BLOCK

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nocando-0.2.0.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nocando-0.2.0-py3-none-any.whl (12.3 kB view details)

Uploaded Python 3

File details

Details for the file nocando-0.2.0.tar.gz.

File metadata

  • Download URL: nocando-0.2.0.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for nocando-0.2.0.tar.gz
Algorithm Hash digest
SHA256 efa348519278896c06e40f6d43f6dd9f9e351c867de471fcd8fbdb44ac5f3113
MD5 983a2a086e7dad62139a2fb30203ba4e
BLAKE2b-256 09742bd70b9a53aee478ffa1427c521c0d69fd9ceef2f7c554326236ed8bfe21

See more details on using hashes here.

File details

Details for the file nocando-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: nocando-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 12.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for nocando-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1b54d834c9e89771296030541e362295ab5d6e554e994e6ac8f52fe18c695da3
MD5 b3b55c67b12783f0aa2031aca985e4f3
BLAKE2b-256 b6268da5b6b39aaa0dfb2c60ba0aadde62a4f8c21fc76f035a9af10fc0213e35

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page