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,1362 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Comprehensive Unit and Integration Test Suite for Fable-Engine MCP Server.
4
+ Tests:
5
+ - Core session data structures & invariants
6
+ - Anti-rush execution lockout logic & cognitive gating validation
7
+ - Immutable authority time-lock enforcement & host-only emergency overrides
8
+ - Continuous rethink-refine cycle tracking & telemetry
9
+ - Epistemic ledger tracking (PROVEN, HYPOTHESIS, UNKNOWN)
10
+ - Formal invariant modeling
11
+ - Immutable authority deadlines and agent-only pacing telemetry
12
+ - Persistence, atomic checkpointing, and restoration
13
+ - Dispatch handler operations and edge-case handling
14
+ - Full JSON-RPC 2.0 stdio MCP server protocol over subprocess
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import sys
20
+ import os
21
+ import json
22
+ import time
23
+ import subprocess
24
+ import threading
25
+ import unittest
26
+ import tempfile
27
+ import shutil
28
+ from pathlib import Path
29
+
30
+ class FakeClock:
31
+ """Deterministic wall and monotonic clocks for lock tests."""
32
+
33
+ def __init__(self):
34
+ self.wall = time.time()
35
+ self.mono = time.monotonic()
36
+
37
+ def time(self):
38
+ return self.wall
39
+
40
+ def monotonic(self):
41
+ return self.mono
42
+
43
+ def advance(self, seconds):
44
+ self.wall += seconds
45
+ self.mono += seconds
46
+
47
+
48
+ # Add current directory to path
49
+ CURRENT_DIR = Path(__file__).resolve().parent
50
+ if str(CURRENT_DIR) not in sys.path:
51
+ sys.path.insert(0, str(CURRENT_DIR))
52
+
53
+ from server import (
54
+ FableSession,
55
+ ACTIVE_SESSIONS,
56
+ SESSIONS_DIR,
57
+ PHASES,
58
+ PHASE_INDEX_MAP,
59
+ handle_fable_session,
60
+ TOOL_SCHEMA,
61
+ FableCASError,
62
+ IntegrityError,
63
+ CASNotFoundError,
64
+ ThreadSafeLRUCache,
65
+ FableCASStore,
66
+ CompositeFrame,
67
+ AdaptiveChunkAccumulator,
68
+ FableGrammar333,
69
+ CASSliceViewer,
70
+ FableCompress,
71
+ CAS_ENGINE
72
+ )
73
+
74
+
75
+ class TestFableSessionCore(unittest.TestCase):
76
+ """Tests core FableSession lifecycle, telemetry, refinement cycles, and anti-rush gates."""
77
+
78
+ def setUp(self):
79
+ self.clock = FakeClock()
80
+ self.session_name = f"test_unit_{int(time.time() * 1000)}"
81
+ self.session = FableSession(
82
+ session_name=self.session_name,
83
+ objective="Architect a lock-free multi-producer ring buffer",
84
+ time_budget_minutes=45.0,
85
+ wall_clock=self.clock.time,
86
+ monotonic_clock=self.clock.monotonic
87
+ )
88
+
89
+ def tearDown(self):
90
+ # Cleanup test session files if any
91
+ target_file = SESSIONS_DIR / f"{self.session_name}.json"
92
+ if target_file.exists():
93
+ try:
94
+ target_file.unlink()
95
+ except Exception:
96
+ pass
97
+ if self.session_name in ACTIVE_SESSIONS:
98
+ del ACTIVE_SESSIONS[self.session_name]
99
+
100
+ def test_initialization_defaults(self):
101
+ """Verifies session initializes in locked state with proper phase, pacing, and refinement structures."""
102
+ self.assertEqual(self.session.session_name, self.session_name)
103
+ self.assertTrue(self.session.execution_locked)
104
+ self.assertFalse(self.session.can_execute_code)
105
+ self.assertEqual(self.session.active_phase, "Phase 1: Epistemic Grounding & Live Research")
106
+ self.assertEqual(self.session.time_budget_minutes, 45.0)
107
+ self.assertEqual(self.session.time_budget_seconds, 2700.0)
108
+ self.assertEqual(len(self.session.epistemic_ledger), 0)
109
+ self.assertEqual(len(self.session.invariants), 0)
110
+ self.assertEqual(len(self.session.refinement_cycles), 0)
111
+ self.assertEqual(len(self.session.phase_history), 1)
112
+
113
+ tel = self.session.get_telemetry()
114
+ self.assertEqual(tel["refinement_count"], 0)
115
+ self.assertEqual(tel["refinement_cycles"], [])
116
+
117
+ def test_timer_adjustment_is_pacing_only(self):
118
+ """An agent sub-timer cannot shorten the authority deadline."""
119
+ authority_deadline = self.session.deadline_time
120
+ tel = self.session.set_timer(20.0)
121
+ self.assertEqual(self.session.time_budget_minutes, 45.0)
122
+ self.assertEqual(self.session.time_budget_seconds, 2700.0)
123
+ self.assertEqual(self.session.pacing_budget_minutes, 20.0)
124
+ self.assertEqual(self.session.deadline_time, authority_deadline)
125
+ self.assertLess(self.session.pacing_deadline_time, authority_deadline)
126
+ self.assertIn("authority_remaining_formatted", tel)
127
+ self.assertIn("pacing_remaining_formatted", tel)
128
+ self.assertIn("cognitive_gates", tel)
129
+
130
+ def test_epistemic_ledger_logging(self):
131
+ """Verifies logging fact, hypothesis, and unknown items."""
132
+ item1 = self.session.log_epistemic_item("PROVEN", "Ring buffer power of 2 size allows bitwise mask", f"{__file__}:L42")
133
+ self.assertEqual(item1["id"], "epi_001")
134
+ self.assertEqual(item1["tag"], "PROVEN")
135
+ self.assertEqual(item1["evidence"], f"{__file__}:L42")
136
+
137
+ item2 = self.session.log_epistemic_item("HYPOTHESIS", "Acquire-Release fences suffice for x86 TSO")
138
+ self.assertEqual(item2["id"], "epi_002")
139
+ self.assertEqual(item2["tag"], "HYPOTHESIS")
140
+
141
+ item3 = self.session.log_epistemic_item("UNKNOWN", "Cache line size on target ARM64 architecture")
142
+ self.assertEqual(item3["id"], "epi_003")
143
+ self.assertEqual(item3["tag"], "UNKNOWN")
144
+
145
+ # Invalid tag test
146
+ with self.assertRaises(ValueError):
147
+ self.session.log_epistemic_item("INVALID_TAG", "Some statement")
148
+
149
+ # Empty claim test
150
+ with self.assertRaises(ValueError):
151
+ self.session.log_epistemic_item("PROVEN", " ")
152
+
153
+ tel = self.session.get_telemetry()
154
+ self.assertEqual(tel["epistemic_counts"]["proven"], 1)
155
+ self.assertEqual(tel["epistemic_counts"]["hypothesis"], 1)
156
+ self.assertEqual(tel["epistemic_counts"]["unknown"], 1)
157
+ self.assertEqual(tel["epistemic_counts"]["total"], 3)
158
+
159
+ def test_invariant_recording(self):
160
+ """Verifies formal invariant recording across domains."""
161
+ inv = self.session.record_invariant(
162
+ invariant_name="INV-01: Head-Tail Boundedness",
163
+ formal_statement="0 <= (head - tail) <= BUFFER_CAPACITY at all times",
164
+ proof_or_rationale="Enforced via CAS atomic operations with modulo mask",
165
+ domain="architecture"
166
+ )
167
+ self.assertEqual(inv["id"], "inv_001")
168
+ self.assertEqual(inv["name"], "INV-01: Head-Tail Boundedness")
169
+ self.assertEqual(inv["domain"], "architecture")
170
+
171
+ # Empty fields validation
172
+ with self.assertRaises(ValueError):
173
+ self.session.record_invariant("", "statement", "rationale")
174
+ with self.assertRaises(ValueError):
175
+ self.session.record_invariant("name", "", "rationale")
176
+
177
+ def test_refinement_cycle_logging(self):
178
+ """Verifies logging structured rethink-refine cycles with probes and artifacts."""
179
+ cycle1 = self.session.log_refinement_cycle(
180
+ refinement_type="archetype_exploration",
181
+ focus_area="Memory Partitioning",
182
+ critique_or_bottleneck="Global CAS on tail causes false sharing on multi-socket NUMA",
183
+ architectural_refinement="Partitioned ring buffer into per-core L1 chunks with batch migration",
184
+ terminal_probe_results="10M ops benchmark: 82ns down to 14ns latency",
185
+ artifact_path="C:/Users/test/artifacts/partitioned_buffer.md"
186
+ )
187
+ self.assertEqual(cycle1["cycle_number"], 1)
188
+ self.assertEqual(cycle1["refinement_type"], "archetype_exploration")
189
+ self.assertEqual(cycle1["focus_area"], "Memory Partitioning")
190
+ self.assertIn("Global CAS", cycle1["critique_or_bottleneck"])
191
+ self.assertIn("Partitioned", cycle1["architectural_refinement"])
192
+ self.assertEqual(cycle1["terminal_probe_results"], "10M ops benchmark: 82ns down to 14ns latency")
193
+ self.assertEqual(cycle1["artifact_path"], "C:/Users/test/artifacts/partitioned_buffer.md")
194
+ self.assertEqual(cycle1["phase"], self.session.active_phase)
195
+
196
+ cycle2 = self.session.log_refinement_cycle(
197
+ refinement_type="triz_contradiction_resolution",
198
+ focus_area="Queue Full Backpressure",
199
+ critique_or_bottleneck="Spinning burns CPU while yielding increases p99 latency",
200
+ architectural_refinement="Adaptive exponential backoff with futex sleep fallback"
201
+ )
202
+ self.assertEqual(cycle2["cycle_number"], 2)
203
+ self.assertIsNone(cycle2["terminal_probe_results"])
204
+ self.assertIsNone(cycle2["artifact_path"])
205
+
206
+ # Validate required field errors
207
+ with self.assertRaises(ValueError):
208
+ self.session.log_refinement_cycle("", "Focus", "Critique", "Refinement")
209
+ with self.assertRaises(ValueError):
210
+ self.session.log_refinement_cycle("Type", "", "Critique", "Refinement")
211
+ with self.assertRaises(ValueError):
212
+ self.session.log_refinement_cycle("Type", "Focus", "", "Refinement")
213
+ with self.assertRaises(ValueError):
214
+ self.session.log_refinement_cycle("Type", "Focus", "Critique", "")
215
+
216
+ tel = self.session.get_telemetry()
217
+ self.assertEqual(tel["refinement_count"], 2)
218
+ self.assertEqual(len(tel["refinement_cycles"]), 2)
219
+
220
+ def test_phase_transitions(self):
221
+ """Verifies phase advancement and invalid phase handling."""
222
+ self.session.advance_phase(
223
+ "Phase 2: Invariant Specification & Blueprint",
224
+ "Completed grounding and verified CPU memory model"
225
+ )
226
+ self.assertEqual(self.session.active_phase, "Phase 2: Invariant Specification & Blueprint")
227
+ self.assertEqual(len(self.session.phase_history), 2)
228
+
229
+ # Invalid phase test
230
+ with self.assertRaises(ValueError):
231
+ self.session.advance_phase("Phase 99: Non-existent", "Should fail")
232
+
233
+ def test_hard_time_lock_enforcement(self):
234
+ """
235
+ Verifies Hard Mechanical Time-Lock:
236
+ 1. Fails with PermissionError when the immutable authority deadline is active.
237
+ 2. A public hard-coded token cannot bypass the lock.
238
+ 3. An explicitly configured out-of-band secret can be used for emergency override.
239
+ 4. Succeeds normally when the authority deadline has elapsed.
240
+ """
241
+ # Set up satisfying cognitive gates
242
+ self.session.log_epistemic_item("PROVEN", "Fact 1: Lock-free atomic swap verified", f"{__file__}:L201")
243
+ self.session.log_epistemic_item("PROVEN", "Fact 2: Modulo arithmetic holds", f"{__file__}:L202")
244
+ self.session.record_invariant("INV-01", "tail <= head", "CAS inductive proof")
245
+ for i in range(9):
246
+ self.session.log_refinement_cycle(
247
+ refinement_type="triz_refinement",
248
+ focus_area=f"Contention Area {i}",
249
+ critique_or_bottleneck=f"Bottleneck {i}",
250
+ architectural_refinement=f"Refinement {i}"
251
+ )
252
+ self.session.advance_phase("Phase 2: Invariant Specification & Blueprint", "Advanced to Phase 2")
253
+ self.session.advance_phase("Phase 3: Adversarial Red-Teaming & Falsification", "Advanced to Phase 3")
254
+
255
+ # 1. Timer has not elapsed -> must throw Hard Time-Lock Violation
256
+ with self.assertRaises(PermissionError) as ctx:
257
+ self.session.unlock_execution("Premature attempt before timer finishes")
258
+ self.assertIn("🛑 HARD TIME-LOCK VIOLATION", str(ctx.exception))
259
+ self.assertIn("immutable 45.0m authority budget has not elapsed yet", str(ctx.exception))
260
+ self.assertIn("internal pacing timer cannot unlock execution", str(ctx.exception))
261
+ self.assertIn("Rethink-Refine Cognitive Loop", str(ctx.exception))
262
+
263
+ # 2. The old public hard-coded token must not bypass the lock.
264
+ with self.assertRaises(PermissionError):
265
+ self.session.unlock_execution(
266
+ "Attempted emergency unlock",
267
+ force_override_token="USER_OVERRIDE_FORCE_UNLOCK"
268
+ )
269
+
270
+ # 3. An administrative override works only through the direct host API.
271
+ os.environ["FABLE_FORCE_UNLOCK_TOKEN"] = "test-secret"
272
+ try:
273
+ res = self.session.unlock_execution(
274
+ "Emergency unlock ordered by host administrator",
275
+ force_override_token="test-secret"
276
+ )
277
+ finally:
278
+ os.environ.pop("FABLE_FORCE_UNLOCK_TOKEN", None)
279
+ self.assertEqual(res["status"], "UNLOCKED")
280
+ self.assertTrue(self.session.can_execute_code)
281
+ self.assertTrue(self.session.unlock_details["force_override_used"])
282
+
283
+ # 3. Test elapsed deadline_time without override token
284
+ new_session = FableSession(
285
+ session_name=f"test_elapsed_{int(time.time() * 1000)}",
286
+ objective="Test elapsed clock",
287
+ time_budget_minutes=10.0,
288
+ wall_clock=self.clock.time,
289
+ monotonic_clock=self.clock.monotonic
290
+ )
291
+ new_session.log_epistemic_item("PROVEN", "Fact 1: Lock-free atomic swap verified", f"{__file__}:L229")
292
+ new_session.log_epistemic_item("PROVEN", "Fact 2: Modulo arithmetic holds", f"{__file__}:L230")
293
+ new_session.record_invariant("INV-01", "tail <= head", "CAS inductive proof")
294
+ for i in range(2):
295
+ new_session.log_refinement_cycle(
296
+ refinement_type="triz_refinement",
297
+ focus_area=f"Area {i}",
298
+ critique_or_bottleneck=f"Critique {i}",
299
+ architectural_refinement=f"Refinement {i}"
300
+ )
301
+ new_session.advance_phase("Phase 2: Invariant Specification & Blueprint", "Phase 2 ready")
302
+ new_session.advance_phase("Phase 3: Adversarial Red-Teaming & Falsification", "Phase 3 ready")
303
+
304
+ # Simulate time elapsed past deadline
305
+ self.clock.advance(601.0)
306
+ res = new_session.unlock_execution("Timer has naturally elapsed")
307
+ self.assertEqual(res["status"], "UNLOCKED")
308
+ self.assertTrue(new_session.can_execute_code)
309
+ self.assertFalse(new_session.unlock_details["force_override_used"])
310
+
311
+ def test_anti_rush_lockout_enforcement(self):
312
+ """
313
+ Rigorous test of Anti-Rush Cognitive Lockout Gates:
314
+ Requires:
315
+ 1. >= 2 PROVEN epistemic items
316
+ 2. >= 1 formal invariant
317
+ 3. Active phase >= Phase 3
318
+ """
319
+ # Simulate an elapsed authority deadline so this test isolates cognitive gates.
320
+ self.clock.advance(2701.0)
321
+
322
+ # Attempt 1: In Phase 1 with 0 proven, 0 invariants -> Must fail cognitive gate
323
+ with self.assertRaises(PermissionError) as ctx:
324
+ self.session.unlock_execution("Let me code")
325
+ self.assertIn("Anti-Rush Lockout Active", str(ctx.exception))
326
+ self.assertIn("at least 2 [PROVEN]", str(ctx.exception))
327
+
328
+ # Attempt 2: Add 1 PROVEN item -> Must still fail
329
+ self.session.log_epistemic_item("PROVEN", "Fact 1: Single producer queue is wait-free", f"{__file__}:L259")
330
+ with self.assertRaises(PermissionError) as ctx:
331
+ self.session.unlock_execution("Let me code")
332
+ self.assertIn("at least 2 [PROVEN]", str(ctx.exception))
333
+
334
+ # Attempt 3: Add 2nd PROVEN item, but 0 invariants -> Must still fail
335
+ self.session.log_epistemic_item("PROVEN", "Fact 2: Atomic CAS is supported on target CPU", f"{__file__}:L265")
336
+ with self.assertRaises(PermissionError) as ctx:
337
+ self.session.unlock_execution("Let me code")
338
+ self.assertIn("at least 1 formal Invariant", str(ctx.exception))
339
+
340
+ # Attempt 4: Add invariant, but active phase is Phase 1 -> Must still fail
341
+ self.session.record_invariant(
342
+ "INV-01",
343
+ "tail <= head",
344
+ "Proof by induction",
345
+ "coding"
346
+ )
347
+ with self.assertRaises(PermissionError) as ctx:
348
+ self.session.unlock_execution("Let me code")
349
+ self.assertIn("at least Phase 3", str(ctx.exception))
350
+
351
+ # Attempt 5: Advance to Phase 2 -> Must still fail
352
+ self.session.advance_phase("Phase 2: Invariant Specification & Blueprint", "Drafted blueprints")
353
+ with self.assertRaises(PermissionError) as ctx:
354
+ self.session.unlock_execution("Let me code")
355
+ self.assertIn("at least Phase 3", str(ctx.exception))
356
+
357
+ # Log required refinement cycles (9 required for 45m budget)
358
+ for i in range(9):
359
+ self.session.log_refinement_cycle(
360
+ refinement_type="archetype_exploration",
361
+ focus_area=f"Area {i}",
362
+ critique_or_bottleneck=f"Critique {i}",
363
+ architectural_refinement=f"Refinement {i}"
364
+ )
365
+
366
+ # Attempt 6: Advance to Phase 3 -> Satisfies ALL gates! Must succeed!
367
+ self.session.advance_phase("Phase 3: Adversarial Red-Teaming & Falsification", "Passed red team fuzzing")
368
+ res = self.session.unlock_execution(
369
+ "All invariants proved and red-team checks passed."
370
+ )
371
+
372
+ self.assertEqual(res["status"], "UNLOCKED")
373
+ self.assertFalse(self.session.execution_locked)
374
+ self.assertTrue(self.session.can_execute_code)
375
+ self.assertIsNotNone(self.session.unlock_details)
376
+ self.assertEqual(self.session.unlock_details["proven_count"], 2)
377
+ self.assertEqual(self.session.unlock_details["invariants_count"], 1)
378
+
379
+ def test_pacing_expiry_cannot_unlock(self):
380
+ """A completed internal timer never satisfies the authority lock."""
381
+ self.session.set_timer(2.0)
382
+ self.clock.advance(1.0)
383
+ self.session.log_epistemic_item("PROVEN", "Fact 1: Verified property", f"{__file__}:L1")
384
+ self.session.log_epistemic_item("PROVEN", "Fact 2: Validated cache line", f"{__file__}:L2")
385
+ self.session.record_invariant("INV-01", "tail <= head", "CAS monotonic counter guarantee")
386
+ self.session.advance_phase("Phase 2: Invariant Specification & Blueprint", "Phase 2")
387
+ self.session.advance_phase("Phase 3: Adversarial Red-Teaming & Falsification", "Phase 3")
388
+ with self.assertRaises(PermissionError):
389
+ self.session.unlock_execution("Pacing timer expired")
390
+
391
+ def test_proven_claims_require_evidence(self):
392
+ """A truth label without an evidence pointer is not an admissible gate input."""
393
+ with self.assertRaises(ValueError):
394
+ self.session.log_epistemic_item("PROVEN", "An unreferenced assertion")
395
+
396
+ item = self.session.log_epistemic_item(
397
+ "PROVEN", "A referenced assertion", f"{__file__}:L1"
398
+ )
399
+ self.assertEqual(item["tag"], "PROVEN")
400
+
401
+ def test_invalid_budget_and_session_name_are_rejected(self):
402
+ with self.assertRaises(ValueError):
403
+ FableSession("invalid/escape", "test", 10)
404
+ with self.assertRaises(ValueError):
405
+ FableSession("bad_budget", "test", float("nan"))
406
+ with self.assertRaises(ValueError):
407
+ self.session.set_timer(-1)
408
+
409
+ def test_serialization_and_atomic_save(self):
410
+ """Verifies session dictionary serialization, deserialization, and disk saving including refinement cycles."""
411
+ self.session.log_epistemic_item("PROVEN", "Proven item 1", f"{__file__}:L303")
412
+ self.session.record_invariant("INV-01", "Statement", "Rationale")
413
+ self.session.log_refinement_cycle(
414
+ refinement_type="archetype_exploration",
415
+ focus_area="Cache coherency",
416
+ critique_or_bottleneck="False sharing",
417
+ architectural_refinement="Padding to 64 bytes"
418
+ )
419
+ saved_path = self.session.save()
420
+ self.assertTrue(saved_path.exists())
421
+
422
+ with open(saved_path, "r", encoding="utf-8") as f:
423
+ data = json.load(f)
424
+
425
+ restored = FableSession.from_dict(data)
426
+ self.assertEqual(restored.session_name, self.session.session_name)
427
+ self.assertEqual(len(restored.epistemic_ledger), 1)
428
+ self.assertEqual(len(restored.invariants), 1)
429
+ self.assertEqual(len(restored.refinement_cycles), 1)
430
+ self.assertEqual(restored.refinement_cycles[0]["focus_area"], "Cache coherency")
431
+
432
+
433
+ class TestFableHandlerDispatch(unittest.TestCase):
434
+ """Tests high-level handle_fable_session tool dispatcher."""
435
+
436
+ def setUp(self):
437
+ self.session_name = f"test_dispatch_{int(time.time() * 1000)}"
438
+
439
+ def tearDown(self):
440
+ target_file = SESSIONS_DIR / f"{self.session_name}.json"
441
+ if target_file.exists():
442
+ try:
443
+ target_file.unlink()
444
+ except Exception:
445
+ pass
446
+ if self.session_name in ACTIVE_SESSIONS:
447
+ del ACTIVE_SESSIONS[self.session_name]
448
+
449
+ def test_refinement_cycle_dispatch(self):
450
+ """Verifies dispatching log_refinement_cycle and aliases."""
451
+ handle_fable_session({
452
+ "action": "create_session",
453
+ "session_name": self.session_name,
454
+ "objective": "Design lock-free queue",
455
+ "time_budget_minutes": 30
456
+ })
457
+
458
+ # Call log_refinement_cycle
459
+ res = handle_fable_session({
460
+ "action": "log_refinement_cycle",
461
+ "session_name": self.session_name,
462
+ "refinement_type": "archetype_exploration",
463
+ "focus_area": "Atomic memory ordering",
464
+ "critique_or_bottleneck": "SeqCst is unnecessarily heavy on ARM64",
465
+ "architectural_refinement": "Relaxed loads with Acquire-Release fences",
466
+ "terminal_probe_results": "Benchmark: 4.2x speedup on aarch64",
467
+ "artifact_path": "C:/docs/arch_refine.md"
468
+ })
469
+ self.assertIn("Rethink-Refine Cycle #1 Logged", res)
470
+ self.assertIn("ARCHETYPE_EXPLORATION", res)
471
+ self.assertIn("Atomic memory ordering", res)
472
+ self.assertIn("Terminal Probes / Benchmarks", res)
473
+ self.assertIn("Artifact Blueprint", res)
474
+ self.assertIn("Total Refinement Cycles", res)
475
+
476
+ # Call alias refine
477
+ res_alias = handle_fable_session({
478
+ "action": "refine",
479
+ "session_name": self.session_name,
480
+ "refinement_type": "adversarial_falsification",
481
+ "focus_area": "ABA Problem",
482
+ "critique_or_bottleneck": "Pointer recycling can fool standard CAS",
483
+ "architectural_refinement": "Tagged pointer with generation counter"
484
+ })
485
+ self.assertIn("Rethink-Refine Cycle #2 Logged", res_alias)
486
+ self.assertIn("ADVERSARIAL_FALSIFICATION", res_alias)
487
+
488
+ # Missing required parameter tests
489
+ res_err = handle_fable_session({
490
+ "action": "log_refinement_cycle",
491
+ "session_name": self.session_name,
492
+ "refinement_type": "test",
493
+ "focus_area": "test",
494
+ "critique_or_bottleneck": ""
495
+ })
496
+ self.assertIn("Error: 'critique_or_bottleneck' is required", res_err)
497
+
498
+ def test_full_workflow_via_handler(self):
499
+ """Executes full lifecycle through the dispatcher tool interface."""
500
+ # 1. Create session
501
+ res = handle_fable_session({
502
+ "action": "create_session",
503
+ "session_name": self.session_name,
504
+ "objective": "Build zero-copy parser",
505
+ "time_budget_minutes": 2.0
506
+ })
507
+ self.assertIn("Fable Cognitive Session Initialized", res)
508
+ self.assertIn("Anti-Rush Lockout is ACTIVE", res)
509
+
510
+ # 2. Get status / telemetry
511
+ res = handle_fable_session({
512
+ "action": "get_status",
513
+ "session_name": self.session_name
514
+ })
515
+ self.assertIn("Fable Session Status & Telemetry", res)
516
+ self.assertIn("LOCKED", res)
517
+
518
+ # 3. Log epistemic items
519
+ res = handle_fable_session({
520
+ "action": "log_epistemic_item",
521
+ "session_name": self.session_name,
522
+ "tag": "PROVEN",
523
+ "claim": "Zero-copy slices borrow from underlying buffer without allocation",
524
+ "evidence": f"{__file__}:L10"
525
+ })
526
+ self.assertIn("Epistemic Item Logged", res)
527
+ self.assertIn("[PROVEN]", res)
528
+
529
+ res = handle_fable_session({
530
+ "action": "log_epistemic_item",
531
+ "session_name": self.session_name,
532
+ "tag": "PROVEN",
533
+ "claim": "Lifetime bounds prevent use-after-free",
534
+ "evidence": "cargo test stdout: rustc verification passed"
535
+ })
536
+ self.assertIn("2 PROVEN", res)
537
+
538
+ # 4. Record invariant
539
+ res = handle_fable_session({
540
+ "action": "record_invariant",
541
+ "session_name": self.session_name,
542
+ "invariant_name": "INV-LIFETIME",
543
+ "formal_statement": "SliceLifetime <= BufferLifetime",
544
+ "proof_or_rationale": "Static borrow checker guarantee",
545
+ "domain": "design"
546
+ })
547
+ self.assertIn("Formal Invariant Recorded", res)
548
+ self.assertIn("INV-LIFETIME", res)
549
+
550
+ # 5. Log refinement cycles (2 required for 2.0m budget)
551
+ res = handle_fable_session({
552
+ "action": "log_refinement_cycle",
553
+ "session_name": self.session_name,
554
+ "refinement_type": "benchmark_probe",
555
+ "focus_area": "SIMD tokenization",
556
+ "critique_or_bottleneck": "Scalar byte scanning is memory-bound",
557
+ "architectural_refinement": "AVX-512 vectorized delimiter detection",
558
+ "terminal_probe_results": "Throughput increased from 1.2 GB/s to 9.8 GB/s"
559
+ })
560
+ self.assertIn("Rethink-Refine Cycle #1 Logged", res)
561
+
562
+ res2 = handle_fable_session({
563
+ "action": "log_refinement_cycle",
564
+ "session_name": self.session_name,
565
+ "refinement_type": "adversarial_falsification",
566
+ "focus_area": "Boundary conditions",
567
+ "critique_or_bottleneck": "Unchecked pointer arithmetic on overflow",
568
+ "architectural_refinement": "Saturating arithmetic bounds with compile-time assertions"
569
+ })
570
+ self.assertIn("Rethink-Refine Cycle #2 Logged", res2)
571
+
572
+ # 6. Try premature unlock (Phase 1) -> Must fail Hard Time-Lock (or cognitive gate)
573
+ res = handle_fable_session({
574
+ "action": "unlock_execution",
575
+ "session_name": self.session_name,
576
+ "rationale": "Premature attempt"
577
+ })
578
+ self.assertIn("HARD TIME-LOCK VIOLATION", res)
579
+
580
+ # 7. Advance to Phase 2 then Phase 3
581
+ handle_fable_session({
582
+ "action": "advance_phase",
583
+ "session_name": self.session_name,
584
+ "next_phase": "Phase 2: Invariant Specification & Blueprint",
585
+ "phase_summary": "Blueprints created"
586
+ })
587
+ handle_fable_session({
588
+ "action": "advance_phase",
589
+ "session_name": self.session_name,
590
+ "next_phase": "Phase 3: Adversarial Red-Teaming & Falsification",
591
+ "phase_summary": "Passed red-teaming checks"
592
+ })
593
+
594
+ # 8. Attempt unlock without elapsed time -> Still hits Hard Time-Lock
595
+ res = handle_fable_session({
596
+ "action": "unlock_execution",
597
+ "session_name": self.session_name,
598
+ "rationale": "Cognitive gates satisfied but timer active"
599
+ })
600
+ self.assertIn("HARD TIME-LOCK VIOLATION", res)
601
+
602
+ # 9. Simulate elapsed monotonic time for testing unlock
603
+ session = ACTIVE_SESSIONS[self.session_name]
604
+ session._authority_deadline_monotonic = time.monotonic() - 1.0
605
+ session._authority_deadline_wall = time.time() - 1.0
606
+
607
+ res = handle_fable_session({
608
+ "action": "unlock_execution",
609
+ "session_name": self.session_name,
610
+ "rationale": "Cognitive gates satisfied with 2 proven facts, 1 invariant, and 2 refinement cycles"
611
+ })
612
+ self.assertIn("Execution Lock Lifted Successfully", res)
613
+ self.assertIn("🟢 UNLOCKED", res)
614
+
615
+ # 10. Adjust internal pacing timer without changing authority budget.
616
+ res = handle_fable_session({
617
+ "action": "set_timer",
618
+ "session_name": self.session_name,
619
+ "time_budget_minutes": 60
620
+ })
621
+ self.assertIn("Pacing Timer", res)
622
+ self.assertIn("Authority Budget", res)
623
+ self.assertIn("2.0", res)
624
+
625
+ # 11. Checkpoint and restore
626
+ res = handle_fable_session({
627
+ "action": "checkpoint_session",
628
+ "session_name": self.session_name
629
+ })
630
+ self.assertIn("Fable Session Checkpointed", res)
631
+ self.assertIn("Refinement Cycles", res)
632
+
633
+ res = handle_fable_session({
634
+ "action": "restore_session",
635
+ "session_name": self.session_name
636
+ })
637
+ self.assertIn("Fable Session Restored", res)
638
+ self.assertIn("Refinement Cycles", res)
639
+
640
+ # 12. List sessions
641
+ res = handle_fable_session({
642
+ "action": "list_sessions"
643
+ })
644
+ self.assertIn(self.session_name, res)
645
+
646
+ def test_cortical_actions_dispatch(self):
647
+ """Tests handle_fable_session routing for cortical_define_lobe and cortical_list_lobes."""
648
+ cortex_dir = Path(__file__).resolve().parents[1] / "skills" / "fable-mode" / "cortex"
649
+ test_file = cortex_dir / "test_distributed_raft.md"
650
+ try:
651
+ # 1. Sprout custom lobe
652
+ res_sprout = handle_fable_session({
653
+ "action": "cortical_define_lobe",
654
+ "name": "test_distributed_raft",
655
+ "description": "Raft consensus, leader election, and term invariants",
656
+ "initial_heuristics": ["Followers only vote once per term"],
657
+ "initial_synaptic_weights": {"quorum": 0.95},
658
+ })
659
+ self.assertIn("Cortical Lobe Sprouted: `test_distributed_raft`", res_sprout)
660
+ self.assertIn("Raft consensus", res_sprout)
661
+
662
+ # 2. List lobes
663
+ res_list = handle_fable_session({
664
+ "action": "cortical_list_lobes",
665
+ })
666
+ self.assertIn("Available Cortical Lobes", res_list)
667
+ self.assertIn("test_distributed_raft", res_list)
668
+
669
+ # 3. Missing name error
670
+ res_err = handle_fable_session({
671
+ "action": "cortical_define_lobe",
672
+ })
673
+ self.assertIn("Error: 'name' or 'lobe_name' is required", res_err)
674
+ finally:
675
+ if test_file.exists():
676
+ try:
677
+ test_file.unlink()
678
+ except Exception:
679
+ pass
680
+
681
+ def test_edge_cases_and_error_handling(self):
682
+ """Tests dispatcher error handling on invalid inputs."""
683
+ # Missing action
684
+ res = handle_fable_session({})
685
+ self.assertIn("Error: Missing required parameter 'action'", res)
686
+
687
+ # Unknown action
688
+ res = handle_fable_session({"action": "fly_to_moon"})
689
+ self.assertIn("Error: Unknown action 'fly_to_moon'", res)
690
+
691
+ # Missing session_name
692
+ res = handle_fable_session({"action": "get_status"})
693
+ self.assertIn("Error: 'session_name' is required", res)
694
+
695
+ # Non-existent session
696
+ res = handle_fable_session({"action": "get_status", "session_name": "ghost_session_xyz"})
697
+ self.assertIn("does not exist", res)
698
+
699
+
700
+ class TestFableMCPStdioServer(unittest.TestCase):
701
+ """End-to-end integration test of the JSON-RPC 2.0 stdio server process."""
702
+
703
+ def setUp(self):
704
+ self.python_exe = sys.executable
705
+ self.server_script = str(CURRENT_DIR / "server.py")
706
+ self.proc = subprocess.Popen(
707
+ [self.python_exe, self.server_script],
708
+ stdin=subprocess.PIPE,
709
+ stdout=subprocess.PIPE,
710
+ stderr=subprocess.PIPE,
711
+ text=True,
712
+ encoding="utf-8"
713
+ )
714
+ # Drain diagnostics continuously: a long-running interactive server
715
+ # must not block on a full stderr pipe while the test reads stdout.
716
+ self._stderr_lines = []
717
+ self._stderr_thread = threading.Thread(target=self._drain_stderr, daemon=True)
718
+ self._stderr_thread.start()
719
+ self.req_id = 0
720
+
721
+ def _drain_stderr(self):
722
+ if self.proc.stderr is None:
723
+ return
724
+ try:
725
+ for line in self.proc.stderr:
726
+ if len(self._stderr_lines) < 256:
727
+ self._stderr_lines.append(line)
728
+ except (OSError, ValueError):
729
+ pass
730
+
731
+ def tearDown(self):
732
+ if self.proc.stdin:
733
+ try:
734
+ self.proc.stdin.close()
735
+ except Exception:
736
+ pass
737
+ if self.proc.stdout:
738
+ try:
739
+ self.proc.stdout.close()
740
+ except Exception:
741
+ pass
742
+ if self.proc.stderr:
743
+ try:
744
+ self.proc.stderr.close()
745
+ except Exception:
746
+ pass
747
+ if self.proc.poll() is None:
748
+ self.proc.terminate()
749
+ try:
750
+ self.proc.wait(timeout=2)
751
+ except subprocess.TimeoutExpired:
752
+ self.proc.kill()
753
+
754
+ def _rpc_call(self, method: str, params: dict = None) -> dict:
755
+ self.req_id += 1
756
+ req = {
757
+ "jsonrpc": "2.0",
758
+ "id": self.req_id,
759
+ "method": method
760
+ }
761
+ if params is not None:
762
+ req["params"] = params
763
+
764
+ raw_req = json.dumps(req) + "\n"
765
+ self.proc.stdin.write(raw_req)
766
+ self.proc.stdin.flush()
767
+
768
+ line = self.proc.stdout.readline()
769
+ self.assertTrue(line, "Server returned empty output")
770
+ return json.loads(line)
771
+
772
+ def test_mcp_handshake_and_tool_call(self):
773
+ """Verifies initialize, tools/list, and tools/call over stdio JSON-RPC."""
774
+ # 1. Initialize
775
+ resp = self._rpc_call("initialize")
776
+ self.assertEqual(resp.get("jsonrpc"), "2.0")
777
+ self.assertEqual(resp.get("id"), 1)
778
+ self.assertEqual(resp["result"]["serverInfo"]["name"], "fable-engine")
779
+
780
+ # 2. Tools List
781
+ resp = self._rpc_call("tools/list")
782
+ tools = resp["result"]["tools"]
783
+ self.assertEqual(len(tools), 14)
784
+ tool_names = [t["name"] for t in tools]
785
+ self.assertIn("fable_session", tool_names)
786
+ self.assertIn("browser_open", tool_names)
787
+ self.assertIn("log_refinement_cycle", tools[0]["inputSchema"]["properties"]["action"]["enum"])
788
+
789
+ # 3. Call fable_session: create_session
790
+ session_name = f"mcp_stdio_test_{int(time.time() * 1000)}"
791
+ resp = self._rpc_call("tools/call", {
792
+ "name": "fable_session",
793
+ "arguments": {
794
+ "action": "create_session",
795
+ "session_name": session_name,
796
+ "objective": "Verify MCP stdio protocol loop",
797
+ "time_budget_minutes": 15
798
+ }
799
+ })
800
+ self.assertFalse(resp["result"].get("isError", True))
801
+ content = resp["result"]["content"][0]["text"]
802
+ self.assertIn("Fable Cognitive Session Initialized", content)
803
+
804
+ # 4. Call fable_session: log_refinement_cycle
805
+ resp = self._rpc_call("tools/call", {
806
+ "name": "fable_session",
807
+ "arguments": {
808
+ "action": "log_refinement_cycle",
809
+ "session_name": session_name,
810
+ "refinement_type": "benchmark_probe",
811
+ "focus_area": "Zero-copy buffering",
812
+ "critique_or_bottleneck": "Memory allocation inside hot loop",
813
+ "architectural_refinement": "Preallocated memory arena slab allocator",
814
+ "terminal_probe_results": "0 allocs/op achieved"
815
+ }
816
+ })
817
+ self.assertFalse(resp["result"].get("isError", True))
818
+ content = resp["result"]["content"][0]["text"]
819
+ self.assertIn("Rethink-Refine Cycle #1 Logged", content)
820
+
821
+ # 5. Call fable_session: compress_payload & view_slice over stdio
822
+ resp = self._rpc_call("tools/call", {
823
+ "name": "fable_session",
824
+ "arguments": {
825
+ "action": "compress_payload",
826
+ "content": "Line 1: Sample MCP payload\nLine 2: Another line\nLine 3: Third line\n",
827
+ "label": "stdio_test_payload"
828
+ }
829
+ })
830
+ self.assertFalse(resp["result"].get("isError", True))
831
+ content = resp["result"]["content"][0]["text"]
832
+ self.assertIn("Fable CAS Payload Compressed", content)
833
+
834
+ # 6. Ping
835
+ resp = self._rpc_call("ping")
836
+ self.assertEqual(resp.get("result"), {})
837
+
838
+ # Clean up session file
839
+ sfile = SESSIONS_DIR / f"{session_name}.json"
840
+ if sfile.exists():
841
+ try:
842
+ sfile.unlink()
843
+ except Exception:
844
+ pass
845
+
846
+
847
+ class TestFableTokenCompression(unittest.TestCase):
848
+ """Direct subsystem tests for FableCASStore, AdaptiveChunkAccumulator, FableGrammar333, CASSliceViewer, and FableCompress."""
849
+
850
+ def setUp(self):
851
+ self.test_dir = Path(tempfile.mkdtemp(prefix="fable_test_cas_"))
852
+ self.compressor = FableCompress(root_dir=self.test_dir)
853
+
854
+ def tearDown(self):
855
+ if self.test_dir.exists():
856
+ shutil.rmtree(self.test_dir, ignore_errors=True)
857
+
858
+ def test_cas_store_atomic_put_get(self):
859
+ """Verify atomic writes, SHA-256 addresses, and byte-exact retrieval."""
860
+ store = self.compressor.cas_store
861
+ sample = "Fable-Mode Token Compression Subsystem verification payload."
862
+ uri = store.put(sample)
863
+ self.assertTrue(uri.startswith("cas://"))
864
+ self.assertEqual(len(store.normalize_ref(uri)), 64)
865
+ self.assertEqual(store.get_text(uri), sample)
866
+ self.assertEqual(store.get_bytes(uri), sample.encode("utf-8"))
867
+ self.assertTrue(store.verify_integrity(uri))
868
+
869
+ def test_cas_corruption_detection(self):
870
+ """Verify integrity verification catches file tampering on disk."""
871
+ store = self.compressor.cas_store
872
+ sample = "Pristine data payload"
873
+ uri = store.put(sample)
874
+ file_path = store.get_file_path(uri)
875
+ store.cache.clear()
876
+
877
+ with open(file_path, "r+b") as f:
878
+ f.seek(0)
879
+ f.write(b"Z")
880
+
881
+ with self.assertRaises(IntegrityError):
882
+ store.get_bytes(uri, verify=True)
883
+ self.assertFalse(store.verify_integrity(uri))
884
+
885
+ def test_lru_cache_bounds_and_eviction(self):
886
+ """Verify LRU cache capacity limits and disk fallback."""
887
+ small_store = FableCASStore(root_dir=self.test_dir / "lru", cache_capacity=2)
888
+ u1 = small_store.put("entry_1")
889
+ u2 = small_store.put("entry_2")
890
+ u3 = small_store.put("entry_3")
891
+
892
+ self.assertEqual(len(small_store.cache), 2)
893
+ self.assertEqual(small_store.get_text(u1), "entry_1")
894
+
895
+ def test_adaptive_chunk_accumulator_coalescing(self):
896
+ """Verify sub-1000 character micro-payload batching into composite frames."""
897
+ acc = self.compressor.accumulator
898
+ payloads = [f"Log trace entry #{i:03d} for subagent execution step." for i in range(30)]
899
+
900
+ flushed_uris = []
901
+ for p in payloads:
902
+ flushed_uris.extend(acc.add(p, metadata={"step": "trace"}))
903
+ flushed_uris.extend(acc.flush())
904
+
905
+ self.assertGreater(len(flushed_uris), 0)
906
+ extracted = []
907
+ for uri in flushed_uris:
908
+ frame_json = self.compressor.cas_store.get_text(uri)
909
+ frame = CompositeFrame.deserialize_json(frame_json)
910
+ for idx in range(len(frame.items)):
911
+ item_text, meta = acc.extract_item(uri, idx)
912
+ extracted.append(item_text)
913
+ self.assertEqual(meta.get("step"), "trace")
914
+
915
+ self.assertEqual(extracted, payloads)
916
+
917
+ def test_grammar333_micro_bytecode_roundtrip(self):
918
+ """Verify bit-exact roundtrip serialization of tool actions."""
919
+ payload = {
920
+ "action_type": "view_file",
921
+ "path": "C:/Projects/module.py",
922
+ "start_line": 10,
923
+ "end_line": 50,
924
+ "content_ref": "cas://abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
925
+ }
926
+ encoded = FableGrammar333.serialize(payload)
927
+ self.assertTrue(encoded.startswith(FableGrammar333.MAGIC_HEADER))
928
+ decoded = FableGrammar333.deserialize(encoded)
929
+ self.assertEqual(decoded, payload)
930
+
931
+ def test_cas_slice_viewer_zero_copy(self):
932
+ """Verify windowed line slice extractor with 1-based indexing."""
933
+ lines = [f"Line {i:03d}: Content description here" for i in range(1, 60)]
934
+ doc = "\n".join(lines)
935
+ uri = self.compressor.cas_store.put(doc)
936
+
937
+ viewer = self.compressor.slice_viewer
938
+ self.assertEqual(viewer.get_line_count(uri), 58)
939
+
940
+ slice_text = viewer.view_slice(uri, 5, 10)
941
+ self.assertEqual(slice_text, "\n".join(lines[4:10]))
942
+
943
+ numbered = viewer.view_slice(uri, 1, 2, include_line_numbers=True)
944
+ self.assertIn(" 1 | Line 001:", numbered)
945
+
946
+ def test_invariant_token_ratio_lte_0_003(self):
947
+ """Verify <= 0.003 tokens/character invariant on large payloads."""
948
+ sizes = [10_000, 50_000, 100_000]
949
+ for size in sizes:
950
+ raw_text = ("function process_data(chunk: Buffer) -> Result {\n return validate(chunk);\n}\n" * (size // 60 + 1))[:size]
951
+ node = self.compressor.compress_payload_to_cas(raw_text, label="trace_dump")
952
+ repr_str = json.dumps(node, separators=(",", ":"))
953
+ ratio = self.compressor.calculate_token_ratio(raw_text, repr_str)
954
+ self.assertLessEqual(ratio, 0.003, f"Failed invariant for size {size}: ratio {ratio}")
955
+ recovered = self.compressor.decompress_cas_payload(node)
956
+ self.assertEqual(recovered, raw_text)
957
+
958
+
959
+ class TestFableCompressionHandlerDispatch(unittest.TestCase):
960
+ """Tests dispatcher tool actions for Token Compression Subsystem."""
961
+
962
+ def test_compress_and_decompress_payload_dispatch(self):
963
+ """Verifies compress_payload and decompress_payload actions."""
964
+ payload = "Structured benchmark probe report for concurrent ring buffer:\n" + ("line output data\n" * 1000)
965
+ res = handle_fable_session({
966
+ "action": "compress_payload",
967
+ "content": payload,
968
+ "label": "benchmark_probe"
969
+ })
970
+ self.assertIn("Fable CAS Payload Compressed", res)
971
+ self.assertIn("cas://", res)
972
+ self.assertIn("PASS (<= 0.003 tokens/char)", res)
973
+
974
+ import re
975
+ match = re.search(r"cas://[0-9a-fA-F]{64}", res)
976
+ self.assertIsNotNone(match)
977
+ cas_uri = match.group(0)
978
+
979
+ res_decomp = handle_fable_session({
980
+ "action": "decompress_payload",
981
+ "cas_ref": cas_uri
982
+ })
983
+ self.assertIn("Fable CAS Payload Retrieved", res_decomp)
984
+ self.assertIn("Structured benchmark probe report", res_decomp)
985
+
986
+ def test_view_slice_dispatch(self):
987
+ """Verifies view_slice action."""
988
+ doc = "\n".join([f"Trace item #{i:02d}" for i in range(1, 30)])
989
+ res_comp = handle_fable_session({
990
+ "action": "compress_payload",
991
+ "content": doc
992
+ })
993
+ import re
994
+ match = re.search(r"cas://[0-9a-fA-F]{64}", res_comp)
995
+ cas_uri = match.group(0)
996
+
997
+ res_slice = handle_fable_session({
998
+ "action": "view_slice",
999
+ "cas_ref": cas_uri,
1000
+ "start_line": 5,
1001
+ "end_line": 8
1002
+ })
1003
+ self.assertIn("Fable CAS Slice View", res_slice)
1004
+ self.assertIn("Trace item #05", res_slice)
1005
+ self.assertIn("Trace item #08", res_slice)
1006
+
1007
+ def test_accumulate_and_flush_dispatch(self):
1008
+ """Verifies accumulate_payload and flush_accumulator actions."""
1009
+ res1 = handle_fable_session({
1010
+ "action": "accumulate_payload",
1011
+ "payload": "Micro-log entry 1",
1012
+ "metadata": {"task": "test"}
1013
+ })
1014
+ self.assertIn("Micro-Payload Ingested", res1)
1015
+
1016
+ res_flush = handle_fable_session({
1017
+ "action": "flush_accumulator"
1018
+ })
1019
+ self.assertIn("Micro-Payload Accumulator", res_flush)
1020
+
1021
+ def test_compression_stats_dispatch(self):
1022
+ """Verifies get_compression_stats action."""
1023
+ res = handle_fable_session({
1024
+ "action": "get_compression_stats"
1025
+ })
1026
+ self.assertIn("Fable Token Compression Subsystem Telemetry", res)
1027
+ self.assertIn("Token Compression Invariant", res)
1028
+
1029
+
1030
+ class TestFableSystem3ActionsDispatch(unittest.TestCase):
1031
+ """Verifies all System 3 MCP actions and session persistence via dispatcher."""
1032
+
1033
+ def setUp(self):
1034
+ self.session_name = f"test_sys3_{int(time.time() * 1000)}"
1035
+ init_res = handle_fable_session({
1036
+ "action": "create_session",
1037
+ "session_name": self.session_name,
1038
+ "objective": "Test System 3 Meta-Cognitive Deliberation",
1039
+ "time_budget_minutes": 30.0,
1040
+ })
1041
+ self.assertIn("Fable Cognitive Session Initialized", init_res)
1042
+
1043
+ def tearDown(self):
1044
+ target_file = SESSIONS_DIR / f"{self.session_name}.json"
1045
+ if target_file.exists():
1046
+ try:
1047
+ target_file.unlink()
1048
+ except Exception:
1049
+ pass
1050
+ if self.session_name in ACTIVE_SESSIONS:
1051
+ del ACTIVE_SESSIONS[self.session_name]
1052
+
1053
+ def test_system3_dialectical_synthesis_dispatch(self):
1054
+ """Verifies system3_dialectical_synthesis action and TRIZ transcendence."""
1055
+ res = handle_fable_session({
1056
+ "action": "system3_dialectical_synthesis",
1057
+ "session_name": self.session_name,
1058
+ "thesis_title": "Lock-Free Ring Buffer",
1059
+ "thesis_description": "Single-writer CAS ring buffer with bounded queue",
1060
+ "antithesis_title": "Contention Bottleneck at Multi-Producer",
1061
+ "contradictions": [
1062
+ {
1063
+ "improving_parameter": "throughput",
1064
+ "worsening_parameter": "latency",
1065
+ "description": "Multi-producer atomic contention degrades P99 latency",
1066
+ "severity": 0.85
1067
+ }
1068
+ ],
1069
+ "failure_modes": ["Cache line bouncing under 16 concurrent producers"],
1070
+ "max_debate_rounds": 3,
1071
+ })
1072
+ self.assertIn("System 3 Dialectical Synthesis Emerged", res)
1073
+ self.assertIn("Transcended TRIZ Inventive Principles", res)
1074
+ self.assertIn("Resolved Contradictions", res)
1075
+
1076
+ session = ACTIVE_SESSIONS[self.session_name]
1077
+ self.assertEqual(len(session.system3_syntheses), 1)
1078
+ self.assertTrue(len(session.refinement_cycles) > 0)
1079
+
1080
+ def test_system3_causal_simulate_dispatch(self):
1081
+ """Verifies system3_causal_simulate action with Pearl do-calculus and brittleness analysis."""
1082
+ nodes = [
1083
+ {"node_id": "threads", "name": "Worker Threads", "node_type": "exogenous", "value": 4.0},
1084
+ {"node_id": "contention", "name": "Lock Contention", "node_type": "endogenous", "value": 0.0},
1085
+ {"node_id": "throughput", "name": "Operations/sec", "node_type": "metric", "value": 0.0}
1086
+ ]
1087
+ edges = [
1088
+ {"source": "threads", "target": "contention", "weight": 0.5},
1089
+ {"source": "threads", "target": "throughput", "weight": 2.0},
1090
+ {"source": "contention", "target": "throughput", "weight": -1.2}
1091
+ ]
1092
+ interventions = {"contention": 0.1}
1093
+
1094
+ res = handle_fable_session({
1095
+ "action": "system3_causal_simulate",
1096
+ "session_name": self.session_name,
1097
+ "model_name": "ThreadContentionDAG",
1098
+ "nodes": nodes,
1099
+ "edges": edges,
1100
+ "interventions": interventions,
1101
+ "target_metric": "throughput"
1102
+ })
1103
+ self.assertIn("System 3 Pearl's Do-Calculus & Causal Simulation", res)
1104
+ self.assertIn("Pearl's Do-Operator Intervention", res)
1105
+ self.assertIn("Structural Brittleness Report", res)
1106
+
1107
+ session = ACTIVE_SESSIONS[self.session_name]
1108
+ self.assertEqual(len(session.system3_causal_graphs), 1)
1109
+
1110
+ def test_system3_evolve_paradigms_dispatch(self):
1111
+ """Verifies system3_evolve_paradigms action with 10D Pareto frontier selection."""
1112
+ res = handle_fable_session({
1113
+ "action": "system3_evolve_paradigms",
1114
+ "session_name": self.session_name,
1115
+ "generations": 2,
1116
+ "population_size": 8,
1117
+ "mutation_rate": 0.20,
1118
+ })
1119
+ self.assertIn("System 3 Evolutionary Paradigm Engine", res)
1120
+ self.assertIn("Top Rank 1 Non-Dominated Pareto Frontier", res)
1121
+ self.assertIn("Winning Gene Allocation", res)
1122
+
1123
+ session = ACTIVE_SESSIONS[self.session_name]
1124
+ self.assertEqual(len(session.system3_gene_pools), 1)
1125
+
1126
+ def test_system3_induce_axioms_dispatch(self):
1127
+ """Verifies system3_induce_axioms action and auto-recording into invariants."""
1128
+ res = handle_fable_session({
1129
+ "action": "system3_induce_axioms",
1130
+ "session_name": self.session_name,
1131
+ "domain": "architecture"
1132
+ })
1133
+ self.assertIn("System 3 Neuro-Symbolic Invariant Induction", res)
1134
+ self.assertIn("Axioms Induced", res)
1135
+
1136
+ session = ACTIVE_SESSIONS[self.session_name]
1137
+ self.assertTrue(len(session.system3_axioms) > 0)
1138
+ self.assertTrue(len(session.invariants) > 0)
1139
+
1140
+ def test_system3_meta_reflect_dispatch(self):
1141
+ """Verifies system3_meta_reflect action with bias detection and heuristic rewriting."""
1142
+ res = handle_fable_session({
1143
+ "action": "system3_meta_reflect",
1144
+ "session_name": self.session_name,
1145
+ "focus_area": "Architecture Deliberation Trace"
1146
+ })
1147
+ self.assertIn("System 3 Meta-Cognitive Deliberation Audit", res)
1148
+ self.assertIn("Recommended Cognitive Gear", res)
1149
+ self.assertIn("Cognitive Bias Diagnostics", res)
1150
+ self.assertIn("Dynamic Search Heuristics", res)
1151
+
1152
+ session = ACTIVE_SESSIONS[self.session_name]
1153
+ self.assertEqual(len(session.system3_reflections), 1)
1154
+
1155
+ def test_system3_tri_level_orchestrate_dispatch(self):
1156
+ """Verifies system3_tri_level_orchestrate action."""
1157
+ res = handle_fable_session({
1158
+ "action": "system3_tri_level_orchestrate",
1159
+ "session_name": self.session_name,
1160
+ "task_complexity": 0.95,
1161
+ "contradiction_density": 0.85,
1162
+ "failure_count": 2,
1163
+ "epistemic_uncertainty": 0.60
1164
+ })
1165
+ self.assertIn("System 3 Tri-Level Cognitive Arbitration", res)
1166
+ self.assertIn("SYSTEM_3_META_COGNITIVE", res)
1167
+
1168
+ session = ACTIVE_SESSIONS[self.session_name]
1169
+ self.assertEqual(len(session.system3_orchestrations), 1)
1170
+
1171
+ def test_system3_hyperbolic_embed_dispatch(self):
1172
+ """Verifies system3_hyperbolic_embed action with Poincaré tree embedding."""
1173
+ tree = {
1174
+ "root": ["agent", "runtime"],
1175
+ "agent": ["planner", "memory"],
1176
+ "runtime": ["broker", "verifier"],
1177
+ }
1178
+ res = handle_fable_session({
1179
+ "action": "system3_hyperbolic_embed",
1180
+ "session_name": self.session_name,
1181
+ "tree": tree,
1182
+ "root_id": "root",
1183
+ "dimension": 2,
1184
+ "curvature": 1.0,
1185
+ "base_step": 1.0,
1186
+ })
1187
+ self.assertIn("System 3 Poincaré Hyperbolic Manifold Embedding", res)
1188
+ self.assertIn("Poincaré Ball", res)
1189
+ self.assertIn("Mean Metric Distortion", res)
1190
+ self.assertIn("Hyperbolic Volume Expansion Ratio", res)
1191
+
1192
+ session = ACTIVE_SESSIONS[self.session_name]
1193
+ self.assertEqual(len(session.system3_hyperbolic_embeddings), 1)
1194
+ self.assertTrue(len(session.refinement_cycles) > 0)
1195
+
1196
+ def test_system3_kripke_verify_dispatch(self):
1197
+ """Verifies system3_kripke_verify action with CTL* temporal verification."""
1198
+ worlds = [
1199
+ {"world_id": "w0", "propositions": ["safe", "init"], "is_initial": True},
1200
+ {"world_id": "w1", "propositions": ["safe", "running"]},
1201
+ {"world_id": "w2", "propositions": ["safe", "complete"]},
1202
+ ]
1203
+ transitions = [
1204
+ {"source": "w0", "target": "w1"},
1205
+ {"source": "w1", "target": "w2"},
1206
+ {"source": "w2", "target": "w2"},
1207
+ ]
1208
+ res = handle_fable_session({
1209
+ "action": "system3_kripke_verify",
1210
+ "session_name": self.session_name,
1211
+ "model_name": "ExecutionWorkflowModel",
1212
+ "worlds": worlds,
1213
+ "transitions": transitions,
1214
+ "formula": "AG(safe)",
1215
+ "initial_world": "w0",
1216
+ })
1217
+ self.assertIn("System 3 Kripke Modal Model Verification", res)
1218
+ self.assertIn("SATISFIED", res)
1219
+ self.assertIn("AG(safe)", res)
1220
+
1221
+ session = ACTIVE_SESSIONS[self.session_name]
1222
+ self.assertEqual(len(session.system3_kripke_verifications), 1)
1223
+
1224
+ def test_system3_active_inference_dispatch(self):
1225
+ """Verifies system3_active_inference action with Variational Free Energy minimization."""
1226
+ res = handle_fable_session({
1227
+ "action": "system3_active_inference",
1228
+ "session_name": self.session_name,
1229
+ "observation": "HIGH_THROUGHPUT_CLEAN",
1230
+ "gamma": 16.0,
1231
+ })
1232
+ self.assertIn("System 3 Friston Active Inference & Variational Free Energy", res)
1233
+ self.assertIn("Variational Free Energy (F)", res)
1234
+ self.assertIn("Selected Policy", res)
1235
+ self.assertIn("Evaluated Policy Landscape", res)
1236
+
1237
+ session = ACTIVE_SESSIONS[self.session_name]
1238
+ self.assertEqual(len(session.system3_active_inferences), 1)
1239
+
1240
+ def test_system3_proof_oracle_dispatch(self):
1241
+ """Verifies system3_proof_oracle action with Curry-Howard constructive verification."""
1242
+ res = handle_fable_session({
1243
+ "action": "system3_proof_oracle",
1244
+ "session_name": self.session_name,
1245
+ "claim": "safe == safe",
1246
+ })
1247
+ self.assertIn("System 3 Gödelian Auto-Formalizing Proof Oracle", res)
1248
+ self.assertIn("DECIDABLE_PROVED", res)
1249
+ self.assertIn("Soundness Verified", res)
1250
+
1251
+ session = ACTIVE_SESSIONS[self.session_name]
1252
+ self.assertEqual(len(session.system3_proof_oracle_verifications), 1)
1253
+ self.assertTrue(len(session.invariants) > 0)
1254
+
1255
+ def test_system3_session_roundtrip_persistence(self):
1256
+ """Verifies full roundtrip serialization & disk saving of all System 3 state fields."""
1257
+ # Execute synthesis, causal, hyperbolic, kripke, free energy, and oracle
1258
+ handle_fable_session({
1259
+ "action": "system3_dialectical_synthesis",
1260
+ "session_name": self.session_name,
1261
+ "thesis_title": "Thesis A",
1262
+ "thesis_description": "Desc A",
1263
+ "antithesis_title": "Critique B",
1264
+ })
1265
+ handle_fable_session({
1266
+ "action": "system3_causal_simulate",
1267
+ "session_name": self.session_name,
1268
+ "nodes": [{"node_id": "X", "value": 1.0}],
1269
+ "edges": []
1270
+ })
1271
+ handle_fable_session({
1272
+ "action": "system3_hyperbolic_embed",
1273
+ "session_name": self.session_name,
1274
+ "tree": {"root": ["a", "b"]},
1275
+ })
1276
+ handle_fable_session({
1277
+ "action": "system3_kripke_verify",
1278
+ "session_name": self.session_name,
1279
+ "worlds": [{"world_id": "w0", "propositions": ["p"]}],
1280
+ "transitions": [{"source": "w0", "target": "w0"}],
1281
+ "formula": "p",
1282
+ })
1283
+ handle_fable_session({
1284
+ "action": "system3_active_inference",
1285
+ "session_name": self.session_name,
1286
+ "observation": "HIGH_THROUGHPUT_CLEAN",
1287
+ })
1288
+ handle_fable_session({
1289
+ "action": "system3_proof_oracle",
1290
+ "session_name": self.session_name,
1291
+ "claim": "safe == safe",
1292
+ })
1293
+
1294
+ session = ACTIVE_SESSIONS[self.session_name]
1295
+ d = session.to_dict()
1296
+ self.assertEqual(len(d["system3_syntheses"]), 1)
1297
+ self.assertEqual(len(d["system3_causal_graphs"]), 1)
1298
+ self.assertEqual(len(d["system3_hyperbolic_embeddings"]), 1)
1299
+ self.assertEqual(len(d["system3_kripke_verifications"]), 1)
1300
+ self.assertEqual(len(d["system3_active_inferences"]), 1)
1301
+ self.assertEqual(len(d["system3_proof_oracle_verifications"]), 1)
1302
+
1303
+ # Restore from dict
1304
+ restored = FableSession.from_dict(d)
1305
+ self.assertEqual(len(restored.system3_syntheses), 1)
1306
+ self.assertEqual(len(restored.system3_causal_graphs), 1)
1307
+ self.assertEqual(len(restored.system3_hyperbolic_embeddings), 1)
1308
+ self.assertEqual(len(restored.system3_kripke_verifications), 1)
1309
+ self.assertEqual(len(restored.system3_active_inferences), 1)
1310
+ self.assertEqual(len(restored.system3_proof_oracle_verifications), 1)
1311
+ self.assertEqual(restored.session_name, self.session_name)
1312
+
1313
+
1314
+ class TestSecondRedTeamRegressions(unittest.TestCase):
1315
+ def test_cached_cas_data_is_verified(self):
1316
+ root = Path(tempfile.mkdtemp(prefix="fable_cas_regression_"))
1317
+ try:
1318
+ store = FableCASStore(root_dir=root)
1319
+ uri = store.put(b"good")
1320
+ digest = store.normalize_ref(uri)
1321
+ store.cache.put(digest, b"bad")
1322
+ with self.assertRaises(IntegrityError):
1323
+ store.get_bytes(uri, verify=True)
1324
+ finally:
1325
+ shutil.rmtree(root, ignore_errors=True)
1326
+
1327
+ def test_restore_ignores_forged_deadline_phase_and_evidence_authority(self):
1328
+ now = time.time()
1329
+ payload = {"session_name": "forged_regression", "objective": "x",
1330
+ "time_budget_minutes": 2.0, "start_time": now - 10000,
1331
+ "authority_deadline_time": now + 10**9,
1332
+ "active_phase": PHASES[-1], "execution_locked": False,
1333
+ "can_execute_code": True,
1334
+ "epistemic_ledger": [{"tag": "PROVEN", "evidence": "forged"},
1335
+ {"tag": "PROVEN", "evidence": "forged"}],
1336
+ "invariants": [{"proof_or_rationale": "forged"}],
1337
+ "phase_history": [{"phase": PHASES[-1]}]}
1338
+ restored = FableSession.from_dict(payload)
1339
+ self.assertTrue(restored.execution_locked)
1340
+ self.assertFalse(restored.can_execute_code)
1341
+ self.assertEqual(restored.active_phase, PHASES[0])
1342
+ self.assertLessEqual(restored.deadline_time, now + 130)
1343
+ self.assertFalse(restored.get_telemetry()["cognitive_gates"]["ready"])
1344
+
1345
+ def test_malformed_rpc_shapes_return_invalid_request(self):
1346
+ root = Path(tempfile.mkdtemp(prefix="fable_rpc_regression_"))
1347
+ try:
1348
+ env = os.environ.copy(); env["FABLE_DATA_DIR"] = str(root / "data")
1349
+ completed = subprocess.run([sys.executable, str(Path(__file__).resolve().parent / "server.py")],
1350
+ input='[1, 2]\n{"jsonrpc":"2.0","id":4,"method":"ping","params":[]}\n',
1351
+ capture_output=True, text=True, env=env, timeout=15)
1352
+ responses = [json.loads(line) for line in completed.stdout.splitlines()]
1353
+ first, second = responses
1354
+ self.assertEqual(first["error"]["code"], -32600)
1355
+ self.assertEqual(second["error"]["code"], -32600)
1356
+ finally:
1357
+ if 'proc' in locals() and proc.poll() is None: proc.kill()
1358
+ shutil.rmtree(root, ignore_errors=True)
1359
+
1360
+
1361
+ if __name__ == "__main__":
1362
+ unittest.main(verbosity=2)