#!/usr/bin/env python3
"""Deterministic first-pass taxonomy classifier for lab-field divergence.

Input: a pandas DataFrame containing field p75 metrics, lab metrics, and optional context columns.
Output: the same DataFrame with `divergence_type` and `divergence_reason`.

This classifier is intentionally conservative. It is not a causal model; it creates reproducible triage labels for auditing and model-training targets.
"""
from __future__ import annotations
import pandas as pd

LCP_GOOD_MS = 2500
INP_GOOD_MS = 200
CLS_GOOD = 0.1
TBT_LAB_WARNING_MS = 200
TTFB_POOR_MS = 1800  # Conservative diagnostic threshold; tune by preregistered sensitivity analysis.


def classify_row(row: pd.Series) -> tuple[str, str]:
    field_lcp_good = row.get('p75_lcp', float('inf')) <= LCP_GOOD_MS
    field_inp_good = row.get('p75_inp', float('inf')) <= INP_GOOD_MS
    field_cls_good = row.get('p75_cls', float('inf')) <= CLS_GOOD
    lab_lcp_good = row.get('lab_lcp_ms', float('inf')) <= LCP_GOOD_MS
    lab_tbt_good = row.get('lab_tbt_ms', float('inf')) <= TBT_LAB_WARNING_MS
    lab_cls_good = row.get('lab_cls', float('inf')) <= CLS_GOOD
    ttfb_poor = row.get('p75_ttfb', 0) and row.get('p75_ttfb', 0) > TTFB_POOR_MS

    if field_lcp_good and field_inp_good and field_cls_good and lab_lcp_good and lab_tbt_good and lab_cls_good:
        return 'REP', 'Lab and field both pass primary metric gates.'
    if (not field_lcp_good) and lab_lcp_good and ttfb_poor:
        return 'TTFB_FIELD', 'Field LCP fails despite lab LCP pass and CrUX TTFB is poor.'
    if (not field_inp_good) and lab_tbt_good:
        return 'INP_BEHAVIOR', 'Field INP fails despite acceptable load-time TBT.'
    if field_inp_good and (not lab_tbt_good):
        return 'TBT_FALSE_ALARM', 'Lab TBT warning but field INP is good.'
    if field_cls_good and (not lab_cls_good):
        return 'CLS_LAB_ONLY', 'Lab CLS fails but field CLS is good.'
    if (not field_cls_good) and lab_cls_good:
        return 'CLS_FIELD_ONLY', 'Field CLS fails but lab CLS is good.'
    if row.get('navigation_bfcache_fraction', 0) and row.get('navigation_bfcache_fraction', 0) > 0.15:
        return 'BFCACHE_SW', 'High bfcache/repeat navigation share likely affects lab-field transportability.'
    if row.get('rtt_p75', 0) and row.get('rtt_p75', 0) > 300:
        return 'GEO_RTT', 'High field RTT suggests geographic or network-population divergence.'
    return 'UNCLASSIFIED', 'No conservative rule fired; inspect page mix, timing, content variance, and missing features.'


def classify(df: pd.DataFrame) -> pd.DataFrame:
    labels = df.apply(classify_row, axis=1, result_type='expand')
    labels.columns = ['divergence_type', 'divergence_reason']
    return pd.concat([df.copy(), labels], axis=1)


if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('input_csv')
    parser.add_argument('output_csv')
    args = parser.parse_args()
    data = pd.read_csv(args.input_csv)
    classify(data).to_csv(args.output_csv, index=False)
