A few months into our first aquaculture deployment, a farmer called the support line and asked us to "stop the app from lying about his pond". The dissolved-oxygen sensor was reading 3.4 mg/L, his alert had fired, and the farmer — who had spent thirty years on that pond — was certain it was fine. He had stuck his hand in. He had watched his fish. He had decided, quietly and without us, that our app didn't know what it was talking about.
The sensor was correct. The threshold was wrong. But that's not actually the lesson. The lesson is that a threshold isn't a number — it is a contract with the operator about when the system gets to interrupt them. And like every contract, the moment one side breaks it, the trust takes years to rebuild.
This post is the companion to my earlier piece on alert fatigue. That post was about how alerts behave once they're firing. This one is about the thing that decides whether they fire in the first place: the threshold itself, and the design choices that decide whether your operators trust it.
Three ways a threshold breaks trust
Most threshold problems are not "the value is wrong". They're one of three more interesting failures, and the design response is different for each.
Too tight, in the wrong direction. The classic. The threshold is set to a textbook value that ignores the realities of the site — a cold-storage chamber that defrosts on a known cycle, a greenhouse that rises 6°C every afternoon in summer, a pond that dips below 4 mg/L every dawn. The system is correct on paper and useless in practice. The operator silences the app or, more dangerously, learns to ignore it.
Too loose, in a way that hides real problems. The opposite mistake. After enough complaints about noise, someone pushes the limit out — sometimes by a lot, sometimes "for now" — and the system stops catching the events that actually matter. This is the version that ends in a phone call from a regulator, or worse, an angry customer.
Mysteriously changing without telling anyone. This is the trust-killer. The operator memorises the limit, the limit moves, no one explains why, and now every alert feels arbitrary. I've seen this destroy entire deployments. The threshold can be perfectly correct; if the operator can't predict when it will fire, they will not act on it.
The first move in designing for trust is to take all three failure modes seriously, because the operator does — even when they can't articulate which one is happening.
Three kinds of thresholds, not one
Almost every agritech and aquatech product I've worked on ends up with three distinct categories of threshold living inside it, and treating them as one type is a recipe for a confusing UI and a brittle alerting layer.
Operational thresholds are the day-to-day ones the operator is allowed to negotiate. Pond DO, chamber temperature, soil moisture, AC setpoint. The farmer or the facility manager has earned the right to tune these. Their judgement is local — they know their pond, their crop, their region. Your job is to give them a safe envelope to tune within, not to lock them out.
Regulatory thresholds are the ones the operator is not allowed to negotiate, because someone external — a food safety auditor, a pharmaceutical regulator, a contract buyer — is going to ask whether the asset stayed within them. The system can show these alongside the operational thresholds, but they are never user-editable in the field, and breaches are logged immutably. Operators almost never push back on this once you explain why; they push back when you confuse it with the operational tier.
Informational thresholds are the ones the system uses to flag oddities for itself. They never reach the operator as alerts. Sensor drift, unusual variance, missing data, gateway lag. They go into a quieter pane the team uses for debugging, and they should be aggressively tuned because their only audience is people who already work on the system.
Most products mix all three on the same screen and call it "Alert Settings". That single decision is responsible for a surprising amount of the trust problems I've seen, because it makes operational tuning feel risky ("am I going to break the regulator's audit?") and it makes informational noise look like operational noise.
Defaults are a recommendation, not a verdict
A threshold the system shipped with should never be presented to the farmer as the right answer. It is, at best, a starting recommendation from a team that has not seen this specific pond, this specific chamber, this specific shed. Phrasing matters: a default of 4.5 mg/L for dissolved oxygen is our recommendation for ponds in this region, not the limit.
Two practical patterns from this:
The first is to ship every operational threshold as a band, not a line. A pond's healthy DO is roughly 4–7 mg/L; below 4 is concerning, above 7 is unusual but not dangerous. A chamber's safe range is, say, −22°C to −18°C. Bands let the operator visualise the room they have to operate within, and they make the alert phrasing far more honest: "DO has dropped below the warning band" reads very differently from "DO is below 4.5".
The second is to present the origin of every threshold inline. If the value came from a regulator, say so. If it came from your team's recommendation, say so. If the operator changed it themselves last Tuesday, say that. A threshold field that quietly mutates over weeks without history is the surest way to make the operator feel manipulated.
Let the operator negotiate, and require them to explain
Operational thresholds should be editable, but the act of editing should leave a trace. The pattern that works in practice has three pieces.
First, a soft envelope around the default. The farmer can move the threshold within a range the system considers safe (say, ±20% of the recommendation) without ceremony. Move it by 10%, no fuss. This is the daily-use case.
Second, a hard boundary that requires a reason. Beyond the soft envelope, the system asks: what's happening that makes you want to set this? A short text field — "fish are at maturity, oxygen demand higher" — is not red tape. It's the conversation that turns a config change into a piece of operating knowledge. Two months later, when someone else inherits the pond, that note is the only artefact that explains the unusual setting.
Third, a regulatory ceiling that the operator simply cannot cross. No reason field, no override flow, just a polite refusal: "this value would breach the storage SLA agreed with your buyer." The operator stops, calls their manager, and the right conversation happens in the right channel — outside the app.
I've watched teams resist the reason field because it feels like friction. It is friction, and that friction is what gives the system a memory. Without it, the threshold history is a list of timestamps with no plot.
Treat threshold history as first-class data
If the operator can change a threshold, the system needs to behave as if those changes are operational events worth keeping. Every revision should record who, when, from what, to what, why, and through which screen or API. That timeline should be visible next to the live reading, not buried in an admin panel.
Two reasons. The first is debuggability: when an alert behaves oddly, the first question is almost always "did the threshold change recently?", and you do not want to answer that question via a database query at 11pm. The second is trust: showing the farmer their own history of edits, in their own words, is one of the strongest legitimacy signals an alerting system can offer. It is their threshold. They wrote the reason. They watched it work. The contract is theirs to defend.
This also feeds back into the alerting pipeline cleanly. A threshold change should appear as a low-severity Info event in the same timeline as the alerts it shapes — exactly the kind of event the alert fatigue framework treats as auditable but not pageable. Operators don't need a notification when a threshold moves; they need to be able to find it.
Watch for thresholds that no longer match the world
Sites change. Seasons change. A pond that was healthy at 4.5 mg/L last winter may be dangerously low at the same value next summer because the stocking density has tripled. A chamber's normal operating temperature drifts as a compressor ages.
A small but powerful pattern: every six weeks or so, surface a threshold review prompt for any operator-set value where the alert distribution has shifted significantly from when the threshold was set. Not a notification — a quiet card on the dashboard. "This threshold has fired 12× more often this month than it did when you set it. Is that what you expected?" Sometimes the answer is yes; the world has changed and the threshold is doing its job. Sometimes the answer is "huh, I'd forgotten about that," and the operator opens the editor.
This is the trust loop. The system noticed something. The operator decides what to do about it. The system records the outcome. Next time, both parties know each other a little better.
The short version
If a team asked me for a five-bullet summary:
- A threshold is a contract with the operator about when the system gets to interrupt them. Treat it as a product surface, not a config value.
- Operational, regulatory, informational — three categories with different rules. Don't mix them on one screen.
- Ship defaults as recommendations inside bands, with their origin always visible.
- Allow negotiation inside a soft envelope, require a reason at the edge, refuse at the regulatory ceiling.
- Make the threshold's history first-class. The operator's own edits are the strongest legitimacy signal you have.
The farmer who told us our app was lying didn't need a smarter sensor. He needed to feel like the threshold belonged to him. Once we let him own it, the alerts started working again — for the rest of the deployment, and for every farm we onboarded after.