def _strong_signals(x):
    n=0
    lat=x.get('response_latency_trend')
    err=x.get('error_rate_trend')
    hint=x.get('hint_rate_trend')
    if isinstance(lat,dict) and lat.get('pct_change',0)>=20: n+=1
    if isinstance(err,dict) and err.get('to',0)-err.get('from',0)>=0.05: n+=1
    if isinstance(hint,dict) and hint.get('to',0)-hint.get('from',0)>=0.08: n+=1
    return n

def evaluate(x):
    required=['learning_session_id','task_family','session_duration','attempt_count','performance_delta','medical_diagnosis_forbidden','pause_recommendation']
    if any(x.get(k) in (None,'') for k in required): return {'state':'HOLD_INSUFFICIENT_EVIDENCE','reason':'required field missing'}
    if x.get('medical_diagnosis_forbidden') is not True or str(x.get('fatigue_signal_class','')).startswith('DIAGNOSED_'):
        return {'state':'HOLD_MEDICAL_BOUNDARY','reason':'medical/internal-state diagnosis from learning telemetry is forbidden'}
    if _strong_signals(x)<2: return {'state':'UNKNOWN_INSUFFICIENT_SIGNALS','reason':'fewer than two behavior trends support a strong pacing signal'}
    if x.get('spacing_interval_minutes') is None or x.get('recent_practice_load') in (None,''):
        return {'state':'HOLD_SPACING_LOAD_CONTEXT','reason':'spacing/load context missing'}
    if x.get('pause_is_punitive') or x.get('pause_is_reversible') is not True or str(x.get('pause_recommendation','')).startswith('FORCED_'):
        return {'state':'HOLD_PUNITIVE_INTERVENTION','reason':'pause must be optional, reversible and non-punitive'}
    if x.get('learner_override') in (None,''):
        return {'state':'HOLD_OVERRIDE_VISIBILITY','reason':'learner override/preference must remain visible'}
    if not isinstance(x.get('provenance'),dict) or not x['provenance'].get('rule_version') or not x['provenance'].get('comparison_window'):
        return {'state':'HOLD_PROVENANCE','reason':'provenance incomplete'}
    if x.get('retention_result')=='STRONG' and x.get('recomputed_from_changed_evidence') is not True:
        return {'state':'INCONCLUSIVE_CONFLICTING_EVIDENCE','reason':'strong later retention contradicts unrecomputed prior signal'}
    if x.get('retention_check_ref') in (None,''):
        return {'state':'UNKNOWN_RETENTION_CONTEXT','reason':'retention reference missing'}
    return {'state':'LEARNER_CHOICE_REVIEW_REQUIRED','reason':'bounded multi-signal pacing evidence; no diagnosis'}

def inspect_transfer(x):
    if x.get('baseline_oracle_reuse') is True or x.get('recomputed_from_changed_evidence') is not True:
        return {'state':'HOLD_BASELINE_ORACLE_REUSE','reason':'transfer must be independently recomputed'}
    return evaluate(x)
