GRAIN 1.2 is out, and it finally checks itself
by APERTURESyndicate · September 5, 2026
So here's the problem with coding standards: everyone agrees to them in the meeting, and then six months later half the codebase has quietly drifted away from them anyway, because checking was never actually anyone's job. That's the thing GRAIN 1.2 fixes. It doesn't change a single rule from 1.1 — same 33 verbs, same "a number needs a unit" rule, same five comment tags. What changes is that you no longer have to trust anyone's memory, yours included, to keep them. The checker does that part now.
And honestly, most of this already existed — it just wasn't connected to anything. There was an ESLint plugin sitting in the repo with all seventeen naming and shape rules written out, and it never got wired into the actual build. It just sat there looking correct while the code around it drifted. So with 1.2 the checker stopped caring whether that plugin was configured anywhere and started running every rule itself, straight up, regardless of your editor. While it was in there, it picked up Kotlin and Swift too, so the Android and iOS shells of Resonance now follow the same rules TypeScript already did.
First question everyone asks: does this mean going back and fixing years of old code? No. Every violation already sitting in the repo — all 45,711 of them — got counted once, written down as the starting line, and left alone. The gate only fails on something new. A function you wrote last year keeps doing exactly what it did yesterday. A function you write today just doesn't get to hide behind "well, the old code does it too."
Here's what that actually looks like on a real handler, not a made-up one. This:
function handleTrackData(data) {
const timeout = 900
// increment counter
const flag = data.views > 0
}becomes this:
function publishTrack(draft) {
const refreshTtlSec = 900
// why: races the worker otherwise
const hasViews = draft.viewCount > 0
}Same logic, nothing rewritten from scratch — the name now says what happens, the number carries its unit, and the comment explains why instead of repeating what the line already says.
The rest of what actually shipped in 1.2, if you're curious:
The checker runs its own AST rules now — it used to lean on that unconnected ESLint plugin, now it doesn't need one at all.
Kotlin and Swift are covered, not just TypeScript — 184 files of the Android shell alone.
SYNX config files get checked too, the same way source code does.
An event name has to read as something that already happened —
v1.invoice.paid, neverv1.payInvoice.There's a --stat flag now that just tells you which service is closest to clean, if you're into that kind of thing.
If you want the full version — all 33 verbs, why handle and process are banned, how the gate decides what actually counts as "new" — it's all at docs.aperturesyndicate.com/en/grain. If not, that's the whole update, really.



