Every dataset that has ever been worth anything started life as a series of small, careful decisions about what should and should not be allowed in. The decisions are usually invisible. They show up as a placeholder in a form, a regex in a controller, a dropdown that quietly removed an option somebody else needed. They live wherever the developer last touched.

This works fine on day one. It begins to fail on day six hundred, when the same field exists on three different forms, two import pipelines, and a public API — and each of them has a slightly different idea of what valid means. By the time anyone notices, the database is full of values that are technically allowed in some places and rejected in others, and the only person who could have explained why has moved teams.

This is the story we wanted to stop telling about asset data inside the Oestler platform. The answer we shipped is the validation register: a single, project-scoped catalogue where every validation rule lives once, applies wherever it's needed, and enforces itself the moment a user types a character.

Rules as First-Class Objects

The core decision was to treat validation rules as data, not as code. Each rule is a record in the project. It has a title, a kind, an error message, and — critically — a list of targets: the fields the rule applies to.

A target is a stable identifier for a piece of data. The asset ID itself is a target. Each attribute defined in the project is a target. A single rule can list one target or many. The same regex that enforces the format of a primary asset ID can be reused, in the same record, to enforce the format of a related-equipment ID, a parent-asset reference, and a hand-written tag — without copying the rule three times and without rewriting the controller.

The validation register is a registry of intent. It is the answer to the question, "What does this project consider valid?", in a form that any team member can read and any module of the platform can consult.

This shape unlocks several things at once. It makes rules discoverable. It makes them auditable — you can look at the register and see exactly which fields are protected and which aren't. It makes them removable, with full understanding of the blast radius before you press the button. And because the rules are shared across every part of the platform that touches their targets, it eliminates the class of bug where a value was rejected on one screen and quietly accepted on another.

Two Primitives, Carefully Chosen

There are two kinds of rule in the register today: regex and unique.

Regex covers the entire surface of string-shape validation. Format checks, length constraints, enumerations, prefix and suffix requirements — anything that can be expressed as "this value, when matched against this pattern, must succeed" is a regex rule. The fact that regex is famously hostile to non-developers used to be an objection to this design; with the AI authoring layer we shipped at the same time, it has become a feature. (We wrote separately about how the AI authoring layer changes the economics of regex.)

Unique is the second primitive, and it doesn't reduce to regex. A uniqueness rule says: no two assets in this project may share the same value for this target. Regex can describe what a single value should look like; only a project-scoped query can know whether the value has already been claimed.

Two primitives are enough. A third — conditional or cross-field validation — is occasionally requested, and we think it almost always reduces to a different schema. If a rule should only apply to certain assets, the right answer is usually to define a more specific attribute and apply the rule there, rather than entangle two attributes inside a single conditional check. Keeping the primitive set small keeps the register honest.

Enforcement at the Input, Not the Database

Validation that only fires at save time is a poor user experience. People type a value, click save, and discover several seconds later that they were wrong about something they could have known the first character. The friction accumulates, especially on mobile, and trains users to ignore the very feedback the system is trying to give them.

The Oestler validation register enforces in three layers, each with a different tempo:

  1. At the field, while typing. Every input that has at least one applicable rule shows a small status indicator next to the input. As the user types, regex rules check synchronously and a tick or cross appears immediately. Uniqueness rules check asynchronously, debounced, against the project — typing "P-1042" and discovering halfway through your sentence that another asset already owns that ID flips the indicator red and disables the save button before you've reached for it.
  2. At the field, before save. The save action is gated on the live status. If a rule is failing or if a uniqueness check is still in flight, the button is disabled. The user can never accidentally submit a value the system already knows is invalid.
  3. Defence in depth. Even when the live indicator says the value is fine, every save runs the full validation pipeline one more time on the way to the database. This catches the rare case where another user has just claimed a unique value during the few hundred milliseconds the editor was open. The result is failure-soft: the save is rejected, the user is told why, the bad data never lands.

Rule Hints: Discoverable Constraints

The other half of good validation UX is making the rules visible to the person being judged by them. We've all met forms that reject our input with a curt "invalid format" and no further explanation. Users learn to fear those forms.

Every input that has applicable rules now displays a small information button beside its label. Hover or tap it and you get a list of every rule that governs the field: its title, its kind, its user-facing error message, and the underlying pattern for the technically curious. The constraint stops being a trap and starts being a brief.

This is particularly important on field-edit screens, where a user might be editing an attribute they didn't define. The information button means they don't have to ask the project lead what the rule is or what valid looks like. The system tells them.

Deletion With Consequences Made Visible

Because rules can apply to many fields, deleting a rule can have consequences that extend well beyond the moment of deletion. We made this explicit. Every rule row in the register has a delete affordance, and every delete prompts a confirmation that lists, by name, the fields the rule was protecting:

"This rule currently enforces: Asset ID, Equipment Tag, Spare Part Code. Deleting it will stop validation on these fields."

Bulk deletion uses the same pattern, with the addition of a small math challenge to slow the user down — a deliberate piece of friction in proportion to the irreversibility of the action. Validation rules are not the kind of thing one should remove by accident.

Project-Scoped, by Design

Every rule lives inside the project that owns it. The register is not a global library, and rules are not shared across projects unless an administrator deliberately copies them. This is intentional. Two construction programs run by the same firm in two different cities will, almost certainly, have different conventions for asset numbering, different equipment classifications, different acceptable abbreviations. Forcing them to share a single rule set produces friction at the boundary and resentment at the centre.

What the register guarantees is consistency within a project. Every form that touches an attribute consults the same rules. Every save runs through the same enforcement pipeline. Every user sees the same constraints with the same error messages. The project becomes the unit of truth, which is exactly the unit at which most engineering organisations actually operate.

What This Looks Like in Practice

A typical setup begins with the small set of rules that are seeded automatically when a project is created — most importantly, the format rule for asset IDs. From there, the project lead opens the register and adds rules as conventions emerge. A regex for the equipment numbering scheme. A uniqueness constraint on the inspection report number. A regex for the contractor reference field, applied to three related attributes at once.

The register grows. Existing data is not retroactively rewritten, but every new write is checked. Within a few weeks, the project's data is provably consistent against a documented set of rules, and the documentation is the rules.

That last sentence is, in our view, the entire point. The validation register is not a feature, exactly. It's a way of making the project's data conventions self-describing, self-enforcing, and visible — so that the next person to inherit the project, or audit it, or hand it over, doesn't have to start by guessing.

The validation register is available now in every Oestler project. Open the validation tab from the side rail to see the rules currently in force, or to add your own.