fable-engine 1.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. fable_compressor.py +356 -0
  2. fable_engine/__init__.py +1 -0
  3. fable_engine/actions/__init__.py +291 -0
  4. fable_engine/actions/cas.py +182 -0
  5. fable_engine/actions/deliberation.py +523 -0
  6. fable_engine/actions/fleet.py +807 -0
  7. fable_engine/actions/lifecycle.py +298 -0
  8. fable_engine/actions/scrapers.py +116 -0
  9. fable_engine/actions/system3.py +815 -0
  10. fable_engine/browser.py +824 -0
  11. fable_engine/cas.py +974 -0
  12. fable_engine/fable_session.json +510 -0
  13. fable_engine/guards.py +283 -0
  14. fable_engine/schema.py +714 -0
  15. fable_engine/scrapers/__init__.py +32 -0
  16. fable_engine/scrapers/arxiv.py +115 -0
  17. fable_engine/scrapers/base.py +386 -0
  18. fable_engine/scrapers/github.py +129 -0
  19. fable_engine/scrapers/reddit.py +154 -0
  20. fable_engine/scrapers/web.py +120 -0
  21. fable_engine/scrapers/x.py +125 -0
  22. fable_engine/scrapers/youtube.py +132 -0
  23. fable_engine/server.py +414 -0
  24. fable_engine/session.py +1819 -0
  25. fable_engine/test_server.py +1362 -0
  26. fable_engine/updater.py +541 -0
  27. fable_engine-1.3.1.dist-info/LICENSE +22 -0
  28. fable_engine-1.3.1.dist-info/METADATA +173 -0
  29. fable_engine-1.3.1.dist-info/RECORD +104 -0
  30. fable_engine-1.3.1.dist-info/WHEEL +5 -0
  31. fable_engine-1.3.1.dist-info/entry_points.txt +5 -0
  32. fable_engine-1.3.1.dist-info/top_level.txt +6 -0
  33. fable_mode/__init__.py +3 -0
  34. fable_mode/__main__.py +4 -0
  35. fable_mode/adapters.py +1014 -0
  36. fable_mode/installer.py +553 -0
  37. fable_mode/launcher.py +437 -0
  38. fable_mode/manifest.py +142 -0
  39. fable_mode/resources.json +114 -0
  40. fable_mode/safety.py +103 -0
  41. fable_mode_entry.py +10 -0
  42. fable_v2/__init__.py +146 -0
  43. fable_v2/adapters.py +151 -0
  44. fable_v2/coder_fleet/__init__.py +100 -0
  45. fable_v2/coder_fleet/ast_tools.py +158 -0
  46. fable_v2/coder_fleet/compute.py +199 -0
  47. fable_v2/coder_fleet/design_engine.py +1316 -0
  48. fable_v2/coder_fleet/diagnostics.py +293 -0
  49. fable_v2/coder_fleet/fleet_dispatcher.py +214 -0
  50. fable_v2/coder_fleet/mock_auditor.py +306 -0
  51. fable_v2/coder_fleet/mutation.py +216 -0
  52. fable_v2/coder_fleet/property_oracle.py +260 -0
  53. fable_v2/coder_fleet/receipt_attestor.py +122 -0
  54. fable_v2/coder_fleet/red_team_swarm.py +908 -0
  55. fable_v2/coder_fleet/test_harness.py +198 -0
  56. fable_v2/coder_fleet/vector_engine.py +1287 -0
  57. fable_v2/coder_fleet/visual.py +357 -0
  58. fable_v2/coder_fleet/workspace.py +153 -0
  59. fable_v2/cortical/__init__.py +20 -0
  60. fable_v2/cortical/plasticity_engine.py +992 -0
  61. fable_v2/execution_broker.py +811 -0
  62. fable_v2/proof_engine.py +1141 -0
  63. fable_v2/protocol.py +485 -0
  64. fable_v2/runtime.py +1010 -0
  65. fable_v2/system3/__init__.py +204 -0
  66. fable_v2/system3/causal.py +558 -0
  67. fable_v2/system3/dialectical.py +577 -0
  68. fable_v2/system3/evolution.py +503 -0
  69. fable_v2/system3/executive.py +338 -0
  70. fable_v2/system3/free_energy.py +479 -0
  71. fable_v2/system3/hyperbolic.py +555 -0
  72. fable_v2/system3/induction.py +336 -0
  73. fable_v2/system3/kripke.py +548 -0
  74. fable_v2/system3/oracle.py +745 -0
  75. fable_v2/verifiers.py +72 -0
  76. tests/__init__.py +1 -0
  77. tests/test_anti_loop_circuit_breaker.py +64 -0
  78. tests/test_auto_updater.py +407 -0
  79. tests/test_coder_fleet.py +535 -0
  80. tests/test_delegation_compiler.py +54 -0
  81. tests/test_descriptor_boundaries.py +126 -0
  82. tests/test_design_engine.py +603 -0
  83. tests/test_epistemic_evidence_validator.py +66 -0
  84. tests/test_execution_broker.py +233 -0
  85. tests/test_fable_v2.py +406 -0
  86. tests/test_fleet_transitions.py +116 -0
  87. tests/test_fsm_redteam_evolution.py +406 -0
  88. tests/test_goal_rubric_and_pipeline.py +367 -0
  89. tests/test_hebbian_plasticity.py +585 -0
  90. tests/test_packaging_runtime.py +194 -0
  91. tests/test_proof_engine.py +259 -0
  92. tests/test_red_team_swarm.py +645 -0
  93. tests/test_redteam_remediation.py +169 -0
  94. tests/test_registration_transaction.py +375 -0
  95. tests/test_requested_regressions.py +467 -0
  96. tests/test_scrapers.py +370 -0
  97. tests/test_server_actions.py +93 -0
  98. tests/test_server_frontier_actions.py +269 -0
  99. tests/test_server_protocol.py +88 -0
  100. tests/test_stealth_browser.py +970 -0
  101. tests/test_system3.py +381 -0
  102. tests/test_system3_deep_integration.py +385 -0
  103. tests/test_system3_frontier.py +436 -0
  104. tests/test_vector_engine.py +608 -0
