A material grade sometimes changes the rate and sometimes changes the whole calculation
The pricing workbook for a fabrication business had two formula columns on every product-feature row. One for each grade of stainless the business quotes in. Same product, same feature, two different rule codes.
I had assumed grade was a rate. Pick the cheaper sheet, the same calculation produces a smaller number, done. That is true for most features and it is not true for all of them, and the difference is not cosmetic — in a heavier grade some items are fabricated differently, so the arithmetic itself changes, not just the input.
Once you accept that, the resolution problem gets its shape. Given a product, a feature, the variant the customer chose and the grade for this line, which of the 362 rules runs.
Both mechanisms have to exist at once
The system ended up supporting two ways for grade to affect a price, and it is worth being precise about them because they behave differently under change.
Grade changes the rate. One rule, and the grade determines which material the user picks from the dropdown. A cheaper sheet has a lower rate, the rule multiplies by that rate, the price falls. The rule is untouched. This is the common case and it is the one you want, because the business maintains one calculation.
Grade changes the rule. A rule mapping can be pinned to a specific grade, so the same product and feature route to a different calculation depending on the line’s grade. This is the minority case and it exists because the workbook said so.
You do not get to pick one. A design that only supports the first cannot express what the business already does. A design that only supports the second forces a grade-pinned mapping for every feature and doubles the mapping count for no benefit.
Resolution by specificity
With both mechanisms live, a mapping lookup can return several candidates, and something has to rank them. The ranking runs in three tiers.
Grade first: a mapping pinned to this line’s grade beats a mapping that names no grade. Then variant: a mapping pinned to the exact variant the customer chose beats a mapping with no variant, which in turn beats a mapping pointed at a catch-all variant that exists purely as a fallback. Ties break on an explicit priority number stored on the mapping.
This is the same shape as stylesheet specificity or route precedence, and it inherits the same property. It works, and it is horrible to debug, because the rule that fired leaves no trace in the output unless you deliberately put one there.
Which is why the engine also carries a diagnostic for the case where a compatible mapping exists but was not the one selected. That is not a data problem for a business user to fix — it means the ranking disagreed with a straightforward search, and it is a defect to report. Distinguishing “your data is incomplete” from “our resolution is wrong” in the output is the difference between a support ticket and a five-minute fix by the person who owns the data.
The autofill heuristic, and why it is the risky part
Grade also drives something less rigorous. When a rule requires a material slot and the user has not picked anything for it, the system picks for them, using the line’s grade as the hint.
The mechanism is a score. Candidate materials within the slot’s group get points for containing a token that matches the grade, points for stating a sheet gauge, more points if that gauge matches the preferred one, and a point for having a non-zero rate. Highest score wins.
That is string matching against product descriptions, and I want to be plain about what it is: a guess. A good guess, tuned to how this business names its stock, and still a guess. Two things follow from that.
It must never be the only path. Anything the heuristic chooses has to be visible and overridable, and the calculation has to record which material was actually used rather than only the rule that consumed it. If a price is queried six weeks later, “the system picked something sensible” is not an answer.
And it must be scoped narrowly. The scoring only ever runs within the material group the slot is bound to, and only for slots the rule marks as required. It is a convenience inside a constrained set, not a search. Widen it and it starts confidently picking wrong.
The interface decision that mattered more than the engine
The business’s own request, once they had used it, was to hide the material pickers entirely.
Their reasoning was operational. A sales person quoting a standard item in a standard grade should not be looking at a list of sheet stock. The grade is set once for the quote, the defaults follow from it, and the pickers are noise that invites someone to change something they should not.
So material selection became conditional on the user explicitly choosing a custom-grade mode. In the normal path, defaults are applied silently and no material control is rendered at all. In the custom path, everything is exposed.
That is worth noting because it inverts what a developer would naturally build. The engine’s most sophisticated capability — per-slot material selection across the whole call tree — turned out to be something most users should never see. The capability still has to exist, in full, for the minority of quotes that need it. It just should not be the default surface.
The same call produced a related instruction: show a dimension field only where the estimator actually has to enter something, and apply the defaults for the rest without asking. Both requests are the same request. Configurability is for the person maintaining the system, not for the person using it eight times a day.
The limit I have not solved
Grade-pinned rules and rate-driven grades coexist, and nothing in the system tells you which mechanism a given product-and-feature is using. You find out by looking at the mappings.
For a catalogue this size that is survivable. For someone maintaining it who did not build it, it is a genuine gap, and the honest position is that the mapping table needs a view that answers “how does grade affect this feature” directly rather than by inference.
The rule
Before you model a variant axis — grade, finish, region, anything — establish whether it changes an input or changes the calculation. Ask for the source data and look for a second column. If both happen in the business, both have to be expressible, and the resolution order between them has to be written down and reported in the output, because specificity ranking is invisible exactly when you need to see it.