Decision Kernels
Turns a research state into one graduated, concrete action — not a binary gate, not a menu of options. v2: rebuilt after direct critique that the original binary version collapsed real gradations (n=42 and n=42,000 got the same answer).
A bug found and fixed while preparing this page
The original file's self-test block had no if __name__ == "__main__": guard.
Because its indentation matched the function above it, Python silently absorbed the
entire test block as unreachable code inside validate_claim_against_evidence(),
after its return statement. The file imported fine, all four functions worked
correctly when called directly — but running the file itself produced zero output, no
error, nothing. Fixed by adding the missing guard.
Fixing it surfaced a second, separate issue: the file imports
MIN_EXPLORATORY_N and CONFIDENCE_TIERS from
exploratory_heuristic_42.py — a file referenced since the very first
version of this site's Infrastructure page and, for a long time, never actually
uploaded. It has since arrived. All four functions are now confirmed running with
real output, shown fresh below — not just correct on inspection.
Source (fixed)
def classify_claim_relationship(claim_a: dict, claim_b: dict) -> dict:
"""Real fix: four categories (contradiction / tension / refinement /
independent), not a binary contradiction check that only caught
same-subject-opposite-direction claims."""
if claim_a.get("subject") != claim_b.get("subject"):
return {"relationship": "independent", "reason": "Different subjects."}
metric_a, metric_b = claim_a.get("metric"), claim_b.get("metric")
dir_a, dir_b = claim_a.get("direction"), claim_b.get("direction")
if metric_a == metric_b and dir_a and dir_b:
if dir_a != dir_b:
return {"relationship": "contradiction",
"reason": "Same subject, same metric, incompatible directions."}
return {"relationship": "refinement",
"reason": "Same subject, same metric, same direction -- likely
replication, not new information."}
if metric_a != metric_b:
return {"relationship": "tension",
"reason": "Same subject, different metrics -- a real tradeoff
worth surfacing, not a direct contradiction."}
return {"relationship": "independent", "reason": "Insufficient information to classify further."}
Real execution — all four functions, run fresh
=== Real test: graduated evidence sufficiency, n=42 vs n=42,000 now genuinely distinguishable ===
{'confidence': 0.3, 'action': 'continue_cautiously', 'reason': 'n=42 against a exploratory threshold of 42 (ratio=1.00).'}
{'confidence': 1.0, 'action': 'continue_high_confidence', 'reason': 'n=42000 against a exploratory threshold of 42 (ratio=1000.00).'}
{'confidence': 0.126, 'action': 'gather_more_data', 'reason': 'n=42 against a performance threshold of 100 (ratio=0.42).'}
=== Real test: graduated escalation, continuous spread instead of a boolean ===
{'confidence': 0.97, 'action': 'escalate_high_confidence', 'reason': 'spread=0.0300 across 2 independent passes.'}
{'confidence': 0.55, 'action': 'investigate_disagreement', 'reason': 'spread=0.4500 across 2 independent passes.'}
{'confidence': 0.1, 'action': 'reframe_question', 'reason': 'spread=0.9000 across 2 independent passes.'}
=== Real test: the exact case this function exists to catch — tension, not contradiction ===
{'relationship': 'tension', 'reason': "Same subject ('estimator_X'), different metrics
('accuracy' vs 'calibration') -- a real tradeoff worth surfacing, not a direct contradiction."}
=== Real test: a genuine direct contradiction, still caught correctly ===
{'relationship': 'contradiction', 'reason': "Same subject ('estimator_A_vs_B'), same metric
('accuracy'), incompatible directions: 'A_better' vs 'B_better'."}
"Improves accuracy" and "hurts calibration" are not opposites — an earlier binary version would have missed this entirely. Correctly flagged as tension, not silently dropped as unrelated — and a genuine direct contradiction, tested right alongside it, is still caught correctly rather than over-corrected into "everything is nuance."
Comments