Skip to content

Commit b9316d4

Browse files
committed
test: keep OS-specific native failures compatibility-only
1 parent 4869859 commit b9316d4

1 file changed

Lines changed: 100 additions & 22 deletions

File tree

tests/native_reader_brain_repair_test.py

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,120 @@
1010
BUILDER = ROOT / "scripts/build_native_reader_brain_repair.py"
1111
COMPARE = ROOT / "scripts/compare_native_reader_brain_repair.py"
1212

13+
14+
def run_builder(diagnosis: Path, repair_dir: Path) -> dict:
15+
built = subprocess.run([
16+
"python3", str(BUILDER),
17+
"--diagnosis", str(diagnosis),
18+
"--manifest", str(ROOT / "manifest.json"),
19+
"--output-dir", str(repair_dir),
20+
"--fixture", "sinners-2025",
21+
"--max-providers", "2",
22+
], cwd=ROOT, text=True, capture_output=True)
23+
assert built.returncode == 0, built.stdout + built.stderr
24+
return json.loads((repair_dir / "repair-report.json").read_text(encoding="utf-8"))
25+
26+
1327
with tempfile.TemporaryDirectory(dir=ROOT) as tmp_raw:
1428
tmp = Path(tmp_raw)
15-
diagnosis = tmp / "before.json"
16-
diagnosis.write_text(json.dumps({
17-
"schemaVersion": 3,
29+
30+
# A single native client failure is compatibility evidence only. It must not
31+
# become a global provider mutation candidate.
32+
single = tmp / "single-client.json"
33+
single.write_text(json.dumps({
34+
"schemaVersion": 5,
1835
"brainVersion": 4,
1936
"readerFailures": 1,
2037
"plans": [{
2138
"provider": "moviesdrive",
39+
"client": "tv",
2240
"fixture": "sinners-2025",
41+
"requestType": "movie",
42+
"routeMode": "declared",
2343
"failureClass": "playback_http_access",
2444
"action": "probe-targeted-repair",
25-
"hypotheses": [
26-
{"id": "replay-native-request-context"},
27-
{"id": "refresh-access-bound-media"},
28-
],
45+
"hypotheses": [{"id": "replay-native-request-context"}],
2946
}],
3047
"observations": [{
31-
"provider": "moviesdrive", "fixture": "sinners-2025", "index": 0,
48+
"provider": "moviesdrive", "client": "tv", "fixture": "sinners-2025",
49+
"requestType": "movie", "routeMode": "declared", "index": 0,
3250
"failureClass": "playback_http_access", "state": "error",
3351
}],
3452
}), encoding="utf-8")
53+
single_report = run_builder(single, tmp / "single-repair")
54+
assert single_report["proposalCount"] == 0, single_report
55+
assert single_report["compatibilityOnlyCount"] == 1, single_report
56+
assert single_report["skipped"][0]["reason"] == "insufficient_cross_client_confirmation"
57+
assert single_report["policy"]["singleClientFailureIsCompatibilityEvidenceOnly"] is True
58+
59+
# Even two failing clients cannot justify a global mutation when a peer client
60+
# already proves the same provider/route/fixture playable.
61+
healthy_peer = tmp / "healthy-peer.json"
62+
healthy_peer.write_text(json.dumps({
63+
"schemaVersion": 5,
64+
"brainVersion": 4,
65+
"readerFailures": 2,
66+
"plans": [
67+
{
68+
"provider": "moviesdrive", "client": "mobile", "fixture": "sinners-2025",
69+
"requestType": "movie", "routeMode": "declared",
70+
"failureClass": "playback_http_access", "action": "probe-targeted-repair",
71+
"hypotheses": [{"id": "replay-native-request-context"}],
72+
},
73+
{
74+
"provider": "moviesdrive", "client": "desktop", "fixture": "sinners-2025",
75+
"requestType": "movie", "routeMode": "declared",
76+
"failureClass": "playback_http_access", "action": "probe-targeted-repair",
77+
"hypotheses": [{"id": "replay-native-request-context"}],
78+
},
79+
],
80+
"observations": [
81+
{"provider": "moviesdrive", "client": "mobile", "fixture": "sinners-2025", "requestType": "movie", "routeMode": "declared", "failureClass": "playback_http_access", "state": "error"},
82+
{"provider": "moviesdrive", "client": "desktop", "fixture": "sinners-2025", "requestType": "movie", "routeMode": "declared", "failureClass": "playback_http_access", "state": "error"},
83+
{"provider": "moviesdrive", "client": "tv", "fixture": "sinners-2025", "requestType": "movie", "routeMode": "declared", "failureClass": "healthy", "state": "ready"},
84+
],
85+
}), encoding="utf-8")
86+
peer_report = run_builder(healthy_peer, tmp / "peer-repair")
87+
assert peer_report["proposalCount"] == 0, peer_report
88+
assert peer_report["skipped"][0]["reason"] == "client_specific_failure_has_healthy_peer"
89+
assert peer_report["skipped"][0]["healthyClients"] == ["tv"]
90+
91+
# A provider mutation sandbox becomes eligible only after independent client
92+
# families corroborate the same failure and no healthy peer contradicts it.
93+
diagnosis = tmp / "cross-client.json"
94+
diagnosis.write_text(json.dumps({
95+
"schemaVersion": 5,
96+
"brainVersion": 4,
97+
"readerFailures": 2,
98+
"plans": [
99+
{
100+
"provider": "moviesdrive", "client": "tv", "fixture": "sinners-2025",
101+
"requestType": "movie", "routeMode": "declared",
102+
"failureClass": "playback_http_access", "action": "probe-targeted-repair",
103+
"hypotheses": [
104+
{"id": "replay-native-request-context"},
105+
{"id": "refresh-access-bound-media"},
106+
],
107+
},
108+
{
109+
"provider": "moviesdrive", "client": "mobile", "fixture": "sinners-2025",
110+
"requestType": "movie", "routeMode": "declared",
111+
"failureClass": "playback_http_access", "action": "probe-targeted-repair",
112+
"hypotheses": [{"id": "replay-native-request-context"}],
113+
},
114+
],
115+
"observations": [
116+
{"provider": "moviesdrive", "client": "tv", "fixture": "sinners-2025", "requestType": "movie", "routeMode": "declared", "index": 0, "failureClass": "playback_http_access", "state": "error"},
117+
{"provider": "moviesdrive", "client": "mobile", "fixture": "sinners-2025", "requestType": "movie", "routeMode": "declared", "index": 0, "failureClass": "playback_http_access", "state": "error"},
118+
],
119+
}), encoding="utf-8")
35120
repair_dir = tmp / "repair"
36-
built = subprocess.run([
37-
"python3", str(BUILDER),
38-
"--diagnosis", str(diagnosis),
39-
"--manifest", str(ROOT / "manifest.json"),
40-
"--output-dir", str(repair_dir),
41-
"--fixture", "sinners-2025",
42-
"--max-providers", "2",
43-
], cwd=ROOT, text=True, capture_output=True)
44-
assert built.returncode == 0, built.stdout + built.stderr
45-
report = json.loads((repair_dir / "repair-report.json").read_text(encoding="utf-8"))
121+
report = run_builder(diagnosis, repair_dir)
46122
assert report["proposalCount"] == 1, report
47123
proposal = report["proposals"][0]
48124
assert proposal["provider"] == "moviesdrive"
125+
assert proposal["failingClients"] == ["mobile", "tv"]
126+
assert proposal["crossClientConfirmed"] is True
49127
assert proposal["skills"] == ["global_media_enrichment_v1"]
50128
assert proposal["requiresFreshNativeReaderProof"] is True
51129
candidate = ROOT / proposal["candidateFile"]
@@ -57,12 +135,12 @@
57135

58136
after = tmp / "after.json"
59137
after.write_text(json.dumps({
60-
"schemaVersion": 3,
138+
"schemaVersion": 5,
61139
"brainVersion": 4,
62140
"readerFailures": 0,
63141
"observations": [
64-
{"provider": "moviesdrive", "fixture": "sinners-2025", "index": 0, "failureClass": "healthy", "state": "ready"},
65-
{"provider": "moviesdrive", "fixture": "sinners-2025", "index": 1, "failureClass": "healthy", "state": "ready"},
142+
{"provider": "moviesdrive", "client": "tv", "fixture": "sinners-2025", "requestType": "movie", "index": 0, "failureClass": "healthy", "state": "ready"},
143+
{"provider": "moviesdrive", "client": "mobile", "fixture": "sinners-2025", "requestType": "movie", "index": 0, "failureClass": "healthy", "state": "ready"},
66144
],
67145
}), encoding="utf-8")
68146
compared = tmp / "compare.json"
@@ -80,4 +158,4 @@
80158
assert result["acceptedProviders"] == ["moviesdrive"], result
81159
assert result["policy"]["freshNativeReaderProofRequired"] is True
82160

83-
print("native reader Brain repair sandbox tests passed")
161+
print("native reader Brain repair cross-client safety tests passed")

0 commit comments

Comments
 (0)