Skip to main content
Back to blog

FinOps Custom Rules Needed the Right Band, Not Just a UI

Riya Mittal
Riya Mittal Engineer · Zop.Dev
6 min read
FinOps Custom Rules Needed the Right Band, Not Just a UI

FinOps Custom Rules Needed the Right Band, Not Just a UI

A built-in rule library only covers what’s common across enough customers to be worth shipping. FinOps is the practice of giving engineering, finance, and product teams shared, real-time visibility into cloud cost so spending decisions get made where the usage happens. ZopNight’s recommendations engine already covers 450 or more built-in rules for that practice: idle resources, right-sizing, scheduling, orphaned volumes, and more. None of that library knows that your team’s staging cluster should be flagged the moment CPU stays under 5% for three days. That threshold was never going to be common enough to ship as a built-in right-sizing rule.

ZopNight now lets you write that rule yourself. Pick the resources you care about, set the metric and threshold that matters to your setup over a time window you choose, and decide what should happen when that threshold is crossed. The custom recommendation that results shows up beside the built-in ones, works exactly the same way, and explains why it fired and what to do about it.

A Policy Is a Resource Selector, a Signal, and an Outcome

A custom rule has three parts: which resources it watches, what metric signal it evaluates over what rolling window, and what it suggests when the condition is met. The outcome can be stopping something idle, scheduling it off during quiet hours, or retiring a resource nobody uses anymore.

Architecture diagram

That last step matters as much as the rule itself. A custom rule doesn’t produce a different kind of object that needs its own review process. It resolves through the same engine as a built-in rule, lands in the same recommendation flow, and gets the same explanation of why it fired, right down to a warning before it suggests turning off anything stateful, like a database. This works when the resource selector matches exactly what you meant to watch. It breaks when a selector is too broad and quietly pulls in resources the rule was never meant to touch, since the engine has no way to know intent beyond what the selector actually matches.

Catching a Spike Meant Fixing Which Statistical Band Got Read

The headline capability, catching a rule like “flag anything whose CPU ever jumped above 80%,” depends on reading the right slice of the underlying metric data. Peak and trough signals, max, p95, p99, and min, were being computed over the hourly-average band instead of the per-hour peak or minimum band. A spike rule evaluated against an average will systematically miss real spikes, because averaging is exactly the operation that smooths a spike away. The symmetric problem hit trough detection too: a “min” rule read against the average band over-reported how low a resource actually dropped.

Signal typeBand it needs to readBand it was reading before the fix
max, p95, p99 (peak)Per-hour peak bandHourly-average band, under-fires on real spikes
min (trough)Per-hour minimum bandHourly-average band, over-reports how low usage went

No amount of threshold tuning would have fixed this. A rule set to fire above 80% wasn’t wrong about the number. It was reading a value that had already been averaged down before the comparison happened, so raising or lowering the threshold moves where the bug shows up, not whether it exists. The fix routes each signal type to the band that actually matches what it’s supposed to measure.

A Coverage Gate That Demanded 100% Was Punishing Real Metrics

A second gate decides whether there’s enough data behind a rule to trust it. The original version measured coverage in filled hour-slots and required something close to full hourly density across the whole window. Real cloud metrics don’t arrive that cleanly: gaps are normal, and some cloud providers drop zero-activity buckets from their own summed bands entirely. A genuinely valid, window-spanning rule could still get floored by this gate, demoted to advisory status, and shown with a savings figure of zero. That wasn’t because the rule was wrong. It was because the coverage math expected a density that real telemetry doesn’t produce.

The fix counts distinct days of coverage instead of filled hours. That’s a small change in what gets counted and a large change in what the gate actually measures: sustained evidence across a window, rather than an artifact of how completely one provider happens to report metrics within each hour.

The Same Recommendation Can’t Disagree With Itself Between List and Drawer

Two more fixes closed gaps that only showed up once the feature was used the way a real workflow uses it. Enrichment that stamps a recommendation’s lever and rebuilds its title, including retitling a stateful resource as “keep it running” rather than “schedule to stop,” ran only on the drawer path. The list view returned the raw row underneath it. That meant the same recommendation could show a null lever in the list and only pick up its correct title, and its downtime warning, once someone actually opened the drawer. A user scanning the list without opening every row could miss the warning meant to stop them from scheduling a database offline by mistake.

A separate, smaller bug gave a rule’s header row the title of one arbitrary child resource’s recommendation instead of the name the customer typed in when they created the rule. Both fixes are cosmetic-sounding but load-bearing. A title and a warning are the only signal a user sees before clicking a button that stops or deletes a resource. Where those get computed determines whether the safety net is actually there when it’s needed.

The whole feature ships behind RBAC permissions rather than a flag, with one new, purely additive database table. That scope is why the release notes ask for all six of its fixes to be reverted together rather than individually: they’re one feature, discovered and hardened in the order real usage exposed its edges.

Tagged
Riya Mittal

Riya Mittal

Engineer · Zop.Dev

Riya works on the autonomous remediation engine at Zop.Dev. Before that she was a security engineer at a SaaS company that learned the hard way what 14 days of exposure looks like. She writes about cloud security, automation, and the trade-off between speed and safety.

Stop watching the waste.
Start cutting it.

See. Find. Fix. Automatic.

Connect your first cloud account in under 5 minutes. See your first remediation in under 7. No credit card required.

CDCR connect detect classify remediate
full audit every action traceable
read-only default access
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·