clm-kernel 0.0.0__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 (333) hide show
  1. clm/__init__.py +230 -0
  2. clm/__main__.py +25 -0
  3. clm/cross_cutting/__init__.py +50 -0
  4. clm/cross_cutting/_test_runner.py +36 -0
  5. clm/cross_cutting/async_utils.py +25 -0
  6. clm/cross_cutting/cel_builder.py +123 -0
  7. clm/cross_cutting/cel_converter.py +697 -0
  8. clm/cross_cutting/cel_engine.py +252 -0
  9. clm/cross_cutting/cel_ops.py +72 -0
  10. clm/cross_cutting/cel_ops_db.py +157 -0
  11. clm/cross_cutting/cel_ops_files.py +99 -0
  12. clm/cross_cutting/cel_ops_state.py +71 -0
  13. clm/cross_cutting/cel_ops_strings.py +64 -0
  14. clm/cross_cutting/cel_resolver.py +63 -0
  15. clm/cross_cutting/cel_slices.py +56 -0
  16. clm/cross_cutting/cel_store.py +330 -0
  17. clm/cross_cutting/clm_logger.py +140 -0
  18. clm/cross_cutting/config/__init__.py +155 -0
  19. clm/cross_cutting/config/config_constants.py +392 -0
  20. clm/cross_cutting/config/env_parameters.py +90 -0
  21. clm/cross_cutting/config/logging.py +378 -0
  22. clm/cross_cutting/config/settings.py +504 -0
  23. clm/cross_cutting/context.py +5 -0
  24. clm/cross_cutting/domain_models.py +55 -0
  25. clm/cross_cutting/domain_types.py +61 -0
  26. clm/cross_cutting/effects.py +67 -0
  27. clm/cross_cutting/errors.py +153 -0
  28. clm/cross_cutting/governance.py +331 -0
  29. clm/cross_cutting/guards.py +41 -0
  30. clm/cross_cutting/mcard.py +321 -0
  31. clm/cross_cutting/native.py +185 -0
  32. clm/cross_cutting/observability.py +289 -0
  33. clm/cross_cutting/pcard.py +434 -0
  34. clm/cross_cutting/registry.py +71 -0
  35. clm/cross_cutting/resources.py +84 -0
  36. clm/cross_cutting/secrets.py +44 -0
  37. clm/cross_cutting/subprocess_utils.py +118 -0
  38. clm/cross_cutting/telemetry.py +164 -0
  39. clm/cross_cutting/testing/__init__.py +8 -0
  40. clm/cross_cutting/testing/comparator.py +187 -0
  41. clm/cross_cutting/testing/datasets.py +87 -0
  42. clm/cross_cutting/timeutil.py +20 -0
  43. clm/cross_cutting/types/new_type_check.py +0 -0
  44. clm/cross_cutting/utils/__init__.py +1 -0
  45. clm/cross_cutting/utils/url_safety.py +50 -0
  46. clm/cross_cutting/vcard.py +560 -0
  47. clm/cross_cutting/writer.py +118 -0
  48. clm/layer0/README.md +50 -0
  49. clm/layer0/__init__.py +223 -0
  50. clm/layer0/algebra.py +60 -0
  51. clm/layer0/algebra_baldwin.py +133 -0
  52. clm/layer0/algebra_baldwin_generators.py +36 -0
  53. clm/layer0/algebra_equivalence.py +262 -0
  54. clm/layer0/algebra_ingest.py +306 -0
  55. clm/layer0/algebra_manifest_io.py +156 -0
  56. clm/layer0/assembler.py +481 -0
  57. clm/layer0/cel/__init__.py +23 -0
  58. clm/layer0/cel_eval.py +491 -0
  59. clm/layer0/codec.py +106 -0
  60. clm/layer0/context.py +122 -0
  61. clm/layer0/db.py +160 -0
  62. clm/layer0/exceptions.py +73 -0
  63. clm/layer0/fibration.py +106 -0
  64. clm/layer0/gates.py +50 -0
  65. clm/layer0/hash.py +80 -0
  66. clm/layer0/loader.py +826 -0
  67. clm/layer0/math_utils.py +163 -0
  68. clm/layer0/mcard.py +96 -0
  69. clm/layer0/model/__init__.py +0 -0
  70. clm/layer0/model/action.py +223 -0
  71. clm/layer0/model/card.py +280 -0
  72. clm/layer0/model/card_triad.py +427 -0
  73. clm/layer0/model/compatibility.py +60 -0
  74. clm/layer0/model/dictionary.py +46 -0
  75. clm/layer0/model/dots.py +331 -0
  76. clm/layer0/model/event_producer.py +88 -0
  77. clm/layer0/model/g_time.py +89 -0
  78. clm/layer0/model/handle.py +163 -0
  79. clm/layer0/model/hash/__init__.py +6 -0
  80. clm/layer0/model/hash/algorithms/__init__.py +3 -0
  81. clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
  82. clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
  83. clm/layer0/model/hash/constants.py +53 -0
  84. clm/layer0/model/hash/enums.py +60 -0
  85. clm/layer0/model/hash/validator.py +307 -0
  86. clm/layer0/model/interpreter.py +275 -0
  87. clm/layer0/model/pagination.py +45 -0
  88. clm/layer0/model/pcard.py +716 -0
  89. clm/layer0/model/schema.py +44 -0
  90. clm/layer0/model/utils/__init__.py +1 -0
  91. clm/layer0/model/utils/content_analyzer.py +152 -0
  92. clm/layer0/model/validators/__init__.py +1 -0
  93. clm/layer0/model/validators/base_validator.py +44 -0
  94. clm/layer0/model/validators/binary_validator.py +66 -0
  95. clm/layer0/model/validators/text_validator.py +82 -0
  96. clm/layer0/model/validators/validation_registry.py +49 -0
  97. clm/layer0/model/vcard.py +823 -0
  98. clm/layer0/model/vcard_ext/__init__.py +39 -0
  99. clm/layer0/model/vcard_ext/core.py +60 -0
  100. clm/layer0/model/vcard_ext/network.py +23 -0
  101. clm/layer0/model/vcard_ext/observability.py +63 -0
  102. clm/layer0/model/vcard_ext/storage.py +60 -0
  103. clm/layer0/model/vcard_ext/vendors.py +211 -0
  104. clm/layer0/model/vcard_sandwich.py +119 -0
  105. clm/layer0/model/vcard_vocabulary.py +463 -0
  106. clm/layer0/model/workflow.py +274 -0
  107. clm/layer0/narrative.py +431 -0
  108. clm/layer0/ontology/collection.py +125 -0
  109. clm/layer0/parser.py +429 -0
  110. clm/layer0/relations.py +73 -0
  111. clm/layer0/rule_evaluator.py +251 -0
  112. clm/layer0/schema/__init__.py +38 -0
  113. clm/layer0/schema/ddl.py +97 -0
  114. clm/layer0/templates/abstract.yaml +99 -0
  115. clm/layer0/templates/balanced.yaml +253 -0
  116. clm/layer0/templates/concrete.yaml +172 -0
  117. clm/layer0/type_registry.py +223 -0
  118. clm/layer0/types.py +204 -0
  119. clm/layer0/utils.py +886 -0
  120. clm/layer0/verifier_core.py +262 -0
  121. clm/layer1/__init__.py +31 -0
  122. clm/layer1/action_dispatcher.py +275 -0
  123. clm/layer1/adapter_registry.py +233 -0
  124. clm/layer1/algebra_baldwin_generators.py +192 -0
  125. clm/layer1/arrow_compiler.py +525 -0
  126. clm/layer1/batch_processor.py +152 -0
  127. clm/layer1/cel/__init__.py +27 -0
  128. clm/layer1/cel/builder.py +173 -0
  129. clm/layer1/engine.py +759 -0
  130. clm/layer1/engine_async.py +89 -0
  131. clm/layer1/eval_callback.py +49 -0
  132. clm/layer1/gate_composer.py +229 -0
  133. clm/layer1/hoare_sandwich.py +298 -0
  134. clm/layer1/identity_guard.py +348 -0
  135. clm/layer1/matrix.py +138 -0
  136. clm/layer1/neural_runtime.py +221 -0
  137. clm/layer1/operations/__init__.py +123 -0
  138. clm/layer1/operations/augment.py +156 -0
  139. clm/layer1/operations/base.py +109 -0
  140. clm/layer1/operations/builtins.py +338 -0
  141. clm/layer1/operations/dispatch.py +144 -0
  142. clm/layer1/operations/exclude.py +107 -0
  143. clm/layer1/operations/handle.py +197 -0
  144. clm/layer1/operations/identity.py +139 -0
  145. clm/layer1/operations/invert.py +66 -0
  146. clm/layer1/operations/loader.py +116 -0
  147. clm/layer1/operations/manipulators/__init__.py +23 -0
  148. clm/layer1/operations/manipulators/document.py +211 -0
  149. clm/layer1/operations/manipulators/media.py +134 -0
  150. clm/layer1/operations/manipulators/structured.py +159 -0
  151. clm/layer1/operations/manipulators/tabular.py +334 -0
  152. clm/layer1/operations/port.py +65 -0
  153. clm/layer1/operations/services.py +529 -0
  154. clm/layer1/operations/split.py +117 -0
  155. clm/layer1/operations/substitute.py +75 -0
  156. clm/layer1/petri.py +1052 -0
  157. clm/layer1/pocketflow_orchestrator.py +408 -0
  158. clm/layer1/pocketflow_scheduler.py +519 -0
  159. clm/layer1/protocols.py +197 -0
  160. clm/layer1/runtime_adapter.py +718 -0
  161. clm/layer1/runtimes/__init__.py +71 -0
  162. clm/layer1/runtimes/_generated_assertions.py +125 -0
  163. clm/layer1/runtimes/_generated_types.py +42 -0
  164. clm/layer1/runtimes/base.py +265 -0
  165. clm/layer1/runtimes/binary.py +101 -0
  166. clm/layer1/runtimes/factory.py +203 -0
  167. clm/layer1/runtimes/javascript.py +321 -0
  168. clm/layer1/runtimes/javascript_runtime.js +33 -0
  169. clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
  170. clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
  171. clm/layer1/runtimes/lambda_calc.py +126 -0
  172. clm/layer1/runtimes/python.py +288 -0
  173. clm/layer1/runtimes/python_runtime.py +41 -0
  174. clm/layer1/runtimes/script.py +114 -0
  175. clm/layer1/sandbox.py +334 -0
  176. clm/layer1/savepoint_guard.py +136 -0
  177. clm/layer1/sparse_net.py +122 -0
  178. clm/layer1/spec_tester.py +165 -0
  179. clm/layer1/store.py +295 -0
  180. clm/layer1/test_runner.py +498 -0
  181. clm/layer1/type_inspector.py +166 -0
  182. clm/layer1/verifier.py +772 -0
  183. clm/layer1/vm.py +91 -0
  184. clm/layer2/__init__.py +78 -0
  185. clm/layer2/card_collection.py +678 -0
  186. clm/layer2/classifier.py +479 -0
  187. clm/layer2/engine/__init__.py +1 -0
  188. clm/layer2/engine/abstract_sql_engine.py +320 -0
  189. clm/layer2/engine/base.py +193 -0
  190. clm/layer2/engine/duckdb_engine.py +576 -0
  191. clm/layer2/engine/sqlite_engine.py +518 -0
  192. clm/layer2/fiber/__init__.py +31 -0
  193. clm/layer2/fiber/context.py +89 -0
  194. clm/layer2/fiber/disposable.py +163 -0
  195. clm/layer2/fiber/fiber.py +125 -0
  196. clm/layer2/fiber/hoare.py +191 -0
  197. clm/layer2/file_io.py +376 -0
  198. clm/layer2/file_registrar.py +77 -0
  199. clm/layer2/ingest.py +202 -0
  200. clm/layer2/lineage.py +322 -0
  201. clm/layer2/mcard_fs.py +262 -0
  202. clm/layer2/merkle.py +11 -0
  203. clm/layer2/mime.py +244 -0
  204. clm/layer2/mime_detector.py +245 -0
  205. clm/layer2/private_collection.py +118 -0
  206. clm/layer2/shared_store.py +11 -0
  207. clm/layer2/storage/__init__.py +190 -0
  208. clm/layer2/storage/db_bitemporal.py +141 -0
  209. clm/layer2/storage/db_driver.py +331 -0
  210. clm/layer2/storage/db_hyperlinks.py +214 -0
  211. clm/layer2/storage/db_pool.py +139 -0
  212. clm/layer2/storage/db_repository.py +229 -0
  213. clm/layer2/storage/savepoint.py +78 -0
  214. clm/layer2/storage/sqlite_wal.py +74 -0
  215. clm/layer2/tridb.py +245 -0
  216. clm/layer2/vcard_receipt.py +71 -0
  217. clm/layer2/vfs.py +17 -0
  218. clm/layer3/__init__.py +141 -0
  219. clm/layer3/agency/__init__.py +19 -0
  220. clm/layer3/agency/config.py +220 -0
  221. clm/layer3/agency/providers/__init__.py +15 -0
  222. clm/layer3/agency/providers/base.py +91 -0
  223. clm/layer3/agency/providers/mlc_llm.py +169 -0
  224. clm/layer3/agency/providers/ollama.py +203 -0
  225. clm/layer3/agency/router.py +71 -0
  226. clm/layer3/agency/runtime.py +524 -0
  227. clm/layer3/gateway.py +353 -0
  228. clm/layer3/open_interpreter_adapter.py +159 -0
  229. clm/layer3/rag/__init__.py +70 -0
  230. clm/layer3/rag/cli.py +228 -0
  231. clm/layer3/rag/config.py +153 -0
  232. clm/layer3/rag/embeddings/__init__.py +16 -0
  233. clm/layer3/rag/embeddings/base.py +79 -0
  234. clm/layer3/rag/embeddings/ollama.py +211 -0
  235. clm/layer3/rag/embeddings/vision.py +290 -0
  236. clm/layer3/rag/engine.py +276 -0
  237. clm/layer3/rag/graph/__init__.py +22 -0
  238. clm/layer3/rag/graph/community.py +198 -0
  239. clm/layer3/rag/graph/engine.py +433 -0
  240. clm/layer3/rag/graph/extractor.py +255 -0
  241. clm/layer3/rag/graph/schema.py +115 -0
  242. clm/layer3/rag/graph/store.py +641 -0
  243. clm/layer3/rag/indexer.py +333 -0
  244. clm/layer3/rag/llm_providers.json +52 -0
  245. clm/layer3/rag/semantic_versioning.py +313 -0
  246. clm/layer3/rag/vector/__init__.py +28 -0
  247. clm/layer3/rag/vector/handle_vector_store.py +749 -0
  248. clm/layer3/rag/vector/schema.py +151 -0
  249. clm/layer3/rag/vector/store.py +632 -0
  250. clm/layer3/reticulum/__init__.py +55 -0
  251. clm/layer3/reticulum/bridge.py +74 -0
  252. clm/layer3/reticulum/daemon.py +88 -0
  253. clm/layer3/reticulum/discovery.py +164 -0
  254. clm/layer3/reticulum/identity.py +107 -0
  255. clm/layer3/reticulum/media.py +148 -0
  256. clm/layer3/reticulum/transport.py +133 -0
  257. clm/layer3/satori/__init__.py +209 -0
  258. clm/layer3/satori/alpha_conversion.py +168 -0
  259. clm/layer3/satori/beta_reduction.py +359 -0
  260. clm/layer3/satori/continuation.py +38 -0
  261. clm/layer3/satori/eta_conversion.py +205 -0
  262. clm/layer3/satori/free_variables.py +163 -0
  263. clm/layer3/satori/io_effects.py +370 -0
  264. clm/layer3/satori/lambda_runtime.py +726 -0
  265. clm/layer3/satori/lambda_term.py +230 -0
  266. clm/layer3/satori/sheaf_audit.py +261 -0
  267. clm/layer3/satori/speech_act.py +279 -0
  268. clm/layer4/README.md +9 -0
  269. clm/layer4/__init__.py +67 -0
  270. clm/layer4/_sovereign_executor.py +580 -0
  271. clm/layer4/action_commands.py +719 -0
  272. clm/layer4/api.py +236 -0
  273. clm/layer4/bootstrap/__init__.py +13 -0
  274. clm/layer4/bootstrap/bootstrapper.py +118 -0
  275. clm/layer4/bootstrap/cleanup.py +44 -0
  276. clm/layer4/bootstrap/clm_hooks.py +49 -0
  277. clm/layer4/bootstrap/genesis.py +77 -0
  278. clm/layer4/bootstrap/injection.py +125 -0
  279. clm/layer4/cli.py +549 -0
  280. clm/layer4/collection_manager.py +553 -0
  281. clm/layer4/commands/__init__.py +81 -0
  282. clm/layer4/commands/action_cmd.py +42 -0
  283. clm/layer4/commands/check_cmd.py +82 -0
  284. clm/layer4/commands/envelope.py +73 -0
  285. clm/layer4/commands/evaluate_cmd.py +224 -0
  286. clm/layer4/commands/mcard_cmd.py +24 -0
  287. clm/layer4/commands/petri_cmd.py +92 -0
  288. clm/layer4/commands/tridb_cmd.py +319 -0
  289. clm/layer4/commands/version_cmd.py +27 -0
  290. clm/layer4/diff_commands.py +167 -0
  291. clm/layer4/eoa_sponsor.py +232 -0
  292. clm/layer4/events.py +69 -0
  293. clm/layer4/flux_gateway.py +133 -0
  294. clm/layer4/gateway.py +91 -0
  295. clm/layer4/loader.py +307 -0
  296. clm/layer4/mcard_commands.py +166 -0
  297. clm/layer4/membrane.py +273 -0
  298. clm/layer4/navigation.py +50 -0
  299. clm/layer4/protocol/protocol_entry_python.py +108 -0
  300. clm/layer4/protocol/python_sync.py +126 -0
  301. clm/layer4/runner.py +150 -0
  302. clm/layer4/satori.py +262 -0
  303. clm/layer4/server/python_sync_client.py +150 -0
  304. clm/layer4/server/python_sync_server.py +139 -0
  305. clm/layer4/server/service_api.py +315 -0
  306. clm/layer4/server/start_servers.py +107 -0
  307. clm/layer4/server/stop_servers.py +24 -0
  308. clm/layer4/simulated_optimization_fix.py +0 -0
  309. clm/layer4/storage.py +463 -0
  310. clm/layer4/tridb_admin.py +268 -0
  311. clm/layer4/websocket/test_ws_client.py +104 -0
  312. clm/layer4/websocket/test_ws_server.py +138 -0
  313. clm/layer4/websocket/ws_server_local.py +160 -0
  314. clm/layer5/__init__.py +51 -0
  315. clm/layer5/async_batch_writer.py +133 -0
  316. clm/layer5/learning.py +276 -0
  317. clm/layer5/telemetry_hook.py +107 -0
  318. clm/layer5/type_lattice.py +238 -0
  319. clm/py.typed +0 -0
  320. clm/schemas/__init__.py +652 -0
  321. clm/schemas/abstract_face_schema.yaml +77 -0
  322. clm/schemas/cel_schema.yaml +416 -0
  323. clm/schemas/lifecycle/__init__.py +45 -0
  324. clm/schemas/lifecycle/models.py +123 -0
  325. clm/schemas/lifecycle/service.py +364 -0
  326. clm/schemas/mcard_schema.sql +192 -0
  327. clm/schemas/mcard_vector_schema.sql +283 -0
  328. clm/schemas/mlp-context-v1.json +91 -0
  329. clm_kernel-0.0.0.dist-info/METADATA +121 -0
  330. clm_kernel-0.0.0.dist-info/RECORD +333 -0
  331. clm_kernel-0.0.0.dist-info/WHEEL +4 -0
  332. clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
  333. clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,163 @@
