This is a submission for Weekend Challenge: Passion Edition
There's a teaching in the Buddhist tradition about a finger pointing at the moon. I say "Hey, look at the moon!" and point upward β and you, instead, are distracted by my finger, and respond with critique about my finger. As with all spiritual parables, the meanings to be drawn are contextual and personal. Here is mine: I built a small tool called nocando (pip install nocando), and nocando is the finger. The moon is energy allocation.
Let me start with the finger, since that's what the dev challenge asks for.
nocando is a pre-flight environment-semantics linter for ML workloads. It answers one question before you occupy hardware: is the code you wrote coherent with the declared environment? 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. Now something does. This has been fomenting, churning and brewing... passion β desire...I spent a year in machine learning chasing my tail through undocumented mismatches: the constant expectation that I should have known something that is never given to me, anywhere, in any linear order. And this week I had enough of this for all of us because I know this is not unique to me, every time I look things up, I am met with some form of "yup... " as if acknowledgement makes the externalization acceptable. It doesn't. I
sat for three and a half hours on a Colab T4 at 0% utilization because, unbeknownst to me, scikit-learn for SVM is CPU-only. It has no CUDA backend. That fact is thoroughly documented, if you know to look for that. Buried in Stack threads and subreddits, indexed by symptom, findable only after you've already failed, because failure is what generates the search terms. Nothing says this up front. So I built a thing that says it up front. That T4 could have been someone else's, or simply not occupied.
Now the moon.
Notice what that wasted session actually was: not a worse model, not a slower result. Nothing. Heat. Eliminating it asks no one to sacrifice anything β nobody's workflow degrades, nobody is told to want less. Multiply one wasted Tuesday across every student, bootcamp cohort, and tutorial-follower hitting the same mismatch, and you get a large number composed entirely of moments nobody valued. No one watches the intersections. I do. Like a lint trap.
There is no shortage of accepted scholarly literature, across a wide berth of domains, laying out in detail how much resource there actually is β energy, water, compute. Our major malfunction is not one of needing more. It is, simply, allocation. Simple, not easy β that's a recovery slogan, and the implication is exact: recovery is not complicated, but our thinking makes it so. Repent means just this: turn around, turn back from your thinking. And this is what is not easy β unsticking from a way of thinking things should be. More is better. Better is better. Or: more is simply more, and better might only be relatively so, for a few, in the
short term.
I'll offer one anecdote about how sticky that thinking is. In my first "big data" graduate course, my distance-learning group and I had a divorce. One mitigating factor, in my perception, was an old, uninformed bias about what makes data "big." To them, big data had to meet some n threshold β never a complexity or quality one. Contemporary definitions freely state that complexity is absolutely a characteristic that can make data big; they were unable to accept this. Quantity was legible to them. Quality was not. Ultimately, we divorced. I share this because that bias is not confined to one group project β it's the same reflex driving the industry's fraught path of more energy needs for more data centers for
more data for more training for more models for more. I propose nothing novel at all. Allocation. We already use allocation in all sorts of systems, and fail to use it in all sorts of others, to our respective advantage and detriment. We do not need more. We simply need better.
A linter cannot fix an industry's thinking. A finger is not the moon.
But a finger that points at the exact line of your file, one second
before you burn the hardware, and says this will produce heat and
nothing else β here's the cheaper allocation β that's a small, tangible, working piece of the turn.
$ nocando train.py --runtime t4
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
nocando pre-flight audit β train.py
declared runtime: T4 (accelerator)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
VERDICT: β NO CAN DO
[BLOCK] scikit-learn (line 11: `clf = GridSearchCV(SVC(...`):
scikit-learn executes on CPU only. It has no CUDA backend
and will not touch a GPU regardless of runtime. Heavy
CPU-bound calls found: SVC, GridSearchCV. These will run
entirely on CPU while the T4 idles at ~0% utilization.
β³ NVIDIA cuML (RAPIDS) is a drop-in GPU replacement, or
switch to a CPU runtime (often faster AND free).
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
It reads both directions β here it catches the opposite mismatch, plus an
environment that contradicts itself:
$ nocando environment.yml
[advise] contradictory pin: numpy (line 6: `- numpy=1.26.4` and
line 9: `- numpy==2.1.0`): pinned to different major
versions in this artifact. Whichever installs last
silently wins or the resolver fails outright.
And when the deterministic core hits its own honest limits, it can hand
what it learned to a language model β clearly labeled as advisory:
$ nocando frankenstein_project.py --runtime t4 --agent
...deterministic report first, including:
unscanned (recognized, no rule exists yet): some_obscure_lab_package
β absence of a warning above means 'no rule fired,'
not 'verified compatible.'
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ADVISORY (Gemini) β NOT part of the deterministic verdict above.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
...Gemini answers only the open questions the core refused to
guess at, instructed to mark its guesses as guesses.
Try it yourself in ten seconds β no launch, no deploy, nothing to
configure. pip install nocando
, then point it at any script, notebook,
environment.yml
, or even a PDF assignment handout you already have. It
reads your file, prints a report, exits. Exit codes (0/1/2) drop straight
into CI and pre-commit hooks.
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).
PyPI: https://pypi.org/project/nocando/
Pure-Python static analysis β deliberately zero LLM calls, zero telemetry, stdlib only in the core. A pre-flight check you can't trust
Three audit dimensions, each born from a real failure of mine:
Runtime coherence β CPU-only workloads pointed at GPUs;
unconditional .cuda()
calls headed for CPU runtimes (which crash at
minute 40, right after the data prep you already waited through); and
hardware-generation traps like flash-attn on a T4 (needs compute
capability β₯ 8.0; a T4 is 7.5 β a constraint that lives nowhere a
beginner would ever look).
Environment-manager coherence β conda + pip install-order
corruption (conda's own docs bury "conda first, pip last" three
paragraphs deep in a blog post nobody reads until their environment is
already dead), and the notebook !pip
vs %pip
trap, where an
install "succeeds" into a different Python than your kernel.
Ingestion honesty β for Frankenstein code mixing libraries it has
never seen together, nocando explicitly reports every
recognized-but-unscanned library, so silence is never mistaken for
"verified compatible." It flags self-contradictory version pins
because that check is pure logic and can never go stale β the tool
refuses to hardcode a compatibility phonebook that would start
decaying the day it was written.
It reads Python, R (Colab serves both kernels β same trap, different
tongue), notebooks, conda manifests, and prose: feed it the assignment
PDF before any code exists and it audits the workload the document is
designed to produce. Every finding names its location and quotes the
offending line β (line 11: ...)
for scripts, (cell 3: ...)
for
notebooks, because Colab shows you cells, not line counts.
49 tests, and the fixtures are real: my actual graduate coursework, fed
through cold. One of those specimens revealed that the tool itself had
shipped with an unexamined assumption β "ML means Python" β until my own
R coursework caught my own linter doing the exact thing it was built to
detect. That finding is preserved in the repo's lineage docs on purpose.
Nobody is exempt from the audit, including the auditor.
But a deterministic core has a horizon, and the tool is honest about
where it sits: "support vector machine" written in words instead of
SVC()
, an unrecognized lab package nobody has mapped, a training task
described entirely in prose. The core refuses to guess at these β so I
built the layer where guessing is allowed to live, clearly labeled.
nocando --handoff
packages the full report plus its open questions
into a prompt you can paste into any assistant.nocando --agent
goes one step further: it sends that same prompt to Gemini in a single API call and prints the response under an ADVISORY banner β commentary on the report, never part of it. The invariant is tested, not aspirational: neither flag can alter a finding, a verdict, or an exit code. Gemini answers only the questions the deterministic core explicitly could not, and is instructed to mark its guesses as guesses.
That's what I think meaningful AI integration looks like: not a model in the loop, but a model at the boundary β consulted exactly where determinism ends, and not one line before. Nothing is good or bad, it is our relationship with it. Probabilistic AI can be awesome. The right tool for the right job, in the right way. It's like going to the hardware store for bread. Making this tool covers a lot of unknowable ground. It can't be a look up table. Updates, and software versions change every day. The entire computing landscape is constantly in flux. If this were purely agentic it would be an energy suck. The question is/was; where in here should determinism and agentic forces best interweave so that like, any relationship, they work better together.
Certified by Ted (stoop tabby, QA). -->
<!nocando's --agent flag sends the
deterministic audit's unresolved questions to Gemini
(google-genai, one generate_content call, model configurable via
GEMINI_MODEL). The integration is deliberately narrow: the
deterministic report is the authority; Gemini is the consultant for the
ambiguities the core refuses to guess at β unscanned libraries,
framework-unconfirmed prose, allocation alternatives. Advisory only,
invariant-tested, degrades gracefully without a key.-->