1. Normalize formatting, not identity
Case and repeated spaces are formatting differences. Pro, Ultra, capacity and generation are often identity differences. Never delete those tokens to increase cache hit rate. Resolve an input to a confirmed product identity before calculating cache keys. An uncertain spelling match should become a suggestion, not an alias automatically. Store aliases only when equivalence has evidence. This protects the expensive evaluation cache from a subtle failure: confidently returning a precise report about an edition the user did not ask for.
2. Hash canonical structured input
Use deterministic serialization rather than joining strings with a separator that could appear inside a name. Include fact content, rubric version, provider/model and scenario in the evaluation identity. The function below treats a product set as order-independent, but preserves edition tokens. An application must still reorder score columns for display when the user reverses inputs. Do not include UI weights in a base evaluation key: weighting an existing score matrix is local arithmetic, not a new model judgment.
import hashlib, json, re
def digest(value):
raw = json.dumps(value, sort_keys=True, separators=(',', ':'), ensure_ascii=False)
return hashlib.sha256(raw.encode()).hexdigest()
def identity(name):
return re.sub(r'\s+', ' ', name.strip().casefold())
def evaluation_key(name, facts, model, rubric='phone-v2', scenario='daily'):
return digest([identity(name), digest(facts), model, rubric, scenario])
def report_key(names, evaluation_keys):
return digest(sorted(zip(map(identity, names), evaluation_keys)))
facts = {'battery_mah': 5000, 'region': 'US'}
a = evaluation_key('Phone Pro', facts, 'model-a')
assert a == evaluation_key(' phone PRO ', facts, 'model-a')
assert a != evaluation_key('Phone', facts, 'model-a')
assert a != evaluation_key('Phone Pro', {**facts, 'region': 'EU'}, 'model-a')
b = evaluation_key('Other Phone', facts, 'model-a')
assert report_key(['Phone Pro', 'Other Phone'], [a,b]) == report_key(['Other Phone','Phone Pro'], [b,a])
print('identity, facts and display-order tests passed')
3. Separate evaluations from choices
A versus B followed by A versus C can reuse A’s facts and compatible scores. It cannot automatically reuse the original pair’s winner or its comparative explanation. Keep single-product evaluations, panel choices, complete reports and translated narratives as distinct layers. A report key should include the actual participating model panel. A two-provider cached report must not be labeled as six providers simply because the current configuration enables more. Likewise, a simulated ballot should remain labeled and outside an independent-provider vote count.
4. Measure misses that deserve investigation
Classify a miss as new identity, changed facts, changed rubric, changed model, changed scenario or a genuinely new combination. Count full-report hits separately from evaluation reuse; a full-report hit does not perform every lower-level lookup. Sample supposedly successful hits for wrong editions and stale explanations. Private supplemental facts need comparison-scoped keys and must not alter a shared product record. In a multi-instance deployment, combine durable cache entries with a work lease so identical cold requests do not all pay for the same analysis.