1
+ """Cordis DisposableList & Savepoint Guard (DEL-389-01, INV-389-02, INV-389-03).
2
+
3
+ Provides:
4
+ 1. DisposableList: Strict LIFO stack of reversible side-effects for zero-residual state.
5
+ 2. SavepointGuard: RAII SQLite savepoint manager with <1ms transactional rollback.
6
+ 3. TriDbSavepointGuard: Multi-database atomic savepoint coordinator across the Triad.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ import sqlite3
12
+ import time
13
+ import uuid
14
+ from typing import Callable
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class DisposableList:
20
+ """Strict LIFO stack of cleanup/rollback closures for Cordis fibers.
21
+
22
+ Enforces INV-389-02: Disposers execute in exact reverse registration order.
23
+ Aggregates exceptions so that all disposers run even if one raises.
24
+ """
25
+
26
+ def __init__(self) -> None:
27
+ self._disposables: list[Callable[[], None]] = []
28
+
29
+ def push(self, disposable: Callable[[], None]) -> None:
30
+ """Register a cleanup closure to be executed on disposal."""
31
+ if callable(disposable):
32
+ self._disposables.append(disposable)
33
+
34
+ def dispose(self) -> list[Exception]:
35
+ """Execute all registered closures in reverse-LIFO order.
36
+
37
+ Returns:
38
+ List of any exceptions raised during disposal.
39
+ """
40
+ errors: list[Exception] = []
41
+ while self._disposables:
42
+ fn = self._disposables.pop()
43
+ try:
44
+ fn()
45
+ except Exception as e:
46
+ logger.error(f"[DisposableList] Disposer failed: {e}", exc_info=True)
47
+ errors.append(e)
48
+ return errors
49
+
50
+ def clear(self) -> None:
51
+ """Clear all registered disposers without executing them."""
52
+ self._disposables.clear()
53
+
54
+ def __len__(self) -> int:
55
+ return len(self._disposables)
56
+
57
+ def __bool__(self) -> bool:
58
+ return len(self._disposables) > 0
59
+
60
+
61
+ class SavepointGuard:
62
+ """RAII SQLite savepoint manager with sub-millisecond rollback (INV-389-03)."""
63
+
64
+ def __init__(
65
+ self,
66
+ conn: sqlite3.Connection,
67
+ name: str | None = None,
68
+ disposables: DisposableList | None = None,
69
+ ) -> None:
70
+ self.conn = conn
71
+ self.name = name or f"sp_{uuid.uuid4().hex[:8]}"
72
+ self.disposables = disposables or DisposableList()
73
+ self._rolled_back = False
74
+ self._released = False
75
+ self.rollback_duration_ms: float = 0.0
76
+
77
+ def begin(self) -> None:
78
+ """Issue SAVEPOINT statement."""
79
+ self.conn.execute(f"SAVEPOINT {self.name};")
80
+
81
+ def rollback(self) -> None:
82
+ """Roll back to savepoint and unwind disposables in LIFO order."""
83
+ if self._rolled_back or self._released:
84
+ return
85
+ t0 = time.perf_counter()
86
+ try:
87
+ self.disposables.dispose()
88
+ self.conn.execute(f"ROLLBACK TO SAVEPOINT {self.name};")
89
+ self.conn.execute(f"RELEASE SAVEPOINT {self.name};")
90
+ finally:
91
+ self._rolled_back = True
92
+ self.rollback_duration_ms = (time.perf_counter() - t0) * 1000.0
93
+ logger.debug(f"[SavepointGuard] Rollback '{self.name}' completed in {self.rollback_duration_ms:.3f}ms")
94
+
95
+ def commit(self) -> None:
96
+ """Release the savepoint cleanly."""
97
+ if self._rolled_back or self._released:
98
+ return
99
+ self.conn.execute(f"RELEASE SAVEPOINT {self.name};")
100
+ self._released = True
101
+
102
+ def __enter__(self) -> SavepointGuard:
103
+ self.begin()
104
+ return self
105
+
106
+ def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
107
+ if exc_type is not None:
108
+ self.rollback()
109
+ return False
110
+ else:
111
+ self.commit()
112
+ return True
113
+
114
+
115
+ class TriDbSavepointGuard:
116
+ """Coordinated savepoint guard across multiple SQLite database connections."""
117
+
118
+ def __init__(
119
+ self,
120
+ connections: dict[str, sqlite3.Connection] | list[sqlite3.Connection],
121
+ name: str | None = None,
122
+ disposables: DisposableList | None = None,
123
+ ) -> None:
124
+ if isinstance(connections, dict):
125
+ self.conns = list(connections.values())
126
+ else:
127
+ self.conns = list(connections)
128
+ self.name = name or f"tridb_sp_{uuid.uuid4().hex[:8]}"
129
+ self.disposables = disposables or DisposableList()
130
+ self._guards = [SavepointGuard(c, self.name, None) for c in self.conns]
131
+ self.rollback_duration_ms: float = 0.0
132
+
133
+ def begin(self) -> None:
134
+ for g in self._guards:
135
+ g.begin()
136
+
137
+ def rollback(self) -> None:
138
+ t0 = time.perf_counter()
139
+ try:
140
+ self.disposables.dispose()
141
+ for g in self._guards:
142
+ g.rollback()
143
+ finally:
144
+ self.rollback_duration_ms = (time.perf_counter() - t0) * 1000.0
145
+
146
+ def commit(self) -> None:
147
+ for g in self._guards:
148
+ g.commit()
149
+
150
+ def __enter__(self) -> TriDbSavepointGuard:
151
+ self.begin()
152
+ return self
153
+
154
+ def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
155
+ if exc_type is not None:
156
+ self.rollback()
157
+ return False
158
+ else:
159
+ self.commit()
160
+ return True
161
+
162
+
163
+ __all__ = ["DisposableList", "SavepointGuard", "TriDbSavepointGuard"]
@@ -0,0 +1,125 @@
1
+ """Cordis 5-State Fiber Lifecycle Machine (DEL-389-01, INV-389-01).
2
+
3
+ Implements the formal state machine:
4
+ Pending ➔ Loading ➔ Active ➔ Unloading ➔ Disposed
5
+
6
+ Enforces INV-389-01: Every execution fiber must strictly follow valid transitions;
7
+ direct jumps or resurrections raise FiberLifecycleError.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ from enum import Enum
13
+ from typing import Callable
14
+
15
+ from clm.layer0.exceptions import CLMError
16
+ from clm.layer2.fiber.context import Context
17
+ from clm.layer2.fiber.disposable import DisposableList
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class FiberState(str, Enum):
23
+ """The five canonical lifecycle states of a Cordis Fiber."""
24
+ PENDING = "pending"
25
+ LOADING = "loading"
26
+ ACTIVE = "active"
27
+ UNLOADING = "unloading"
28
+ DISPOSED = "disposed"
29
+
30
+
31
+ class FiberLifecycleError(CLMError):
32
+ """Raised when an illegal transition is attempted across fiber states."""
33
+ pass
34
+
35
+
36
+ # Strict transition matrix enforcing INV-389-01
37
+ VALID_TRANSITIONS: dict[FiberState, set[FiberState]] = {
38
+ FiberState.PENDING: {FiberState.LOADING},
39
+ FiberState.LOADING: {FiberState.ACTIVE, FiberState.DISPOSED},
40
+ FiberState.ACTIVE: {FiberState.UNLOADING},
41
+ FiberState.UNLOADING: {FiberState.DISPOSED},
42
+ FiberState.DISPOSED: set(), # Terminal state: cannot transition out
43
+ }
44
+
45
+
46
+ class Fiber:
47
+ """Cordis Execution Fiber.
48
+
49
+ Represents an isolated unit of execution with a 5-state lifecycle and LIFO disposer stack.
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ fiber_id: str,
55
+ context: Context | None = None,
56
+ disposables: DisposableList | None = None,
57
+ ) -> None:
58
+ self.id = fiber_id
59
+ self.state: FiberState = FiberState.PENDING
60
+ self.context = context or Context()
61
+ self.disposables = disposables or DisposableList()
62
+ self._history: list[FiberState] = [FiberState.PENDING]
63
+
64
+ def register_disposable(self, callback: Callable[[], None]) -> None:
65
+ """Register a LIFO cleanup closure on this fiber."""
66
+ self.disposables.push(callback)
67
+
68
+ def transition(self, target: FiberState | str) -> None:
69
+ """Transition the fiber to a new lifecycle state.
70
+
71
+ Raises:
72
+ FiberLifecycleError: If the transition violates INV-389-01.
73
+ """
74
+ if isinstance(target, str):
75
+ try:
76
+ target_state = FiberState(target.lower())
77
+ except ValueError:
78
+ raise FiberLifecycleError(f"Unknown FiberState '{target}' for fiber '{self.id}'")
79
+ else:
80
+ target_state = target
81
+
82
+ allowed = VALID_TRANSITIONS.get(self.state, set())
83
+ if target_state not in allowed:
84
+ raise FiberLifecycleError(
85
+ f"Illegal fiber lifecycle transition for '{self.id}': "
86
+ f"cannot jump from {self.state.value.upper()} to {target_state.value.upper()}. "
87
+ f"Valid target states: {[s.value.upper() for s in allowed]}"
88
+ )
89
+
90
+ logger.debug(f"[Fiber:{self.id}] {self.state.value} -> {target_state.value}")
91
+ self.state = target_state
92
+ self._history.append(target_state)
93
+
94
+ # When entering DISPOSED, automatically unwind disposables
95
+ if target_state == FiberState.DISPOSED:
96
+ self.disposables.dispose()
97
+
98
+ def dispose(self) -> None:
99
+ """Gracefully transition this fiber to DISPOSED via valid intermediate steps."""
100
+ if self.state == FiberState.DISPOSED:
101
+ return
102
+ if self.state == FiberState.PENDING:
103
+ self.transition(FiberState.LOADING)
104
+ self.transition(FiberState.DISPOSED)
105
+ elif self.state == FiberState.LOADING:
106
+ self.transition(FiberState.DISPOSED)
107
+ elif self.state == FiberState.ACTIVE:
108
+ self.transition(FiberState.UNLOADING)
109
+ self.transition(FiberState.DISPOSED)
110
+ elif self.state == FiberState.UNLOADING:
111
+ self.transition(FiberState.DISPOSED)
112
+
113
+ @property
114
+ def is_active(self) -> bool:
115
+ return self.state == FiberState.ACTIVE
116
+
117
+ @property
118
+ def is_disposed(self) -> bool:
119
+ return self.state == FiberState.DISPOSED
120
+
121
+ def __repr__(self) -> str:
122
+ return f"<Fiber id={self.id!r} state={self.state.value!r} disposables={len(self.disposables)}>"
123
+
124
+
125
+ __all__ = ["FiberState", "FiberLifecycleError", "Fiber"]
@@ -0,0 +1,191 @@
1
+ """Hoare Fiber State Machine & Deterministic Rollback (DEL-389-01, INV-389-03).
2
+
3
+ Executes formal Hoare Triples {P} C {Q} across Fiber lifecycles with guaranteed
4
+ sub-millisecond (<1ms) transactional rollback via SavepointGuard and DisposableList.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import logging
9
+ import sqlite3
10
+ import time
11
+ from dataclasses import dataclass
12
+ from typing import Any, Callable
13
+
14
+ from clm.layer2.fiber.context import Context
15
+ from clm.layer2.fiber.disposable import SavepointGuard
16
+ from clm.layer2.fiber.fiber import Fiber, FiberState
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @dataclass
22
+ class HoareTriple:
23
+ """Formal specification of a state transition as a Hoare Triple {P} C {Q}."""
24
+ name: str
25
+ transition: Callable[[Context, Fiber], Any]
26
+ precondition: Callable[[Context], bool | tuple[bool, str]] | None = None
27
+ postcondition: Callable[[Context, Any], bool | tuple[bool, str]] | None = None
28
+
29
+
30
+ @dataclass
31
+ class HoareExecutionReport:
32
+ """Execution telemetry report measuring rollback timing and determinism."""
33
+ fiber_id: str
34
+ success: bool
35
+ rollback_triggered: bool
36
+ rollback_duration_ms: float
37
+ final_state: FiberState
38
+ value: Any = None
39
+ error: str | None = None
40
+
41
+
42
+ class HoareFiberExecutor:
43
+ """Executes transitions under formal Hoare contract verification with deterministic rollback."""
44
+
45
+ @staticmethod
46
+ def execute(
47
+ context: Context,
48
+ fiber: Fiber,
49
+ triple: HoareTriple,
50
+ conn: sqlite3.Connection | None = None,
51
+ ) -> HoareExecutionReport:
52
+ """Execute a HoareTriple {P} C {Q} over a Fiber.
53
+
54
+ Guarantees:
55
+ - {P} evaluated in LOADING state.
56
+ - Computation C evaluated in ACTIVE state.
57
+ - {Q} evaluated on concrete output value before state commitment.
58
+ - On {P} or {Q} failure or exception: triggers LIFO unwinding and savepoint rollback in <1ms.
59
+ """
60
+ # Step 1: Ensure fiber is in LOADING state
61
+ if fiber.state == FiberState.PENDING:
62
+ fiber.transition(FiberState.LOADING)
63
+
64
+ # Step 2: Evaluate Precondition {P} in LOADING state
65
+ if triple.precondition is not None:
66
+ try:
67
+ pre_res = triple.precondition(context)
68
+ if isinstance(pre_res, tuple):
69
+ passed, msg = pre_res
70
+ if not passed:
71
+ fiber.transition(FiberState.DISPOSED)
72
+ return HoareExecutionReport(
73
+ fiber_id=fiber.id,
74
+ success=False,
75
+ rollback_triggered=False,
76
+ rollback_duration_ms=0.0,
77
+ final_state=fiber.state,
78
+ error=f"Precondition {{P}} failed: {msg}",
79
+ )
80
+ elif not pre_res:
81
+ fiber.transition(FiberState.DISPOSED)
82
+ return HoareExecutionReport(
83
+ fiber_id=fiber.id,
84
+ success=False,
85
+ rollback_triggered=False,
86
+ rollback_duration_ms=0.0,
87
+ final_state=fiber.state,
88
+ error="Precondition {P} check returned False",
89
+ )
90
+ except Exception as e:
91
+ fiber.transition(FiberState.DISPOSED)
92
+ return HoareExecutionReport(
93
+ fiber_id=fiber.id,
94
+ success=False,
95
+ rollback_triggered=False,
96
+ rollback_duration_ms=0.0,
97
+ final_state=fiber.state,
98
+ error=f"Precondition {{P}} exception: {e}",
99
+ )
100
+
101
+ # Step 3: Transition to ACTIVE state
102
+ fiber.transition(FiberState.ACTIVE)
103
+
104
+ # Step 4: Setup SavepointGuard for computation C
105
+ sp_guard: SavepointGuard | None = None
106
+ if conn is not None:
107
+ sp_guard = SavepointGuard(conn, name=f"sp_{triple.name[:12]}", disposables=fiber.disposables)
108
+ sp_guard.begin()
109
+
110
+ # Step 5: Execute computation C
111
+ try:
112
+ val = triple.transition(context, fiber)
113
+ except Exception as e:
114
+ logger.warning(f"[HoareFiberExecutor] Computation error in '{triple.name}': {e}", exc_info=True)
115
+ rollback_duration = 0.0
116
+ if sp_guard is not None:
117
+ sp_guard.rollback()
118
+ rollback_duration = sp_guard.rollback_duration_ms
119
+ else:
120
+ t0 = time.perf_counter()
121
+ fiber.disposables.dispose()
122
+ rollback_duration = (time.perf_counter() - t0) * 1000.0
123
+
124
+ fiber.transition(FiberState.UNLOADING)
125
+ fiber.transition(FiberState.DISPOSED)
126
+
127
+ return HoareExecutionReport(
128
+ fiber_id=fiber.id,
129
+ success=False,
130
+ rollback_triggered=True,
131
+ rollback_duration_ms=rollback_duration,
132
+ final_state=fiber.state,
133
+ error=f"Execution error in {triple.name}: {e}",
134
+ )
135
+
136
+ # Step 6: Evaluate Postcondition {Q} in ACTIVE state on output value
137
+ if triple.postcondition is not None:
138
+ post_passed = True
139
+ post_error = ""
140
+ try:
141
+ post_res = triple.postcondition(context, val)
142
+ if isinstance(post_res, tuple):
143
+ post_passed, post_error = post_res
144
+ elif not post_res:
145
+ post_passed = False
146
+ post_error = "Postcondition {Q} returned False"
147
+ except Exception as e:
148
+ post_passed = False
149
+ post_error = f"Postcondition {{Q}} exception: {e}"
150
+
151
+ if not post_passed:
152
+ logger.warning(f"[HoareFiberExecutor] Postcondition {{Q}} failed in '{triple.name}': {post_error}")
153
+ rollback_duration = 0.0
154
+ if sp_guard is not None:
155
+ sp_guard.rollback()
156
+ rollback_duration = sp_guard.rollback_duration_ms
157
+ else:
158
+ t0 = time.perf_counter()
159
+ fiber.disposables.dispose()
160
+ rollback_duration = (time.perf_counter() - t0) * 1000.0
161
+
162
+ fiber.transition(FiberState.UNLOADING)
163
+ fiber.transition(FiberState.DISPOSED)
164
+
165
+ return HoareExecutionReport(
166
+ fiber_id=fiber.id,
167
+ success=False,
168
+ rollback_triggered=True,
169
+ rollback_duration_ms=rollback_duration,
170
+ final_state=fiber.state,
171
+ error=f"Postcondition {{Q}} failed: {post_error}",
172
+ )
173
+
174
+ # Step 7: Postconditions satisfied, commit transaction
175
+ if sp_guard is not None:
176
+ sp_guard.commit()
177
+
178
+ fiber.transition(FiberState.UNLOADING)
179
+ fiber.transition(FiberState.DISPOSED)
180
+
181
+ return HoareExecutionReport(
182
+ fiber_id=fiber.id,
183
+ success=True,
184
+ rollback_triggered=False,
185
+ rollback_duration_ms=0.0,
186
+ final_state=fiber.state,
187
+ value=val,
188
+ )
189
+
190
+
191
+ __all__ = ["HoareTriple", "HoareExecutionReport", "HoareFiberExecutor"]