@@ -0,0 +1,436 @@
1
+ """Comprehensive Unit & Verification Test Suite for Frontier System 3 Transcendence Engine.
2
+
3
+ Tests:
4
+ 1. Poincaré Hyperbolic Manifold (Metric tensor, Möbius addition, Exp/Log maps, Tree embeddings, Distortion)
5
+ 2. Kripke Modal Model Checker (CTL* temporal operators: AG, EF, AF, AX, EX, EG, EU, AU; Box/Diamond; Witness & Counterexample traces)
6
+ 3. Friston Active Inference Engine (Variational Free Energy F = Complexity - Accuracy, Expected Free Energy G, Policy Selection)
7
+ 4. Gödelian Proof Oracle (Curry-Howard Isomorphism, Constructive Type Checking, Tactic Synthesis, Incompleteness / Paradox boundaries)
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import unittest
13
+ import math
14
+ import json
15
+
16
+ from fable_v2.system3 import (
17
+ # Hyperbolic
18
+ PoincareBall,
19
+ HyperbolicPoint,
20
+ HyperbolicTreeEmbedder,
21
+ TreeEmbeddingNode,
22
+ TreeEmbeddingResult,
23
+ HyperbolicGeometryError,
24
+ # Kripke
25
+ KripkeStructure,
26
+ KripkeWorld,
27
+ KripkeModelChecker,
28
+ ModelCheckResult,
29
+ CTLOperator,
30
+ FormulaNode,
31
+ FormulaParser,
32
+ # Free Energy
33
+ ActiveInferenceEngine,
34
+ GenerativeModel,
35
+ Policy,
36
+ PolicyEvaluation,
37
+ FreeEnergyReport,
38
+ create_default_architecture_pomdp,
39
+ # Oracle
40
+ ProofOracle,
41
+ CurryHowardVerifier,
42
+ UndecidabilityDetector,
43
+ TacticsEngine,
44
+ FormalProofResult,
45
+ ProofStatus,
46
+ Type,
47
+ Term,
48
+ Prop,
49
+ Unit,
50
+ Void,
51
+ Implies,
52
+ And,
53
+ Or,
54
+ Not,
55
+ Eq,
56
+ Var,
57
+ Lam,
58
+ App,
59
+ Pair,
60
+ Fst,
61
+ Snd,
62
+ Inl,
63
+ Inr,
64
+ Case,
65
+ Refl,
66
+ Abort,
67
+ )
68
+
69
+
70
+ class TestPoincareHyperbolicManifold(unittest.TestCase):
71
+ """Unit tests for Poincaré Ball hyperbolic geometry and tree embeddings."""
72
+
73
+ def setUp(self):
74
+ self.manifold = PoincareBall(dimension=2, curvature=1.0)
75
+
76
+ def test_point_creation_and_clamping(self):
77
+ p1 = HyperbolicPoint(coords=(0.2, 0.3), curvature=1.0)
78
+ self.assertEqual(p1.dimension, 2)
79
+ self.assertAlmostEqual(p1.norm, math.sqrt(0.04 + 0.09), places=5)
80
+
81
+ # Out-of-bounds point should be automatically clamped inside unit disk
82
+ p_out = HyperbolicPoint(coords=(1.5, 0.0), curvature=1.0)
83
+ self.assertLess(p_out.norm, 1.0)
84
+
85
+ # Invalid curvature should raise
86
+ with self.assertRaises(ValueError):
87
+ HyperbolicPoint(coords=(0.1, 0.1), curvature=-1.0)
88
+
89
+ def test_conformal_factor_and_metric_tensor(self):
90
+ origin = (0.0, 0.0)
91
+ lam_0 = self.manifold.conformal_factor(origin)
92
+ self.assertAlmostEqual(lam_0, 2.0, places=5)
93
+
94
+ tensor_0 = self.manifold.metric_tensor(origin)
95
+ self.assertEqual(tensor_0, [[4.0, 0.0], [0.0, 4.0]])
96
+
97
+ # Near boundary, conformal factor grows to infinity
98
+ p_near = (0.9, 0.0)
99
+ lam_near = self.manifold.conformal_factor(p_near)
100
+ self.assertAlmostEqual(lam_near, 2.0 / (1.0 - 0.81), places=4)
101
+ self.assertGreater(lam_near, 10.0)
102
+
103
+ def test_mobius_addition_algebra(self):
104
+ x = (0.3, 0.2)
105
+ y = (-0.1, 0.4)
106
+ zero = (0.0, 0.0)
107
+
108
+ # Identity: x (+) 0 = x
109
+ x_plus_zero = self.manifold.mobius_add(x, zero)
110
+ self.assertAlmostEqual(x_plus_zero[0], x[0], places=5)
111
+ self.assertAlmostEqual(x_plus_zero[1], x[1], places=5)
112
+
113
+ # Inverse: x (+) (-x) = 0
114
+ neg_x = (-x[0], -x[1])
115
+ x_plus_neg_x = self.manifold.mobius_add(x, neg_x)
116
+ self.assertAlmostEqual(x_plus_neg_x[0], 0.0, places=5)
117
+ self.assertAlmostEqual(x_plus_neg_x[1], 0.0, places=5)
118
+
119
+ # Subtraction: x (-) x = 0
120
+ x_sub_x = self.manifold.mobius_sub(x, x)
121
+ self.assertAlmostEqual(x_sub_x[0], 0.0, places=5)
122
+ self.assertAlmostEqual(x_sub_x[1], 0.0, places=5)
123
+
124
+ def test_distance_and_geodesic_properties(self):
125
+ x = (0.0, 0.0)
126
+ y = (0.5, 0.0)
127
+ d_xy = self.manifold.distance(x, y)
128
+ # Distance from origin in Poincare disk: 2 * artanh(||y||) = 2 * artanh(0.5) = ln(3) ~ 1.0986
129
+ expected_d = 2.0 * math.atanh(0.5)
130
+ self.assertAlmostEqual(d_xy, expected_d, places=5)
131
+
132
+ # Symmetry: d(x, y) == d(y, x)
133
+ d_yx = self.manifold.distance(y, x)
134
+ self.assertAlmostEqual(d_xy, d_yx, places=5)
135
+
136
+ # Triangle Inequality: d(x, z) <= d(x, y) + d(y, z)
137
+ z = (0.2, 0.6)
138
+ d_xz = self.manifold.distance(x, z)
139
+ d_yz = self.manifold.distance(y, z)
140
+ self.assertLessEqual(d_xz, d_xy + d_yz + 1e-6)
141
+
142
+ def test_exp_and_log_maps_roundtrip(self):
143
+ x = (0.2, -0.1)
144
+ v = (0.3, 0.4)
145
+
146
+ # Exponential map maps tangent vector to manifold
147
+ y = self.manifold.exp_map(x, v)
148
+ self.assertLess(math.sqrt(y[0]**2 + y[1]**2), 1.0)
149
+
150
+ # Logarithmic map recovers original tangent vector
151
+ v_recovered = self.manifold.log_map(x, y)
152
+ self.assertAlmostEqual(v_recovered[0], v[0], places=4)
153
+ self.assertAlmostEqual(v_recovered[1], v[1], places=4)
154
+
155
+ def test_geodesic_interpolation(self):
156
+ x = (-0.4, 0.2)
157
+ y = (0.3, -0.5)
158
+
159
+ # Midpoint gamma(0.5)
160
+ mid = self.manifold.geodesic_interpolate(x, y, 0.5)
161
+ d_total = self.manifold.distance(x, y)
162
+ d_x_mid = self.manifold.distance(x, mid)
163
+ d_mid_y = self.manifold.distance(mid, y)
164
+
165
+ self.assertAlmostEqual(d_x_mid, d_total / 2.0, places=4)
166
+ self.assertAlmostEqual(d_mid_y, d_total / 2.0, places=4)
167
+
168
+ def test_hyperbolic_tree_embedder(self):
169
+ embedder = HyperbolicTreeEmbedder(dimension=2, curvature=1.0, base_step_distance=1.0)
170
+
171
+ # Construct tree hierarchy
172
+ tree = {
173
+ "root": ["arch", "broker", "verifier"],
174
+ "arch": ["causal", "dialectical"],
175
+ "broker": ["policy", "runtime"],
176
+ "verifier": ["function", "composite"],
177
+ }
178
+ labels = {"root": "FableMode", "arch": "System3", "broker": "Broker", "verifier": "Verifiers"}
179
+
180
+ res = embedder.embed_hierarchy(tree, root_id="root", node_labels=labels)
181
+ self.assertEqual(res.total_nodes, 10)
182
+ self.assertEqual(res.tree_depth, 2)
183
+ self.assertEqual(res.root_id, "root")
184
+
185
+ # Root at origin
186
+ self.assertEqual(res.nodes["root"].coords, (0.0, 0.0))
187
+
188
+ # Children are strictly within Poincaré open disk
189
+ for nid, node in res.nodes.items():
190
+ norm = math.sqrt(sum(c * c for c in node.coords))
191
+ self.assertLess(norm, 1.0)
192
+
193
+ # Stress and distortion should be reasonably bounded
194
+ self.assertGreaterEqual(res.average_distortion, 0.0)
195
+ self.assertGreaterEqual(res.hierarchical_capacity_ratio, 1.0)
196
+
197
+ # Serialization roundtrip
198
+ d = res.to_dict()
199
+ restored = TreeEmbeddingResult.from_dict(d)
200
+ self.assertEqual(restored.total_nodes, res.total_nodes)
201
+ self.assertEqual(restored.root_id, res.root_id)
202
+
203
+
204
+ class TestKripkeModalModelChecker(unittest.TestCase):
205
+ """Unit tests for Kripke Structure, Multi-World Semantics, and CTL Model Checking."""
206
+
207
+ def setUp(self):
208
+ self.ks = KripkeStructure(name="System3SafetyProtocol")
209
+ # Worlds
210
+ self.ks.add_world("s0_init", ["ready", "safe"], is_initial=True)
211
+ self.ks.add_world("s1_deliberating", ["safe", "locked"])
212
+ self.ks.add_world("s2_unlocked", ["safe", "can_execute"])
213
+ self.ks.add_world("s3_done", ["safe", "complete"])
214
+ self.ks.add_world("s_error", ["error"])
215
+
216
+ # Transitions (Safe path: s0 -> s1 -> s2 -> s3 -> s3; Error branch: s1 -> s_error)
217
+ self.ks.add_transition("s0_init", "s1_deliberating")
218
+ self.ks.add_transition("s1_deliberating", "s2_unlocked")
219
+ self.ks.add_transition("s2_unlocked", "s3_done")
220
+ self.ks.add_transition("s3_done", "s3_done") # Self loop
221
+ self.ks.add_transition("s_error", "s_error")
222
+
223
+ self.checker = KripkeModelChecker(self.ks)
224
+
225
+ def test_formula_parser(self):
226
+ f1 = FormulaParser.parse("AG(safe)")
227
+ self.assertEqual(f1.op, CTLOperator.AG)
228
+ self.assertEqual(f1.left.op, CTLOperator.ATOM)
229
+ self.assertEqual(f1.left.name, "safe")
230
+
231
+ f2 = FormulaParser.parse("and(ready, safe)")
232
+ self.assertEqual(f2.op, CTLOperator.AND)
233
+ self.assertEqual(f2.left.name, "ready")
234
+ self.assertEqual(f2.right.name, "safe")
235
+
236
+ f3 = FormulaParser.parse("E[safe U complete]")
237
+ self.assertEqual(f3.op, CTLOperator.EU)
238
+ self.assertEqual(f3.left.name, "safe")
239
+ self.assertEqual(f3.right.name, "complete")
240
+
241
+ f4 = FormulaParser.parse("box(safe)")
242
+ self.assertEqual(f4.op, CTLOperator.BOX)
243
+
244
+ def test_modal_operators_box_and_diamond(self):
245
+ # In s0_init, all successors (s1_deliberating) have 'safe' -> Box(safe) holds
246
+ res_box = self.checker.check("box(safe)", initial_world="s0_init")
247
+ self.assertTrue(res_box.is_satisfied)
248
+
249
+ # In s0_init, diamond(locked) holds because s1_deliberating has 'locked'
250
+ res_dia = self.checker.check("diamond(locked)", initial_world="s0_init")
251
+ self.assertTrue(res_dia.is_satisfied)
252
+
253
+ def test_ctl_temporal_invariants(self):
254
+ # 1. AG(safe) from s0_init should be TRUE (s_error is unreachable from s0_init)
255
+ res_ag = self.checker.check("AG(safe)", initial_world="s0_init")
256
+ self.assertTrue(res_ag.is_satisfied)
257
+
258
+ # 2. EF(complete) from s0_init should be TRUE (s0 -> s1 -> s2 -> s3)
259
+ res_ef = self.checker.check("EF(complete)", initial_world="s0_init")
260
+ self.assertTrue(res_ef.is_satisfied)
261
+ self.assertIsNotNone(res_ef.witness_path)
262
+ self.assertEqual(res_ef.witness_path[0], "s0_init")
263
+ self.assertEqual(res_ef.witness_path[-1], "s3_done")
264
+
265
+ # 3. AF(complete) from s0_init should be TRUE
266
+ res_af = self.checker.check("AF(complete)", initial_world="s0_init")
267
+ self.assertTrue(res_af.is_satisfied)
268
+
269
+ # 4. AX(locked) from s0_init should be TRUE (next state is s1_deliberating)
270
+ res_ax = self.checker.check("AX(locked)", initial_world="s0_init")
271
+ self.assertTrue(res_ax.is_satisfied)
272
+
273
+ # 5. E[safe U complete] from s0_init should be TRUE
274
+ res_eu = self.checker.check("E[safe U complete]", initial_world="s0_init")
275
+ self.assertTrue(res_eu.is_satisfied)
276
+
277
+ def test_violation_and_counterexample_trace(self):
278
+ # Add transition from s1_deliberating to s_error
279
+ self.ks.add_transition("s1_deliberating", "s_error")
280
+
281
+ # Now AG(safe) fails because s_error is reachable
282
+ res_ag_fail = self.checker.check("AG(safe)", initial_world="s0_init")
283
+ self.assertFalse(res_ag_fail.is_satisfied)
284
+ self.assertIsNotNone(res_ag_fail.counterexample_path)
285
+ self.assertEqual(res_ag_fail.counterexample_path, ["s0_init", "s1_deliberating", "s_error"])
286
+
287
+ # Serialization
288
+ d = res_ag_fail.to_dict()
289
+ restored = ModelCheckResult.from_dict(d)
290
+ self.assertFalse(restored.is_satisfied)
291
+ self.assertEqual(restored.counterexample_path, ["s0_init", "s1_deliberating", "s_error"])
292
+
293
+
294
+ class TestFristonActiveInferenceEngine(unittest.TestCase):
295
+ """Unit tests for Karl Friston's Active Inference & Variational Free Energy."""
296
+
297
+ def setUp(self):
298
+ self.model = create_default_architecture_pomdp()
299
+ self.engine = ActiveInferenceEngine(generative_model=self.model, policy_precision_gamma=16.0)
300
+
301
+ def test_model_initialization_and_normalization(self):
302
+ self.assertEqual(len(self.model.states), 4)
303
+ self.assertEqual(len(self.model.observations), 4)
304
+ self.assertEqual(len(self.model.actions), 4)
305
+
306
+ # Column sums of A matrix must be 1.0
307
+ for s_idx in range(len(self.model.states)):
308
+ col_sum = sum(self.model.a_matrix[o_idx][s_idx] for o_idx in range(len(self.model.observations)))
309
+ self.assertAlmostEqual(col_sum, 1.0, places=5)
310
+
311
+ def test_perception_free_energy_calculation(self):
312
+ # Ingest clean high throughput observation
313
+ f_val, comp_kl, acc_ll = self.engine.update_beliefs("HIGH_THROUGHPUT_CLEAN")
314
+
315
+ # Variational Free Energy F = Complexity - Accuracy
316
+ self.assertAlmostEqual(f_val, comp_kl - acc_ll, places=5)
317
+
318
+ # Belief for OPTIMAL_DECOUPLED should dominate
319
+ opt_idx = self.model.states.index("OPTIMAL_DECOUPLED")
320
+ self.assertGreater(self.engine.current_beliefs[opt_idx], 0.70)
321
+
322
+ def test_action_selection_and_policy_ranking(self):
323
+ # Inject lock contention warning observation
324
+ report = self.engine.select_action(
325
+ observation="LOCK_CONTENTION_WARN",
326
+ candidate_policies=[
327
+ Policy(policy_id="p_shard", actions=["SHARD_WORKERS"]),
328
+ Policy(policy_id="p_refactor", actions=["REFACTOR_MUTEX"]),
329
+ Policy(policy_id="p_cas", actions=["APPLY_CAS_ISOLATION"]),
330
+ Policy(policy_id="p_benchmark", actions=["RUN_BENCHMARK"]),
331
+ ]
332
+ )
333
+
334
+ self.assertEqual(report.current_observation, "LOCK_CONTENTION_WARN")
335
+ self.assertEqual(len(report.evaluated_policies), 4)
336
+
337
+ # Expected Free Energy should favor corrective action
338
+ self.assertIn(report.selected_action, ["SHARD_WORKERS", "REFACTOR_MUTEX", "APPLY_CAS_ISOLATION"])
339
+ self.assertIsNotNone(report.selected_policy)
340
+ self.assertTrue(report.selected_policy.is_optimal)
341
+
342
+ # Probabilities sum to 1.0
343
+ prob_sum = sum(p.probability for p in report.evaluated_policies)
344
+ self.assertAlmostEqual(prob_sum, 1.0, places=5)
345
+
346
+ # Serialization
347
+ d = report.to_dict()
348
+ restored = FreeEnergyReport.from_dict(d)
349
+ self.assertEqual(restored.current_observation, report.current_observation)
350
+ self.assertEqual(restored.selected_action, report.selected_action)
351
+
352
+
353
+ class TestGodelianProofOracle(unittest.TestCase):
354
+ """Unit tests for Gödelian Proof Oracle and Curry-Howard Constructive Type Checker."""
355
+
356
+ def setUp(self):
357
+ self.oracle = ProofOracle(max_search_depth=6)
358
+
359
+ def test_curry_howard_tautologies(self):
360
+ A = Prop("A")
361
+ B = Prop("B")
362
+
363
+ # 1. Identity / Modus Ponens Base: A -> A
364
+ # Proof: \x: A. x
365
+ proof_id = Lam("x", A, Var("x"))
366
+ self.assertTrue(CurryHowardVerifier.check_type(proof_id, Implies(A, A)))
367
+
368
+ # 2. Conjunction Commutativity: (A /\ B) -> (B /\ A)
369
+ # Proof: \p: (A /\ B). <snd p, fst p>
370
+ p_type = And(A, B)
371
+ proof_comm = Lam("p", p_type, Pair(Snd(Var("p")), Fst(Var("p"))))
372
+ self.assertTrue(CurryHowardVerifier.check_type(proof_comm, Implies(p_type, And(B, A))))
373
+
374
+ # 3. Disjunction Commutativity: (A \/ B) -> (B \/ A)
375
+ # Proof: \s: (A \/ B). case s of inl a => inr a | inr b => inl b
376
+ s_type = Or(A, B)
377
+ target_sum = Or(B, A)
378
+ proof_or_comm = Lam(
379
+ "s", s_type,
380
+ Case(
381
+ Var("s"),
382
+ "a", Inr(Var("a"), target_sum),
383
+ "b", Inl(Var("b"), target_sum),
384
+ )
385
+ )
386
+ self.assertTrue(CurryHowardVerifier.check_type(proof_or_comm, Implies(s_type, target_sum)))
387
+
388
+ def test_automatic_tactic_synthesis(self):
389
+ # Auto-prove A -> (B -> A)
390
+ A = Prop("A")
391
+ B = Prop("B")
392
+ goal = Implies(A, Implies(B, A))
393
+
394
+ res = self.oracle.verify_proposition(goal)
395
+ self.assertEqual(res.status, ProofStatus.DECIDABLE_PROVED)
396
+ self.assertTrue(res.is_sound)
397
+ self.assertIsNotNone(res.proof_term)
398
+
399
+ # Auto-prove equality: safe == safe
400
+ eq_goal = Eq("safe", "safe")
401
+ res_eq = self.oracle.verify_proposition(eq_goal)
402
+ self.assertEqual(res_eq.status, ProofStatus.DECIDABLE_PROVED)
403
+ self.assertTrue(res_eq.is_sound)
404
+
405
+ def test_refutation_of_contradictory_claims(self):
406
+ A = Prop("A")
407
+ # Context has A and ~A (A -> Void)
408
+ # Claim: Void -> goal should succeed or refuting A
409
+ ctx = {"h1": A, "h2": Not(A)}
410
+ res = self.oracle.verify_proposition(claim="P", context=ctx)
411
+ self.assertEqual(res.status, ProofStatus.DECIDABLE_PROVED) # Proved via ex falso quodlibet from context contradiction
412
+
413
+ def test_godelian_undecidability_and_paradox_detection(self):
414
+ # 1. Liar Paradox claim
415
+ res_liar = self.oracle.verify_proposition("Liar_Self_Negation_Paradox")
416
+ self.assertEqual(res_liar.status, ProofStatus.INDEPENDENT_UNDECIDABLE)
417
+ self.assertFalse(res_liar.is_sound)
418
+ self.assertIsNotNone(res_liar.undecidability_diagnostics)
419
+
420
+ # 2. Gödel sentence claim
421
+ res_godel = self.oracle.verify_proposition("Godel_Unprovable_Sentence")
422
+ self.assertEqual(res_godel.status, ProofStatus.INDEPENDENT_UNDECIDABLE)
423
+ self.assertIn("GODELIAN", res_godel.undecidability_diagnostics.get("boundary_type", ""))
424
+
425
+ # 3. Halting problem reduction
426
+ res_halt = self.oracle.verify_proposition("Turing_Diagonal_Halts_Predicate")
427
+ self.assertEqual(res_halt.status, ProofStatus.INDEPENDENT_UNDECIDABLE)
428
+
429
+ # Serialization
430
+ d = res_godel.to_dict()
431
+ restored = FormalProofResult.from_dict(d)
432
+ self.assertEqual(restored.status, ProofStatus.INDEPENDENT_UNDECIDABLE)
433
+
434
+
435
+ if __name__ == "__main__":
436
+ unittest.main(verbosity=2)