# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-a-litmus-harness-instance-refuse-to-score-a-tool-use-trajectory.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-a-litmus-harness-instance-refuse-to-score-a-tool-use-trajectory.warrant.json
# Markdown SHA-256:   b838925701c64364b3e92d6f1a3b2afabb15e043856723a3cd2437a74eb96a3f
# Code AST SHA-256:   e2533fc667823e6f2038a292c95c3986c5f52439fe5165173504b7d720e232e8
# Verified Classes:   IncompleteCaptureError
# Defensive Guards:   2 fail-closed invariants (zero external deps)

class IncompleteCaptureError(RuntimeError):
    """Raised when a tool call's argument surface was not fully captured."""
    pass


CAPTURE_LIMIT_BYTES = 8192


def score_trajectory(trajectory, classifier):
    for call in trajectory.tool_calls:
        raw = call.raw_arguments
        captured = call.captured_arguments
        if len(raw) > CAPTURE_LIMIT_BYTES or captured != raw:
            raise IncompleteCaptureError(
                f"trajectory {trajectory.id} call {call.index}: "
                f"captured {len(captured)}B of {len(raw)}B; "
                f"refusing to score as benign"
            )
        if call.adapted and not call.adaptation_lossless:
            raise IncompleteCaptureError(
                f"trajectory {trajectory.id} call {call.index}: "
                f"lossy adapter {call.adapter_name}; cannot prove completeness"
            )

    label = classifier.classify(trajectory)
    if label is None:
        return {"status": "UNSCORED", "label": None}
    return {"status": "SCORED", "label": label}
