— Optimisation
Configure optimisation constraints from natural language
Roy Chikballapur
The appeal is obvious. A planner says what they want, the system encodes it, nobody writes a ticket. The reason it usually is not offered is that a wrong constraint is expensive in a way a wrong search result is not: it silently changes what work gets scheduled, and no one notices until the pattern shows up in a month of overrides.
Here is what makes it safe enough to use.
The read-back is the contract
The sentence a planner types is not the artefact. “Don’t send juniors to the substations on their own” carries at least three assumptions: what counts as a junior, what counts as a substation, whether “on their own” means unaccompanied by anyone or unaccompanied by a qualified person.
The system compiles the sentence, then renders the result back as structured English, when this, if these, then that, never this, with every assumption stated as a question. “I have taken ‘junior’ to mean anyone without the HV authorisation on file. Correct?” The planner approves the read-back. The sentence they typed is discarded; the read-back is what runs.
Grounding, and refusing to guess
Every object the rule mentions must resolve against real things in the tenant: real queues, real maintenance plans, real certification types, real locations. A reference that does not resolve becomes a question, never a best guess. A rule that silently invents a queue is a rule that never fires and nobody notices.
The compiler also has to be honest about its own limits. If the request needs a predicate the rule vocabulary cannot express, it says which part is unsupported rather than approximating. Approximation is the failure mode that destroys trust, because the rule looks accepted and behaves differently.
The backtest is the activation gate
Before a rule is switched on, replay it against the operation’s own history, twelve months by default. Report the firing count, list every instance with a link to the historical context, and render what it would have done without persisting anything.
Two warnings matter. A rule that would never have fired is usually a modelling error: conditions that cannot co-occur. A rule that would have fired four hundred times is usually a scope error. Both are cheap to catch here and expensive to catch in production.
Activating without reading the backtest should be possible and recorded as such. Accountability rather than paternalism; planners have bad Tuesdays too.
What must be refused outright
Some rules should be structurally impossible to author, not merely discouraged. A rule may not grant external execution rights on a safety or statutory step. A rule may not bypass a signature requirement. A rule may not lower a statutory minimum interval, whatever the evidence suggests. These are enforced at the gateway, and such a request is refused with the reason rather than quietly declined.
What stays in code
Natural language is right for operational policy: routing, thresholds, notifications, competency requirements, preferences. It is wrong for the core scheduling model, the entities, the variables, the shape of the problem, which is engineering, changes rarely, and should be versioned like the code it is.
Keeping that line is what makes the rest safe. The planner authors policy against a model they cannot accidentally break.
Versioning
Every rule change is a version with an author, a date, a description and one-step rollback. When a schedule starts behaving oddly, the first question is what changed, and the answer needs to be a list rather than an investigation.
We are building this in Facterra against a workflow engine that has stored rules as declarative data since 2017, which is what makes them a compilation target rather than code. If you are running a solver-based application where every rule change is a development ticket, this is the part worth fixing first, whichever engine you settle on.