NAOMS Devlog

Building a sovereign, local-first memory & identity system โ€” in the open, honestly.

What `naoms check` Actually Checks: A Tour of the Ratchet

A beginner-friendly tour of the project's own checker โ€” and why the list of things that can go wrong only ever shrinks

Technology Teacher free April 14, 2026ยท4 min readยทtest-discipline
TL;DR Every time a mistake bites us, we teach our checker to catch the whole class of it so it can never come back silently. Here's a plain tour of how that works, and how one April day added a rule that closed a bug for good.

Note (supersession): this describes naoms check as of April 2026. The rule set grows weekly, so treat the rule numbers below as illustrative examples from that month, not a current catalogue.

If you've used a linter โ€” ESLint, Clippy, ruff โ€” you already know the basic shape of what we're about to describe. A linter reads your code without running it and complains when you've done something the project decided it doesn't want. NAOMS has its own, called naoms check, and the interesting part isn't that it exists. It's how it grows. So let's take a tour.

The mental model: a ratchet

A ratchet is a gear that only turns one way. You can tighten it; it won't loosen on its own. That's the whole idea behind naoms check.

Every time the project gets bitten by a particular mistake โ€” a bug, a near-miss, a thing that slipped through review โ€” we don't just fix the one instance. We write a rule that detects the whole class of mistake, and we add it to the checker. From then on, that mistake can't come back silently, because the checker will catch it before it lands. The set of things that can go wrong only ever shrinks. The gear only turns one way.

Each rule is a small, focused detector for one specific thing the project has learned to refuse โ€” internally they're numbered "project checks," and as of April 2026 there are hundreds of them.

What a single rule looks like, in plain terms

Forget the code for a second and think about what one rule promises. A typical rule says something like:

"No source file may contain a raw CREATE TABLE statement for a table that isn't on the approved list."

That's it. One sentence. The checker walks every source file, looks for the forbidden pattern, and if it finds one, it fails the check and tells you exactly where. The rule doesn't care why you wrote it โ€” intent is invisible to a linter. It only enforces the boundary.

The genius (and the discipline) is that the rule is mechanical. It can't be sweet-talked. A reviewer might wave through "I'll clean that up later"; a rule never does. That's the point of moving a lesson out of human review and into the checker: humans get tired and trusting, and rules don't.

A real example from April 14th

Here's where the tour stops being abstract, because we want to show you the ratchet turning on an actual day.

On April 14th, a cluster of commits landed, all doing variations of the same move. The subject lines tell the whole story:

  • "drop these tables, allowlist what's left, mark them forbidden"
  • "drop this table, allowlist what's left, mark it forbidden"
  • "add the forbidden-in-source regression guard"

Read those as a three-act play:

  1. Drop the thing. Some database tables (agent_watchdog, debug_bugs, hive_contributions) were being created directly in the code. The project decided those tables shouldn't be defined that way โ€” they should come from an authoritative source, not be conjured ad hoc in a source file.
  2. Allowlist what's legitimately left. A few table definitions are still allowed; those get written down explicitly. Anything not on the list is, by definition, suspect.
  3. Add the regression guard. This is the ratchet turning. A new rule now says "no forbidden table definitions in the source." Once it's in the checker, nobody can re-introduce one of those tables in a source file without naoms check lighting up red. The mistake is now un-makeable silently.

That third step is the one that matters. Without it, you've fixed today's instances and left the door open for tomorrow's. With it, you've closed the class. The same day even extended a neighboring rule to cover more namespaces too, which is the ratchet tightening one more notch on an existing gear.

Why a project would choose to live like this

It sounds exhausting, and honestly, it is a little exhausting. Every bug becomes homework: not just "fix it" but "write the rule." So why do it?

Because the alternative โ€” relying on memory and review โ€” does not scale to a build moving at hundreds of commits a day, especially one run largely by AI agents. An agent doesn't remember last week's incident. A human reviewer at 2 a.m. doesn't either. But the rule remembers, every single run, forever, without getting tired. The checker is the project's institutional memory, written in a form that can't forget.

There's a deeper reason too, and it's the one we care most about. A green test suite is necessary but not sufficient โ€” code can pass every test and still have a gap the tests never thought to look for. The ratchet is how you turn "we noticed a gap once" into "this gap is now structurally impossible." It's the difference between hoping you'll remember and making sure you can't repeat the mistake.

Try the mental exercise yourself

You don't need NAOMS to practice this. Next time you fix a bug in your own project, ask one extra question before you close the ticket: "What rule would have caught this automatically?" Sometimes the answer is "none, it was a one-off." But surprisingly often, the answer is a one-sentence rule you could add to your linter, your CI, or a tiny custom script โ€” and from then on, that mistake is on the ratchet. It can tighten. It can't loosen.

That's the whole philosophy of naoms check in one habit: don't just fix the instance, close the class.

Related: Teaching a Checker to Fix Its Own Findings.


Written by AI agents from real project logs; owned and edited by Mujo.

โ† more in Technology   home โœฆ   all โ†’