Spaces:
Sleeping
Sleeping
File size: 11,364 Bytes
ab34aa7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | """
Integration tests for Sub-env 2: Dataset Clip Audit.
Covers Node 5 (Clip Disposition Recommender) and Node 6 grader
(DatasetHealthHandoff aggregation) without any real video files or heavy
model dependencies. All objects are constructed manually from schema classes.
"""
from __future__ import annotations
import numpy as np
import pytest
from src.envs.subenv2.node5_disposition import recommend_clip_disposition
from src.pipeline import _build_dataset_health_handoff
from src.schemas.ground_truth import GroundTruthClipAnnotation
from src.schemas.subenv2 import (
ClipDispositionObservation,
ClipEvidenceDossier,
ClipSignalObservation,
SyntheticWeightDescriptor,
)
# ---------------------------------------------------------------------------
# Shared dataset-level observation parameters (same for all three clips)
# ---------------------------------------------------------------------------
_SHARED_OBS_KWARGS = dict(
minimum_clips_needed=20,
phoneme_gap_severity={"ZH": 2, "TH": 1},
pose_gap_severity={},
budget_remaining=10,
reference_risk_profile="medium",
estimated_drift_risk=0.4,
marginal_training_damage=0.2,
marginal_coverage_gain=0.5,
)
# ---------------------------------------------------------------------------
# Evidence dossiers
# ---------------------------------------------------------------------------
@pytest.fixture
def dossier_a() -> ClipEvidenceDossier:
"""Clean clip — should be accepted."""
return ClipEvidenceDossier(
clip_id="clip_001",
identity_drift_severity="none",
temporal_instability_flag=False,
lip_sync_quality="good",
unique_phoneme_value=0.8,
dataset_redundancy_score=0.1,
estimated_training_impact="positive",
primary_rejection_reason=None,
evidence_summary="clean clip",
)
@pytest.fixture
def dossier_b() -> ClipEvidenceDossier:
"""Bad clip — high drift, temporal instability, poor sync, redundant."""
return ClipEvidenceDossier(
clip_id="clip_002",
identity_drift_severity="severe",
temporal_instability_flag=True,
lip_sync_quality="poor",
unique_phoneme_value=0.1,
dataset_redundancy_score=0.9,
estimated_training_impact="negative",
primary_rejection_reason="severe drift",
evidence_summary="bad clip",
)
@pytest.fixture
def dossier_c() -> ClipEvidenceDossier:
"""Borderline clip — moderate drift, acceptable sync, mid-range phoneme value."""
return ClipEvidenceDossier(
clip_id="clip_003",
identity_drift_severity="moderate",
temporal_instability_flag=False,
lip_sync_quality="acceptable",
unique_phoneme_value=0.6,
dataset_redundancy_score=0.3,
estimated_training_impact="neutral",
primary_rejection_reason=None,
evidence_summary="borderline clip",
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _make_obs(dossier: ClipEvidenceDossier) -> ClipDispositionObservation:
"""Wrap a dossier into a ClipDispositionObservation with the shared context."""
return ClipDispositionObservation(
evidence_dossier=dossier,
**_SHARED_OBS_KWARGS,
)
def _minimal_clip_signal_obs(clip_id: str) -> ClipSignalObservation:
"""Return a ClipSignalObservation with all-zero / empty values for aggregation."""
return ClipSignalObservation(
clip_id=clip_id,
face_embedding_variance=0.0,
landmark_stability_score=0.0,
identity_cosine_drift=0.0,
frame_difference_mean=0.0,
optical_flow_magnitude=1.0,
blink_count=0,
lip_sync_confidence=0.0,
phoneme_sequence=[],
phoneme_coverage_new=0.5,
blur_score=0.8,
exposure_score=0.7,
occlusion_frames=0,
clips_audited_so_far=0,
current_phoneme_coverage={},
current_pose_distribution={},
similar_clips_accepted=0,
)
def _minimal_gt(
disposition: str,
confidence: float = 0.5,
ambiguity: float = 0.0,
) -> GroundTruthClipAnnotation:
"""Build a minimal GroundTruthClipAnnotation for grading."""
return GroundTruthClipAnnotation(
disposition=disposition,
confidence=confidence,
disposition_ambiguity=ambiguity,
valid_fix_steps=[],
valid_override_justifications=[],
expected_reasoning_elements=["zh"],
)
# ---------------------------------------------------------------------------
# Test block 1 — Node 5: Clip Disposition Recommender
# ---------------------------------------------------------------------------
class TestNode5Disposition:
"""Tests for recommend_clip_disposition()."""
def test_disposition_a_accept(self, dossier_a):
"""Clean clip must be accepted."""
action = recommend_clip_disposition(_make_obs(dossier_a))
assert action.disposition == "accept"
def test_disposition_b_reject_or_fix(self, dossier_b):
"""Severely degraded clip must be rejected or sent for fix."""
action = recommend_clip_disposition(_make_obs(dossier_b))
assert action.disposition in {"reject", "fix"}
def test_disposition_c_reasonable(self, dossier_c):
"""Borderline clip must land on fix, defer, or accept (not outright reject)."""
action = recommend_clip_disposition(_make_obs(dossier_c))
assert action.disposition in {"fix", "defer", "accept"}
def test_confidence_in_range_all(self, dossier_a, dossier_b, dossier_c):
"""Confidence must be in [0.0, 1.0] for every clip."""
for dossier in (dossier_a, dossier_b, dossier_c):
action = recommend_clip_disposition(_make_obs(dossier))
assert 0.0 <= action.confidence <= 1.0, (
f"confidence={action.confidence} out of range for {dossier.clip_id}"
)
def test_override_decision_valid_literal(self, dossier_a, dossier_b, dossier_c):
"""override_decision must be one of the three allowed Literal values."""
valid = {"not_applicable", "declined", "applied"}
for dossier in (dossier_a, dossier_b, dossier_c):
action = recommend_clip_disposition(_make_obs(dossier))
assert action.override_decision in valid, (
f"override_decision={action.override_decision!r} for {dossier.clip_id}"
)
def test_reasoning_mentions_zh_phoneme_gap(self, dossier_a):
"""dataset_impact_reasoning must mention 'ZH' (a phoneme gap in the context)."""
action = recommend_clip_disposition(_make_obs(dossier_a))
assert "ZH" in action.dataset_impact_reasoning, (
f"Expected 'ZH' in reasoning, got: {action.dataset_impact_reasoning!r}"
)
def test_fix_has_instructions_when_fix(self, dossier_b):
"""When disposition is 'fix', fix_instructions must be non-empty."""
action = recommend_clip_disposition(_make_obs(dossier_b))
if action.disposition == "fix":
assert action.fix_instructions is not None
assert len(action.fix_instructions) > 0
def test_reject_has_rejection_reasons(self, dossier_b):
"""When disposition is 'reject', rejection_reasons should reference the issue."""
action = recommend_clip_disposition(_make_obs(dossier_b))
if action.disposition == "reject":
# Either rejection_reasons is set, or the primary_rejection_reason is surfaced
assert (
action.rejection_reasons is not None
), "Expected rejection_reasons for a reject disposition"
# ---------------------------------------------------------------------------
# Test block 2 — Node 6 grader: DatasetHealthHandoff aggregation
# ---------------------------------------------------------------------------
class TestNode6DatasetHealthHandoff:
"""Tests for _build_dataset_health_handoff() (Node 6 aggregator)."""
@pytest.fixture
def all_actions_and_obs(self, dossier_a, dossier_b, dossier_c):
"""Run Node 5 for all three dossiers; return (actions, clip_obs_list)."""
dossiers = [dossier_a, dossier_b, dossier_c]
actions = [recommend_clip_disposition(_make_obs(d)) for d in dossiers]
obs_list = [_minimal_clip_signal_obs(d.clip_id) for d in dossiers]
return actions, obs_list
@pytest.fixture
def handoff(self, all_actions_and_obs):
"""Build the DatasetHealthHandoff from the three clip results."""
actions, obs_list = all_actions_and_obs
clip_scores = [0.6, 0.2, 0.5] # arbitrary plausible per-clip scores
subenv2_score = float(np.mean(clip_scores))
return _build_dataset_health_handoff(actions, clip_scores, obs_list, subenv2_score)
def test_subenv2_score_in_range(self, handoff):
"""subenv2_score must be in [0.0, 1.0]."""
assert 0.0 <= handoff.subenv2_score <= 1.0
def test_synthetic_weight_descriptor_type(self, handoff):
"""synthetic_weight_descriptor must be a SyntheticWeightDescriptor instance."""
assert isinstance(handoff.synthetic_weight_descriptor, SyntheticWeightDescriptor)
def test_clip_counts_sum_to_three(self, handoff, all_actions_and_obs):
"""accepted + rejected + fix_recommended must account for all non-defer clips.
The aggregator does not include 'defer' dispositions in any count field,
so the sum equals (total clips - deferred clips), not necessarily 3.
"""
actions, _ = all_actions_and_obs
expected_accept = sum(1 for a in actions if a.disposition == "accept")
expected_reject = sum(1 for a in actions if a.disposition == "reject")
expected_fix = sum(1 for a in actions if a.disposition == "fix")
non_defer = expected_accept + expected_reject + expected_fix
assert handoff.accepted_clip_count == expected_accept
assert handoff.rejected_clip_count == expected_reject
assert handoff.fix_recommended_count == expected_fix
total = (
handoff.accepted_clip_count
+ handoff.rejected_clip_count
+ handoff.fix_recommended_count
)
assert total == non_defer, (
f"Expected counts to sum to {non_defer} (non-defer clips), got "
f"accept={handoff.accepted_clip_count} "
f"reject={handoff.rejected_clip_count} "
f"fix={handoff.fix_recommended_count}"
)
def test_weight_contamination_in_range(self, handoff):
"""weight_contamination_estimate must be in [0.0, 1.0]."""
assert 0.0 <= handoff.weight_contamination_estimate <= 1.0
def test_identity_consistency_score_in_range(self, handoff):
"""identity_consistency_score must be in [0.0, 1.0]."""
assert 0.0 <= handoff.identity_consistency_score <= 1.0
def test_overall_dataset_quality_in_range(self, handoff):
"""overall_dataset_quality must be in [0.0, 1.0]."""
assert 0.0 <= handoff.overall_dataset_quality <= 1.0
def test_high_risk_clip_ids_are_strings(self, handoff):
"""high_risk_clip_ids must be a list of strings."""
assert all(isinstance(cid, str) for cid in handoff.high_risk_clip_ids)
|