Quality & how we work
Rules that live in prose get broken. The ones here fail your build before you can commit them — a script that runs inside the ordinary check command, on a laptop, before anything reaches CI. Most of this project's engineering discipline is one habit: when a defect can recur silently, write the rule instead of the note.
Rules that fail the build
A rule is a function in one script. It gets a name, a comment arguing why it exists, and a place in the check every developer runs before committing — not a step in a CI file, because a rule that only fires on push is a rule you discover after you have already written the code the wrong way.
The kinds of thing they catch:
- Runtime traps the tests cannot see. The mobile JavaScript engine lacks APIs that Node provides, so a test suite can pass on code that would crash on a phone. A rule refuses those APIs in the app's source outright.
- Conventions that had drifted for months. "Screens compose the component library" was written down long before anything checked it; by the time a rule did, the screen tree held 32 violations. It shipped ratcheted at 32 and was driven to zero, and the allowlist was deleted.
- Untranslated user-facing text, including screen-reader labels — text somebody reads even though nobody sees it.
- Documents that must not be committed, checked against what git actually
tracks rather than what an ignore file claims, because an ignore is one
git add -faway from being bypassed and the damage needs a history rewrite to undo.
A rule ships with a self-test. The newer ones exercise their own predicate on fixtures every time they run and fail loudly if they stop catching what they exist for. A guard nobody has ever seen fail is a guard nobody knows still works, and a predicate is exactly the kind of thing that quietly stops matching when someone tidies it up.
The count of rules is deliberately not published here. It changes, and a number in prose beside a list that grows is a fact with an expiry date. This project has made that mistake in its own internal documents — one file claimed nine rules for four rules too long — and the fix was to delete the count, not to maintain it.
The size ratchet
Source files stay under 500 lines. The files that were already over it when the rule arrived are pinned at their exact length in a list, and the guard fails if any of them grows. They can only shrink, and an entry is deleted when its file drops under the limit.
The mechanism matters more than the limit: a ratchet converts "we should clean this up" into "this cannot get worse", which is the only form of that intention that survives a busy week. It also cannot be escaped by adding a file to the list, because that is precisely what the rule exists to prevent.
The same file list is what the formatter is told to leave alone, and a separate rule asserts the two lists are identical — so reformatting a pinned file cannot silently change its line count and break the ratchet three commits later.
Suites that run against a real database
The row-level security suites connect to an actual Postgres, create real users, and try real attacks across every owner-scoped table. They are described, with their own code quoted, on Security.
Two things about them belong here rather than there. They cannot be pointed at anything but a local database — every client passes a guard that throws unless the host is local, because a destructive two-user matrix aimed at the wrong place must fail loudly rather than quietly succeed. And when they are switched off, they print one loud line saying so; a skipped suite that looks like a passing suite is worse than no suite.
Both languages, in step
Romanian is the source language and English mirrors it. A parity suite fails when a key exists in one and not the other, so a half-translated release cannot ship — the failure arrives at the moment the key is added, which is the only moment it is cheap to fix.
The device flow pack
A set of scripted flows drives the real app on a real phone. They run by hand, which is a weakness and is named as one below.
What is mechanical is narrower and worth having: every element id a flow taps must exist in the app's source, checked on every run. That closes a specific failure this project actually had — a flow tapped an id that a refactor had renamed months earlier, and the pack had been failing ever since without anyone knowing, because nothing ran it automatically.
The lesson recorded at the time is narrower than "run it in CI": a check that only runs when a human remembers is a check that reports the state of the world on the last day somebody remembered.
How we work
Two claims here are about practice rather than about code. Neither can be checked by an outside reader, and neither is dressed up as if it could.
Sprints end with a written retrospective, including what went wrong. One of them records that a test pack had been failing for weeks unnoticed, that an internal document claimed a fix was "proven on device" when the same page said it had not been investigated, and that the plan for the sprint misclassified a control as non-interactive when it was tappable. That is what a retrospective is for, and a polished one would be no use to anybody.
Releases are smoked on a device against a checklist, in the order you walk the app.
Whether the habit holds every single time is not something an outside reader can verify. Here you are taking our word for it, and it is worth knowing exactly where.
Further reading
- Architecture — the design these rules protect, and the decisions that went badly.
- Security — the authorisation model and the suites that prove it.