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,89 @@
1
+ """AsyncPTREngine - Asynchronous interface for the Polynomial Type Runtime (PTR)
2
+
3
+ Provides native async/await methods by delegating to the existing synchronous
4
+ PTREngine using asyncio.to_thread dynamically.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ from typing import Any
11
+
12
+ from clm.layer1.engine import ExecutionResult, PTREngine
13
+ from clm.layer1.store import PTRSharedStore
14
+
15
+
16
+ class AsyncPTREngine:
17
+ """Asynchronous wrapper for PTREngine.
18
+
19
+ Dynamically proxies all synchronous PTREngine methods into asyncio thread pool.
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ storage_collection: Any | None = None,
25
+ execution_log_collection: Any | None = None,
26
+ identity_space_collection: Any | None = None,
27
+ **engine_kwargs: Any,
28
+ ) -> None:
29
+ self._engine = PTREngine(
30
+ storage_collection=storage_collection,
31
+ execution_log_collection=execution_log_collection,
32
+ identity_space_collection=identity_space_collection,
33
+ **engine_kwargs,
34
+ )
35
+ # Preserve public properties
36
+ self.logger = self._engine.logger
37
+ self.correctness_tracker = self._engine.correctness_tracker
38
+ self.collection = self._engine.collection
39
+
40
+ async def execute_pcard(
41
+ self,
42
+ pcard_hash: str,
43
+ target_hash: str,
44
+ context: dict[str, Any] | PTRSharedStore | None = None,
45
+ specification_embedding: list[float] | None = None,
46
+ ) -> ExecutionResult:
47
+ """Fast-path execute_pcard with optional artifact preloading."""
48
+ # Async prefetch artifacts using CardCollection.aget when available
49
+ store = getattr(self._engine, "collection", None)
50
+
51
+ if isinstance(context, PTRSharedStore):
52
+ pre_context = context
53
+ if store and hasattr(store, "aget"):
54
+ pcard = await store.aget(pcard_hash)
55
+ target = await store.aget(target_hash)
56
+ pre_context.inputs["_preloaded_pcard"] = pcard
57
+ pre_context.inputs["_preloaded_target"] = target
58
+ else:
59
+ pre_context = dict(context or {})
60
+ if store and hasattr(store, "aget"):
61
+ pcard = await store.aget(pcard_hash)
62
+ target = await store.aget(target_hash)
63
+ pre_context["_preloaded_pcard"] = pcard
64
+ pre_context["_preloaded_target"] = target
65
+
66
+ return await asyncio.to_thread(
67
+ self._engine.execute_pcard,
68
+ pcard_hash,
69
+ target_hash,
70
+ pre_context,
71
+ specification_embedding,
72
+ )
73
+
74
+ def __getattr__(self, name: str) -> Any:
75
+ """Dynamically propagate all other methods from PTREngine.
76
+
77
+ Automatically wraps callable methods in asyncio.to_thread to make them asynchronous.
78
+ """
79
+ attr = getattr(self._engine, name)
80
+
81
+ # If it's not a method or it's a private attribute, return as-is
82
+ if not callable(attr) or name.startswith("_"):
83
+ return attr
84
+
85
+ # Create an async wrapper for the synchronous method
86
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
87
+ return await asyncio.to_thread(attr, *args, **kwargs)
88
+
89
+ return async_wrapper
@@ -0,0 +1,49 @@
1
+ """Evaluation Callback Registry — Dependency inversion for Layer 1.
2
+
3
+ Sprint 143 V-2/V-3 fix: Layer 1 (petri.py, runtime_adapter.py) was importing
4
+ evaluate_cmd from higher layers, creating upward dependencies that violate
5
+ the Type Lattice SSOT principle (type_lattice.md §4.5).
6
+
7
+ This module provides a registry where higher layers can register their evaluate_cmd
8
+ function at startup. Layer 1 calls get_evaluate_callback() to retrieve it,
9
+ avoiding any direct upward import.
10
+
11
+ Usage in higher layers:
12
+ from clm.layer1.eval_callback import register_evaluate_callback
13
+ register_evaluate_callback(evaluate_cmd)
14
+
15
+ Usage in Layer 1:
16
+ from clm.layer1.eval_callback import get_evaluate_callback
17
+ cb = get_evaluate_callback()
18
+ if cb:
19
+ rc = cb(clm_root, clm_file, extra_args)
20
+ """
21
+
22
+ from typing import Callable, Optional
23
+
24
+ # Type alias: evaluate_cmd(clm_root: str, clm_file: str, extra_args: list[str]) -> int
25
+ EvaluateFn = Callable[[str, str, list[str]], int]
26
+
27
+ _callback: Optional[EvaluateFn] = None
28
+
29
+
30
+ def register_evaluate_callback(fn: EvaluateFn) -> None:
31
+ """Register the evaluate_cmd function from Layer 3."""
32
+ global _callback
33
+ _callback = fn
34
+
35
+
36
+ def get_evaluate_callback() -> Optional[EvaluateFn]:
37
+ """Retrieve the registered evaluate_cmd, or None if not yet registered."""
38
+ return _callback
39
+
40
+
41
+ def evaluate_or_fail(clm_root: str, clm_file: str, extra_args: list[str]) -> int:
42
+ """Call the registered evaluate_cmd, or raise if no callback is registered."""
43
+ cb = get_evaluate_callback()
44
+ if cb is None:
45
+ raise RuntimeError(
46
+ "No evaluate callback registered. "
47
+ "Layer 3 must call register_evaluate_callback() at import time."
48
+ )
49
+ return cb(clm_root, clm_file, extra_args)
@@ -0,0 +1,229 @@
1
+ """CLM Gate Composer — Gate PCard composition and nested evaluation.
2
+
3
+ Handles the sequencing and execution of pre/post gate PCards
4
+ in the CLM evaluation lifecycle:
5
+ - compose_conditions_cmd: resolve and run pre/post gate PCards in sequence
6
+ - run_nested_evaluate: execute a gate PCard in an isolated subprocess sandbox
7
+ """
8
+
9
+ import os
10
+ import subprocess
11
+ import sys
12
+ import threading
13
+ from collections.abc import Callable
14
+
15
+ from clm.cross_cutting.clm_logger import get_logger
16
+ from clm.layer0.utils import resolve_clm_path
17
+
18
+ from .verifier import get_load_manifest, validate_postcondition, verify_precondition
19
+
20
+ _logger = get_logger("clm.layer1.gate_composer")
21
+ HASH_PREFIX = "sha256:"
22
+
23
+
24
+ def run_nested_evaluate(clm_root: str, gate_file: str, target_clm: str, exit_code: int | None = None) -> int:
25
+ """
26
+ Runs a nested evaluation of a gate PCard in an isolated sandbox.
27
+
28
+ Args:
29
+ clm_root (str): The root directory of the CLM workspace.
30
+ gate_file (str): The gate PCard to evaluate.
31
+ target_clm (str): The target PCard being gated.
32
+ exit_code (Optional[int]): Optional exit code context for post-gates.
33
+
34
+ Returns:
35
+ int: The return code of the nested sandbox.
36
+ """
37
+ gate_file = resolve_clm_path(clm_root, gate_file)
38
+ target_clm = resolve_clm_path(clm_root, target_clm)
39
+ engine_py = os.path.join(clm_root, "kernel/scripts/clm_runner.py")
40
+ cmd = [sys.executable, engine_py, "evaluate", gate_file, target_clm]
41
+ if exit_code is not None:
42
+ cmd.append(str(exit_code))
43
+ env = os.environ.copy()
44
+ env["CLM_NESTED_EXEC"] = "1"
45
+ env["CLM_NESTED_FILE"] = os.path.abspath(gate_file)
46
+ env["CLM_SKIP_CONDITIONS"] = "1"
47
+ proc = subprocess.Popen(cmd, env=env)
48
+ proc.wait()
49
+ return proc.returncode
50
+
51
+ def compose_conditions_cmd(clm_root: str, clm_file: str, phase: str, exit_code: int = 0) -> int:
52
+ """
53
+ Composes and runs the sequence of gate PCards for a given execution phase (pre or post).
54
+
55
+ Args:
56
+ clm_root (str): The root directory of the CLM workspace.
57
+ clm_file (str): The target PCard being executed.
58
+ phase (str): The phase of execution ('pre' or 'post').
59
+ exit_code (int): The exit code from the execution (for 'post' phase).
60
+
61
+ Returns:
62
+ int: The exit code of the gate evaluations. 0 if successful, non-zero otherwise.
63
+ """
64
+ load_normalized_manifest = get_load_manifest()
65
+ clm_file = resolve_clm_path(clm_root, clm_file)
66
+ custom_pcard = None
67
+ if os.path.exists(clm_file):
68
+ try:
69
+ data = load_normalized_manifest(clm_root, clm_file)
70
+ inner = data.get("clm", data)
71
+ concrete = inner.get("concrete_impl", {})
72
+ if phase == "pre":
73
+ pre = concrete.get("precondition", {})
74
+ if pre:
75
+ custom_pcard = pre.get("vcard_pre")
76
+ elif phase == "post":
77
+ post = concrete.get("postcondition", {})
78
+ if post:
79
+ custom_pcard = post.get("vcard_post")
80
+ except Exception:
81
+ pass
82
+
83
+ if custom_pcard:
84
+ orig_custom_pcard = custom_pcard
85
+ if custom_pcard.startswith("gate:"):
86
+ gate_name = custom_pcard.split("gate:")[1]
87
+ custom_pcard = f"computable_knowledge/Abstract/layer5_system/bootstrap/governance/gates/{gate_name}.yaml"
88
+ elif custom_pcard.startswith(HASH_PREFIX):
89
+ target = "clm.layer2.storage"
90
+ mod = sys.modules.get(target)
91
+ if mod is None:
92
+ __import__(target)
93
+ mod = sys.modules.get(target)
94
+ if mod is not None:
95
+ db = mod.CLMDB(clm_root)
96
+ repo = mod.CLMRepository(db, clm_root)
97
+ handle = repo.get_handle_by_hash(custom_pcard, "content_memory")
98
+ if handle and handle.startswith("gate:"):
99
+ gate_name = handle.split("gate:")[1]
100
+ custom_pcard = f"computable_knowledge/Abstract/layer5_system/bootstrap/governance/gates/{gate_name}.yaml"
101
+
102
+ resolved_custom_pcard = resolve_clm_path(clm_root, custom_pcard)
103
+ custom_gate = None
104
+ if resolved_custom_pcard and os.path.exists(resolved_custom_pcard):
105
+ try:
106
+ gate_data = load_normalized_manifest(clm_root, resolved_custom_pcard)
107
+ inner_gate = gate_data.get("clm", gate_data)
108
+ custom_gate = inner_gate.get("concrete_impl", {}).get("operation")
109
+ except Exception:
110
+ pass
111
+
112
+ if custom_gate:
113
+ _logger.info(f"[COMPOSE] Discovered custom {phase} gate: {custom_gate} (from {orig_custom_pcard})")
114
+
115
+ override_gate = os.environ.get("CLM_GATE_OVERRIDE", "0") == "1"
116
+ expr = ""
117
+ if phase == "pre":
118
+ if custom_pcard:
119
+ if override_gate:
120
+ expr = custom_pcard
121
+ elif custom_pcard in ["computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/verify_precondition.yaml", "computable_knowledge/Abstract/layer5_system/bootstrap/governance/gates/payload_nonempty.yaml"]:
122
+ expr = "computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/verify_precondition.yaml"
123
+ else:
124
+ expr = f"computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/verify_precondition.yaml >>> {custom_pcard}"
125
+ else:
126
+ expr = "computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/verify_precondition.yaml"
127
+ else:
128
+ if custom_pcard:
129
+ if override_gate:
130
+ expr = custom_pcard
131
+ elif custom_pcard in ["computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/validate_postcondition.yaml", "computable_knowledge/Abstract/layer5_system/bootstrap/governance/gates/result_sealed.yaml"]:
132
+ expr = "computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/validate_postcondition.yaml"
133
+ else:
134
+ expr = f"computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/validate_postcondition.yaml >>> {custom_pcard}"
135
+ else:
136
+ expr = "computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/validate_postcondition.yaml"
137
+
138
+ seq_gates = [g.strip() for g in expr.split(">>>")]
139
+ for gate in seq_gates:
140
+ if not gate:
141
+ continue
142
+ _logger.info(f"[COMPOSE] Executing Gate: {gate}")
143
+ if gate == "computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/verify_precondition.yaml":
144
+ if not verify_precondition(clm_root, clm_file):
145
+ _logger.info("CRITICAL: Pre-Gate Failed.")
146
+ return 1
147
+ elif gate == "computable_knowledge/Abstract/layer5_system/bootstrap/evaluator/validate_postcondition.yaml":
148
+ if not validate_postcondition(clm_root, clm_file, exit_code):
149
+ _logger.info("CRITICAL: Post-Gate Failed.")
150
+ return 1
151
+ else:
152
+ rc = run_nested_evaluate(clm_root, gate, clm_file, exit_code if phase == "post" else None)
153
+ if rc != 0:
154
+ _logger.info(f"CRITICAL: Gate {gate} Failed with exit code {rc}")
155
+ return rc
156
+ return 0
157
+
158
+ def execute_composed_pcard_py(
159
+ clm_root: str,
160
+ expr: str,
161
+ phase: str,
162
+ exit_code: int = 0,
163
+ payload: str = "",
164
+ lookup: dict[str, Callable] | None = None
165
+ ) -> int:
166
+ """
167
+ Python-native monadic composition executor.
168
+ Supports >>> (sequential), ⊗ (tensor/parallel), and id (passthrough).
169
+ """
170
+ if lookup is None:
171
+ lookup = {}
172
+
173
+ expr = expr.strip()
174
+ if not expr or expr == "id":
175
+ return 0
176
+
177
+ # 1. Sequential composition (>>>) has lowest precedence (splits first)
178
+ if ">>>" in expr:
179
+ # Split by >>>
180
+ parts = [p.strip() for p in expr.split(">>>")]
181
+ for part in parts:
182
+ if not part:
183
+ continue
184
+ rc = execute_composed_pcard_py(clm_root, part, phase, exit_code, payload, lookup)
185
+ if rc != 0:
186
+ return rc
187
+ return 0
188
+
189
+ # 2. Tensor Product Composition (⊗)
190
+ if "⊗" in expr:
191
+ parts = [p.strip() for p in expr.split("⊗")]
192
+ threads = []
193
+ results = []
194
+
195
+ def worker(part):
196
+ rc = execute_composed_pcard_py(clm_root, part, phase, exit_code, payload, lookup)
197
+ results.append(rc)
198
+
199
+ for part in parts:
200
+ if not part:
201
+ continue
202
+ t = threading.Thread(target=worker, args=(part,))
203
+ threads.append(t)
204
+ t.start()
205
+
206
+ for t in threads:
207
+ t.join()
208
+
209
+ for rc in results:
210
+ if rc != 0:
211
+ return rc
212
+ return 0
213
+
214
+ # 3. Base case: single gate
215
+ gate = expr
216
+ if gate in lookup:
217
+ func = lookup[gate]
218
+ try:
219
+ rc = func(payload) if phase == "pre" else func(exit_code, payload)
220
+ if isinstance(rc, bool):
221
+ return 0 if rc else 1
222
+ if rc is None:
223
+ return 0
224
+ return int(rc)
225
+ except Exception as e:
226
+ _logger.error(f"[COMPOSE] Error running gate function '{gate}': {e}")
227
+ return 1
228
+
229
+ return run_nested_evaluate(clm_root, gate, payload, exit_code if phase == "post" else None)
@@ -0,0 +1,298 @@
1
+ """Declarative VCard Hoare Sandwich Engine (Sprint 394 / DEL-394-01).
2
+
3
+ Implements the formal Hoare Triple verification lifecycle:
4
+ {V_pre} Action {V_post}
5
+ Enforces pre-condition invariant gating, operator execution, post-condition lattice
6
+ witness certification, and atomic <1.0ms rollback on violation.
7
+
8
+ Acceptance Criteria:
9
+ - AC-394-01-01: Passing V_pre & V_post completes Z4 lifecycle, outputs certified MCard & VCardReceipt.
10
+ - AC-394-01-02: Failing V_pre aborts with PreconditionBreachError without invoking operator.
11
+ - AC-394-01-03: Failing V_post triggers <1ms atomic rollback, raising PostconditionBreachError.
12
+
13
+ Layer 1 module (no static imports above L1).
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import sys
19
+ import time
20
+ from dataclasses import dataclass, field
21
+ from pathlib import Path
22
+ from typing import Any
23
+
24
+ from clm.cross_cutting.domain_models import MCard
25
+ from clm.layer0.exceptions import CLMError
26
+ from clm.layer0.model.action import ActionManifest
27
+ from clm.layer0.model.card_triad import compute_canonical_hash
28
+ from clm.layer0.rule_evaluator import SafeRuleEvaluator
29
+ from clm.layer1.action_dispatcher import ActionDispatcher
30
+ from clm.layer1.savepoint_guard import VCardMeetViolation, z4_savepoint_guard
31
+
32
+
33
+ class PreconditionBreachError(CLMError):
34
+ """Raised when an Action precondition (V_pre) evaluates to false."""
35
+
36
+
37
+ class PostconditionBreachError(CLMError):
38
+ """Raised when an Action postcondition (V_post) evaluates to false, triggering rollback."""
39
+
40
+
41
+ @dataclass(frozen=True)
42
+ class HoareSandwichResult:
43
+ """Certified result of an Action executed inside the Hoare Sandwich."""
44
+
45
+ status: str
46
+ action_name: str
47
+ outputs: dict[str, MCard] = field(default_factory=dict)
48
+ receipt: MCard | None = None
49
+ precondition_verdicts: list[dict[str, Any]] = field(default_factory=list)
50
+ postcondition_verdicts: list[dict[str, Any]] = field(default_factory=list)
51
+ rollback_occurred: bool = False
52
+ rollback_time_ms: float = 0.0
53
+ metrics: dict[str, Any] = field(default_factory=dict)
54
+ error: str | None = None
55
+
56
+ @property
57
+ def is_success(self) -> bool:
58
+ return self.status == "success"
59
+
60
+
61
+ class HoareSandwichEngine:
62
+ """Executes Action manifests within the {V_pre} Action {V_post} Hoare Sandwich."""
63
+
64
+ @classmethod
65
+ def execute(
66
+ cls,
67
+ manifest: ActionManifest | str | Path | dict[str, Any],
68
+ input_bindings: dict[str, Any] | None = None,
69
+ fs: Any = None,
70
+ ) -> HoareSandwichResult:
71
+ """Execute Action with full pre- and post-condition verification."""
72
+ t_start = time.perf_counter()
73
+
74
+ # 1. Parse manifest
75
+ if isinstance(manifest, (str, Path)):
76
+ action = ActionManifest.from_yaml(manifest)
77
+ elif isinstance(manifest, dict):
78
+ action = ActionManifest.from_dict(manifest)
79
+ elif isinstance(manifest, ActionManifest):
80
+ action = manifest
81
+ else:
82
+ raise TypeError(f"Invalid manifest type: {type(manifest)}")
83
+
84
+ action_hash = compute_canonical_hash(action.to_dict())
85
+
86
+ # 2. Build Precondition Context
87
+ bindings = dict(input_bindings or {})
88
+ if fs is not None:
89
+ for k, v in list(bindings.items()):
90
+ if isinstance(v, str) and (v.startswith("mcard:") or v.startswith("mcard://")):
91
+ clean_uri = v
92
+ if clean_uri.startswith("mcard://"):
93
+ clean_uri = "mcard:" + clean_uri[len("mcard://"):]
94
+ try:
95
+ resolved_card = fs.read_file(clean_uri)
96
+ if resolved_card is not None:
97
+ bindings[k] = resolved_card
98
+ except Exception:
99
+ pass
100
+
101
+ pre_ctx: dict[str, Any] = {}
102
+ for inp in action.inputs:
103
+ bound_val = bindings.get(inp.name)
104
+ if bound_val is not None:
105
+ card_or_data = bound_val.payload if isinstance(bound_val, MCard) else bound_val
106
+ ctx_info = cls._build_item_context(card_or_data, bound_val)
107
+ pre_ctx[inp.name] = ctx_info
108
+ # Also expose single input as 'input'
109
+ if len(action.inputs) == 1 or inp.name == "dataset":
110
+ pre_ctx["input"] = ctx_info
111
+
112
+ # 3. Phase 1: Evaluate Preconditions (V_pre)
113
+ pre_verdicts: list[dict[str, Any]] = []
114
+ for pre in action.preconditions:
115
+ try:
116
+ passed = SafeRuleEvaluator.evaluate(pre.rule, pre_ctx)
117
+ except Exception as e:
118
+ raise PreconditionBreachError(
119
+ f"Precondition '{pre.invariant}' evaluation error: {e}"
120
+ ) from e
121
+
122
+ verdict = {
123
+ "invariant": pre.invariant,
124
+ "rule": pre.rule,
125
+ "passed": passed,
126
+ "description": pre.description,
127
+ }
128
+ pre_verdicts.append(verdict)
129
+
130
+ # AC-394-01-02: Abort immediately prior to operator execution
131
+ if not passed:
132
+ raise PreconditionBreachError(
133
+ f"Precondition '{pre.invariant}' violated: '{pre.rule}' evaluated to false"
134
+ )
135
+
136
+ # 4. Phase 2 & 3: Savepoint-Guarded Execution and Postcondition Verification
137
+ # If filesystem has a connection, wrap in z4_savepoint_guard
138
+ conn = getattr(fs, "conn", None)
139
+
140
+ if conn is not None:
141
+ # Transactional Savepoint Guard active
142
+ try:
143
+ with z4_savepoint_guard(conn, step_id=f"hoare_{action.clm.name}") as guard:
144
+ exec_result = ActionDispatcher.execute(action, bindings, fs=fs)
145
+ if not exec_result.is_success:
146
+ guard.fail_meet(exec_result.error or "Operator execution failure")
147
+
148
+ # Phase 3: Evaluate Postconditions (V_post)
149
+ post_ctx = cls._build_post_context(pre_ctx, exec_result.outputs)
150
+ post_verdicts = cls._eval_postconditions(action.postconditions, post_ctx)
151
+
152
+ # Advance guard to commit
153
+ guard.advance_phase(3)
154
+
155
+ except VCardMeetViolation as e:
156
+ raise PostconditionBreachError(f"Postcondition breach: {e}") from e
157
+
158
+ else:
159
+ # In-memory execution without direct sqlite connection
160
+ exec_result = ActionDispatcher.execute(action, bindings, fs=fs)
161
+ if not exec_result.is_success:
162
+ raise CLMError(f"Action execution failed: {exec_result.error}")
163
+
164
+ post_ctx = cls._build_post_context(pre_ctx, exec_result.outputs)
165
+ post_verdicts = cls._eval_postconditions(action.postconditions, post_ctx)
166
+
167
+ # 5. Phase 4: Generate VCardReceipt and complete Hoare Sandwich
168
+ receipt = cls._generate_receipt(
169
+ action_name=action.clm.name,
170
+ action_hash=action_hash,
171
+ input_hashes=exec_result.input_hashes,
172
+ output_hashes=exec_result.output_hashes,
173
+ pre_verdicts=pre_verdicts,
174
+ post_verdicts=post_verdicts,
175
+ metrics=exec_result.metrics,
176
+ )
177
+
178
+ t_elapsed = (time.perf_counter() - t_start) * 1000.0
179
+
180
+ return HoareSandwichResult(
181
+ status="success",
182
+ action_name=action.clm.name,
183
+ outputs=exec_result.outputs,
184
+ receipt=receipt,
185
+ precondition_verdicts=pre_verdicts,
186
+ postcondition_verdicts=post_verdicts,
187
+ metrics={
188
+ **exec_result.metrics,
189
+ "hoare_total_time_ms": round(t_elapsed, 3),
190
+ },
191
+ )
192
+
193
+ @classmethod
194
+ def _eval_postconditions(
195
+ cls,
196
+ postconditions: list[Any],
197
+ context: dict[str, Any],
198
+ ) -> list[dict[str, Any]]:
199
+ """Evaluate all postconditions, raising PostconditionBreachError on failure."""
200
+ post_verdicts: list[dict[str, Any]] = []
201
+ for post in postconditions:
202
+ try:
203
+ passed = SafeRuleEvaluator.evaluate(post.rule, context)
204
+ except Exception as e:
205
+ raise PostconditionBreachError(
206
+ f"Postcondition '{post.invariant}' evaluation error: {e}"
207
+ ) from e
208
+
209
+ verdict = {
210
+ "invariant": post.invariant,
211
+ "rule": post.rule,
212
+ "passed": passed,
213
+ "description": post.description,
214
+ }
215
+ post_verdicts.append(verdict)
216
+
217
+ # AC-394-01-03: Failing postcondition halts execution and triggers rollback
218
+ if not passed:
219
+ raise PostconditionBreachError(
220
+ f"Postcondition '{post.invariant}' violated: '{post.rule}' evaluated to false"
221
+ )
222
+ return post_verdicts
223
+
224
+ @staticmethod
225
+ def _build_item_context(payload: Any, card: Any = None) -> dict[str, Any]:
226
+ """Extract structured properties for rule evaluation context."""
227
+ ctx: dict[str, Any] = {}
228
+ if isinstance(payload, str):
229
+ ctx["size_bytes"] = len(payload.encode("utf-8"))
230
+ lines = [ln for ln in payload.splitlines() if ln.strip()]
231
+ ctx["line_count"] = len(lines)
232
+ if lines and ("," in lines[0] or "\t" in lines[0]):
233
+ cols = [c.strip() for c in lines[0].split(",")]
234
+ ctx["columns"] = cols
235
+ ctx["column_count"] = len(cols)
236
+ ctx["row_count"] = len(lines) - 1
237
+ elif isinstance(payload, bytes):
238
+ ctx["size_bytes"] = len(payload)
239
+ elif isinstance(payload, dict):
240
+ ctx["keys"] = list(payload.keys())
241
+ ctx["key_count"] = len(payload)
242
+ ctx.update(payload)
243
+ elif isinstance(payload, list):
244
+ ctx["item_count"] = len(payload)
245
+ ctx["row_count"] = len(payload)
246
+
247
+ if card and hasattr(card, "metadata") and isinstance(card.metadata, dict):
248
+ ctx.update(card.metadata)
249
+
250
+ return ctx
251
+
252
+ @classmethod
253
+ def _build_post_context(
254
+ cls,
255
+ pre_ctx: dict[str, Any],
256
+ outputs: dict[str, MCard],
257
+ ) -> dict[str, Any]:
258
+ """Assemble combined context (input + output) for postcondition evaluation."""
259
+ post_ctx = dict(pre_ctx)
260
+ out_dict: dict[str, Any] = {}
261
+ for name, card in outputs.items():
262
+ info = cls._build_item_context(card.payload, card)
263
+ out_dict[name] = info
264
+
265
+ post_ctx["output"] = out_dict
266
+ if len(outputs) == 1:
267
+ # Expose primary output attributes directly on 'output'
268
+ primary_name = next(iter(outputs.keys()))
269
+ post_ctx["output"].update(out_dict[primary_name])
270
+
271
+ return post_ctx
272
+
273
+ @staticmethod
274
+ def _generate_receipt(
275
+ action_name: str,
276
+ action_hash: str,
277
+ input_hashes: dict[str, str],
278
+ output_hashes: dict[str, str],
279
+ pre_verdicts: list[dict[str, Any]],
280
+ post_verdicts: list[dict[str, Any]],
281
+ metrics: dict[str, Any] | None = None,
282
+ ) -> MCard:
283
+ """Deferred dynamic invocation of Layer 2 VCardReceipt generator."""
284
+ target = "clm.layer2.vcard_receipt"
285
+ mod = sys.modules.get(target)
286
+ if mod is None:
287
+ __import__(target)
288
+ mod = sys.modules.get(target)
289
+ fn = mod.generate_vcard_receipt
290
+ return fn(
291
+ action_name=action_name,
292
+ action_hash=action_hash,
293
+ input_hashes=input_hashes,
294
+ output_hashes=output_hashes,
295
+ precondition_verdicts=pre_verdicts,
296
+ postcondition_verdicts=post_verdicts,
297
+ metrics=metrics,
298
+ )