When I first built the Groundwise engine for the Ridewise app, it answered one question: is it too wet to ride? Low wetness meant good conditions. High wetness meant stay home. Exactly what I needed for mountain biking, skateboarding, and other outdoor wheeled activities where surface conditions impacted by weather mattered.
Then I started thinking about my garden.
I have raised beds, a few containers on the patio, and a lawn that I'd like to keep alive without drowning it. I don't get obsessive about it, and to be honest my lawn is far from impressive. I'm not one of those people who try to maintain golf course grass, far from it. But I've still regularly done that assessment where I look at the sky, vaguely remember whether it rained, and make the same kind of gut call on watering that I used to make about trails. The variables were familiar: recent rain, temperature, sun exposure, how fast things dry. I was running the same mental model, just asking the opposite question.
That realization is what turned one app into three. If the engine could quantify moisture on a surface, it could answer both "is it too wet to ride?" and "is it too dry, should I water?"
The Inversion
The engine always calculates a wetness score from 0 (bone dry) to 1 (saturated). The EngineMode enum controls what that score means:
Wetness concern (Ridewise, Fieldwise): Low wetness = Yes (go ride or play). High wetness = No (too wet).
Dryness concern (Yardwise): Low wetness = Yes (water today). High wetness = No (skip watering).
The verdict is the same enum, Yes, Maybe, No, but the interpretation flips. This means the consuming app doesn't need to know which mode produced the result. It renders green for Yes, orange for Maybe, red for No, regardless.
The thresholds shift too:
| Yes | Maybe | No | |
|---|---|---|---|
| Wetness concern | < 0.30 | 0.30 – 0.60 | ≥ 0.60 |
| Dryness concern | < 0.15 | 0.15 – 0.45 | ≥ 0.45 |
Yardwise thresholds are lower because the stakes are asymmetric. This wasn't immediately obvious until testing early versions of the app, when I realized that missing a watering day rarely if ever harms established plants. Riding a muddy trail damages the surface. So Yardwise is more lenient than the other apps, and leans toward "maybe check the soil" rather than "definitely water" — this makes the verdict less alarming. The reality is that the cost of a false positive (unnecessary watering) is real (overwatering causes its own problems), while the cost of a false negative (skipping one day) is usually trivial.
Manual Watering: Tracking What the Weather Doesn't Know
Here's where Yardwise diverges from Ridewise and Fieldwise most sharply. The weather API knows about rain. It doesn't know that you ran the sprinkler for 20 minutes yesterday evening.
Yardwise lets users log manual watering events with timestamps. The engine converts these into precipitation equivalents that then get added to the rain score alongside actual precipitation, with the same time-weighted decay:
0-24 hours ago: 0.7x weight (70% contribution)
24-48 hours ago: 0.2x weight
48-72 hours ago: 0.1x weight
A watering yesterday contributes about 0.175 inches to the effective precipitation (0.25 × 0.7). That's enough to shift a borderline "water today" verdict to "check soil" or even "skip."
The decay is important. A watering three days ago shouldn't prevent the engine from recommending water today, the moisture is long gone, especially in containers with fast-draining potting mix. The time-weighted model handles this naturally.
Cold Weather Extends Watering Memory
One wrinkle: cold weather slows evapotranspiration. A watering event that would normally decay in 48 hours can remain relevant for up to 96 hours during cold weather. The engine extends the effective window based on the same cold factor used for dormancy:
wateringWindow = 48 + 48 × coldFactor
At 34°F, the cold factor is about 0.62, giving a window of roughly 78 hours. At 45°F, it's about 56 hours. This prevents the engine from recommending watering when yesterday's water is still sitting in cold, slowly-evaporating soil. Keep in mind that winter watering is pretty rare, reserved almost exclusively for new plantings (trees, shrubs, etc.) and only during an unusual dry spell.
Establishment Sensitivity: Protecting Young Plants
Newly seeded lawns and recently transplanted plants need more water than established ones, and they're far more susceptible to drought. The engine handles this through an establishment sensitivity boost that layers on top of the surface type's base damage sensitivity.
| Establishment | Sensitivity Boost |
|---|---|
| Established | +0.0 (default) |
| Newly planted | +0.2 |
| Newly seeded | +0.5 |
This boost affects the sensitivity veto, the mechanism that pushes borderline verdicts toward protection. With a newly seeded lawn (base sensitivity 0.4 + boost 0.5 = 0.9 effective sensitivity), a Maybe verdict with wetness below 0.3 gets overridden to Yes: water those seeds.
For established plants with no boost, the same borderline conditions stay as Maybe: check the soil yourself. The engine doesn't push you to water unless there's a fragile surface that genuinely needs protection.
This is the same sensitivity veto that Fieldwise uses to protect natural grass athletic fields from being played on when borderline wet. Same mechanism, opposite direction. In wetness-concern mode, high sensitivity + borderline conditions → No (protect from use). In dryness-concern mode, high sensitivity + borderline conditions → Yes (protect from drought).
Dormancy and Evaporative Demand
Two Yardwise-specific wetness modifiers that were covered in the edge cases article deserve a brief recap in the context of the inversion:
Cold-weather dormancy injects additional wetness into the score when temperatures drop below 55°F. This suppresses watering recommendations by pushing the score toward the "skip" zone because dormant plants don't benefit from watering and the moisture promotes root rot and fungal growth.
From the engine's perspective, dormancy is saying: "the soil might technically be dry, but the plant doesn't need water right now, so act as if conditions are wetter than they are."
Low evaporative demand does something similar on cool, overcast, humid days. Even if the soil surface looks dry, the plant isn't losing much water through transpiration when there's no sun and the air is already saturated. A small wetness boost (up to 0.25) prevents unnecessary watering recommendations.
Both modifiers only activate in dryness-concern mode. They don't make sense for riders or field sports, cold weather doesn't make a trail less muddy, and overcast skies don't affect whether the ground is rideable or a football field is playable.
Yardwise Surface Types
The Groundwise family shares a surface type system, but Yardwise introduces types that don't exist in the riding or sports world:
Potting mix (containers) dries at 2.0x — the same rate as concrete. This isn't a coincidence. Potting mix is engineered for drainage, just like concrete. Containers are also typically exposed to wind on all sides, which accelerates drying considerably. The result: containers often need daily watering in summer, even after rain. The engine captures this naturally because the high drying multiplier clears moisture quickly.
Amended soil with mulch dries at 0.7x — the slowest rate in the system, tied with clay. Mulch deliberately slows evaporation. A mulched garden bed after rain stays moist for days. The engine's residual wetness model (which only activates for absorbent surfaces above 0.25 inches of rain) extends this further, keeping the score in "skip watering" territory well after a good rain.
Fresh seed has the highest effective damage sensitivity in the system: base 0.8 plus an establishment boost of 0.5, capped at 1.0. The engine is maximally protective of newly seeded areas, pushing any borderline verdict toward "water."
Compost is the most forgiving surface: 1.2x drying multiplier and only 0.3 damage sensitivity. Compost generates internal heat from decomposition, which drives some of its own drying. And it's hard to damage, overwatering a compost pile isn't really a concern. The engine mostly stays out of the way for compost, skewing toward "skip" unless conditions are genuinely dry.
The Insight That Made It Work
The hardest part of building Yardwise wasn't the code, it was convincing myself that the inversion was valid. Every instinct I'd built while developing Ridewise and Fieldwise said "wet = bad." Retraining my thinking to "wet = good (for gardening)" took effort.
What made it click was realizing that the engine isn't really about wet or dry. It's about moisture state relative to the ideal for a given surface and activity. For a trail, the ideal is dry. For a garden bed, the ideal is moist (not soaked!). The engine measures distance from ideal in both directions.
Once I saw it that way, the inversion was mechanical. Same measurements, same model, same pipeline. Just a different definition of "good."
Next in the Series
The final article covers the verdict UX, why three states beat a percentage, how the engine communicates uncertainty through confidence levels and contributing factors, and the role of the recovery outlook in managing expectations.
Yardwise is available for iOS from Stalefish Labs. Same engine as Ridewise and Fieldwise, different question.
Top comments (0)