Methods 10 min
What a certificate is, and what it isn't
A guarantee over a continuum of lights is worth more than a test over five of them. It is also much easier to get subtly wrong.
The ordinary way to check that a palette survives different lighting is to test it under a few lamps. Render it under D65, under an incandescent A, maybe under a fluorescent, look at the numbers, and ship if the worst pair stays far enough apart.
That tells you about those lamps. It says nothing about the lamps in between, and the lamps in between are where products actually live. A certificate is the stronger object: a statement that holds for every light in a family, including the uncountably many you never evaluated. This post is about how to build one honestly, and about the way this lab got it wrong the first time.
The structure that makes it possible
The reason a certificate is available at all is a linearity fact.
For a fixed reflectance, the tristimulus response is linear in the illuminant. If light L₁ gives response X₁ and light L₂ gives X₂, then the mixture αL₁ + (1−α)L₂ gives exactly αX₁ + (1−α)X₂. No approximation. That means as the illuminant ranges over the convex hull of a set of basis lights, the reachable set of XYZ responses for each surface is exactly the convex hull of its basis responses.
That is a strong statement about an infinite family obtained from finitely many evaluations. If the story ended there, certification would be easy.
It does not end there, because we do not judge color differences in XYZ. Perceptual separation is measured in a space like Oklab, and the map from XYZ to Oklab is not linear — it involves a cube root. Convexity does not survive it. A mixture of two lights does not produce the mixture of the two Oklab positions, so knowing the corners no longer bounds the interior.
The bridge, and the trap
The standard fix is a Lipschitz bound. If you know the map cannot stretch distances by more than a factor K, then evaluating on a grid fine enough that no unevaluated point is farther than h from an evaluated one gives you a bound: the true minimum separation is at least the sampled minimum, minus K · h, doubled because both surfaces in a pair can move.
Subtract that correction and the result is a genuine lower bound over the whole continuum, not an estimate. Report it, and you have a certificate.
The trap is in estimating K.
The first implementation here estimated the Lipschitz constant of the XYZ-to-Oklab map over the bounding box of the reachable set. That is the obvious thing to do and it is wrong in a specific, punishing way. The bounding box of a set of reachable colors includes corners the surfaces cannot actually reach — in particular corners with components near zero. The cube root’s gradient is unbounded as its argument approaches zero. So the estimate was dominated by the steepness of the function at points that no illuminant in the family ever produces.
The measured effect: for a D65-plus-A family, the correction term came out at 6.32 against a sampled minimum separation of 0.30. The correction exceeded the quantity being corrected by a factor of twenty. Every certificate the tool produced was a guaranteed bound of zero. Not wrong, exactly — a true statement, uselessly weak, and delivered with the same confident structure as a real result.
The fix is to estimate the constant over the reachable points themselves and their midpoints, rather than over a box drawn around them. That is the set the certificate is actually about. With that change the constant lands roughly an order of magnitude lower and the bounds become informative. A regression test now pins it below 15, so if someone reintroduces a bounding-box estimate the suite says so.
What the failure teaches
A vacuous bound is worse than an error, because it does not look like one.
If the tool had crashed, the bug would have been found in an afternoon. Instead it returned a well-formed certificate whose guarantee happened to be zero, wrapped in the vocabulary of rigor. Anyone reading quickly would see “certified lower bound” and a number and move on.
The lesson this lab took from it is that a bound needs a sanity companion. Every certificate here now reports the sampled minimum alongside the guaranteed one. If the correction has eaten the entire result, the two numbers sit next to each other and the gap is impossible to miss. A guarantee you cannot compare against anything is a guarantee you cannot audit.
What the certificate still does not claim
Even correct, a certificate here is bounded by its assumptions, and the output says so:
- It covers the convex hull of the basis lights you named. A lamp outside that hull — a narrowband LED when your basis was two broadband illuminants — is not covered. The family is an input, not a discovery.
- It is stated for the standard observer. Individual observers vary; the certificate is about a population model.
- It uses a finite grid with a stated step, and the correction term is computed from that step. Report the step or the bound is unauditable.
- It assumes passive, non-fluorescent surfaces, because that is what the linearity argument requires.
Each of those is a place the guarantee stops. Naming them is not throat-clearing; it is what distinguishes a certificate from a marketing claim. A bound whose conditions are unstated cannot be checked, and a bound that cannot be checked is just a number in a nice font.
The shape worth copying
Strip away the color science and the pattern generalizes to any guarantee over a continuum:
- Find the structure that makes finite evaluation informative — here, linearity in the illuminant.
- Identify exactly where that structure breaks — here, the nonlinear perceptual map.
- Bridge the gap with a bound whose constant you estimate over the set you actually care about, not a convenient superset.
- Report the raw and corrected quantities together, so a collapsed guarantee is visible.
- State the conditions in the output, not the documentation, because the output is what gets pasted into someone else’s report.
Step three is where this lab lost a week. It is also the step most likely to be skipped, because the convenient superset is always easier to define.