jeanbatuli commited on
Commit
7494edd
·
verified ·
1 Parent(s): 41cdf0b

Sync from GitHub main

Browse files
Files changed (1) hide show
  1. tests/test_evidence.py +98 -0
tests/test_evidence.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import unittest
4
+
5
+ from limen_runtime_audit.evidence import EvidenceRun
6
+
7
+
8
+ class TestEvidenceChain(unittest.TestCase):
9
+ def _build_run(self, profile: str = "generation_probability") -> EvidenceRun:
10
+ run = EvidenceRun(capture_profile=profile)
11
+ for i in range(3):
12
+ step = run.new_step()
13
+ step.set_channel("generation", "AVAILABLE", {"token_id": 100 + i})
14
+ step.set_channel("probability", "AVAILABLE", {"entropy_nats": 0.5 + i})
15
+ step.set_channel("latent", "NOT_CAPTURED", note="profile does not request latent")
16
+ run.append(step)
17
+ return run
18
+
19
+ def test_valid_chain_verifies(self) -> None:
20
+ run = self._build_run()
21
+ ok, broken_at = run.verify_chain()
22
+ self.assertTrue(ok)
23
+ self.assertIsNone(broken_at)
24
+
25
+ def test_tamper_detected(self) -> None:
26
+ """Mirrors the project's own kill-test discipline: editing a sealed
27
+ step's payload after the fact must break the chain, not pass
28
+ silently."""
29
+ run = self._build_run()
30
+ tampered = run.steps[1]
31
+ tampered.channels["generation"].value["token_id"] = 999999
32
+ ok, broken_at = run.verify_chain()
33
+ self.assertFalse(ok)
34
+ self.assertEqual(broken_at, run.steps[1].event_id)
35
+
36
+ def test_reorder_detected(self) -> None:
37
+ """Shuffling step order must also be caught, since identity and
38
+ chaining are explicit, never inferred from array position."""
39
+ run = self._build_run()
40
+ run.steps[0], run.steps[1] = run.steps[1], run.steps[0]
41
+ ok, broken_at = run.verify_chain()
42
+ self.assertFalse(ok)
43
+
44
+ def test_not_captured_excluded_from_denominator(self) -> None:
45
+ run = self._build_run(profile="generation_probability")
46
+ cov = run.coverage()
47
+ # latent is NOT_CAPTURED and not in this profile's expected set, so
48
+ # it must not appear in expected_channels or reduce coverage.
49
+ self.assertNotIn("latent", cov["expected_channels"])
50
+ self.assertEqual(cov["available"], cov["expected_total"])
51
+ self.assertEqual(cov["coverage_fraction"], 1.0)
52
+
53
+ def test_failed_channel_is_flagged_not_silently_zero(self) -> None:
54
+ run = EvidenceRun(capture_profile="generation_probability")
55
+ step = run.new_step()
56
+ step.set_channel("generation", "AVAILABLE", {"token_id": 1})
57
+ step.set_channel("probability", "FAILED", note="backend returned no logits")
58
+ run.append(step)
59
+ cov = run.coverage()
60
+ self.assertEqual(cov["available"], 1)
61
+ self.assertEqual(cov["expected_total"], 2)
62
+ self.assertIn(f"{step.event_id}:probability", cov["failed_events"])
63
+
64
+ def test_available_channel_requires_value(self) -> None:
65
+ run = EvidenceRun(capture_profile="generation_only")
66
+ step = run.new_step()
67
+ with self.assertRaises(ValueError):
68
+ step.set_channel("generation", "AVAILABLE", value=None)
69
+
70
+ def test_absent_channel_must_not_carry_value(self) -> None:
71
+ run = EvidenceRun(capture_profile="generation_only")
72
+ step = run.new_step()
73
+ with self.assertRaises(ValueError):
74
+ step.set_channel("generation", "NOT_CAPTURED", value={"token_id": 1})
75
+
76
+ def test_out_of_order_step_rejected(self) -> None:
77
+ run = EvidenceRun(capture_profile="generation_only")
78
+ step0 = run.new_step()
79
+ step0.set_channel("generation", "AVAILABLE", {"token_id": 1})
80
+ run.append(step0)
81
+ # Manually construct a step with a wrong index to simulate a bug
82
+ # that would otherwise silently desynchronize identity.
83
+ from limen_runtime_audit.evidence import EvidenceStep
84
+
85
+ bad_step = EvidenceStep(run_id=run.run_id, step_index=5)
86
+ bad_step.set_channel("generation", "AVAILABLE", {"token_id": 2})
87
+ with self.assertRaises(ValueError):
88
+ run.append(bad_step)
89
+
90
+ def test_to_dict_reports_chain_integrity(self) -> None:
91
+ run = self._build_run()
92
+ out = run.to_dict()
93
+ self.assertTrue(out["chain_integrity"]["valid"])
94
+ self.assertEqual(out["coverage"]["available"], 6)
95
+
96
+
97
+ if __name__ == "__main__":
98
+ unittest.main()