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
clm/layer0/loader.py ADDED
@@ -0,0 +1,826 @@
1
+ """CLM Chapter & YAML Template Loader (Layer 0).
2
+
3
+ Part of Phase 7 (Sprint 383: Layer 0 Kenotic Core & Parser Unification).
4
+ Loads CLM Chapter specifications and templates from YAML, parses dimensional metadata,
5
+ and dynamically constructs executable Chapter objects.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import os
11
+ from typing import Any
12
+
13
+ import yaml
14
+
15
+ from clm.layer0.narrative import Chapter, CLMConfiguration, NarrativeMonad
16
+
17
+ # ─────────────────────────────────────────────────────────────────────────────
18
+ # Constants
19
+ # ─────────────────────────────────────────────────────────────────────────────
20
+
21
+ CLM_EXTENSIONS = (".clm", ".yaml", ".yml")
22
+ CODE_READABLE_RUNTIMES = ("python", "javascript")
23
+ MODULE_URI_PREFIX = "module://"
24
+ DEFAULT_RUNTIME = "python"
25
+ DEFAULT_TARGET = "dummy_target"
26
+
27
+ # Runtime factory hook for Layer 1 execution engines (Dependency Inversion for INV-383-02)
28
+ _runtime_factory: Any = None
29
+
30
+
31
+ def register_runtime_factory(factory: Any) -> None:
32
+ """Register runtime factory from Layer 1."""
33
+ global _runtime_factory
34
+ _runtime_factory = factory
35
+
36
+
37
+ def _resolve_runtime_factory() -> Any:
38
+ global _runtime_factory
39
+ if _runtime_factory is not None:
40
+ return _runtime_factory
41
+ import sys
42
+
43
+ runtimes_mod = sys.modules.get("clm.layer1.runtimes")
44
+ if runtimes_mod and hasattr(runtimes_mod, "RuntimeFactory"):
45
+ return runtimes_mod.RuntimeFactory
46
+ return None
47
+
48
+
49
+
50
+ # ─────────────────────────────────────────────────────────────────────────────
51
+ # Path Resolution Utilities
52
+ # ─────────────────────────────────────────────────────────────────────────────
53
+
54
+
55
+ def _resolve_path(base_dir: str, path: str) -> str:
56
+ """Resolve a relative path against a base directory."""
57
+ if os.path.isabs(path):
58
+ return path
59
+ return os.path.join(base_dir, path)
60
+
61
+
62
+ def _is_module_uri(path: str) -> bool:
63
+ """Check if path is a module:// URI."""
64
+ return path.startswith(MODULE_URI_PREFIX)
65
+
66
+
67
+ def _resolve_concrete_paths(concrete: dict, base_dir: str, runtime: str) -> None:
68
+ """Resolve all file paths in concrete config relative to base_dir.
69
+ Modifies concrete dict in-place.
70
+ """
71
+ # code_file resolution
72
+ if "code_file" in concrete and not _is_module_uri(concrete["code_file"]):
73
+ code_path = _resolve_path(base_dir, concrete["code_file"])
74
+ concrete["code_file"] = code_path
75
+ # Read code content for runtimes that need it
76
+ if runtime in CODE_READABLE_RUNTIMES and os.path.exists(code_path):
77
+ with open(code_path) as f:
78
+ concrete["code"] = f.read()
79
+
80
+ # binary_path resolution
81
+ if "binary_path" in concrete and not os.path.isabs(concrete["binary_path"]):
82
+ concrete["binary_path"] = _resolve_path(base_dir, concrete["binary_path"])
83
+
84
+ # wasm_module resolution
85
+ if "wasm_module" in concrete and not os.path.isabs(concrete["wasm_module"]):
86
+ concrete["wasm_module"] = _resolve_path(base_dir, concrete["wasm_module"])
87
+
88
+
89
+ def _parse_numeric_result(result: Any) -> Any:
90
+ """Attempt to parse a string result as a number."""
91
+ if isinstance(result, str):
92
+ clean = result.strip()
93
+ # Check if it looks numeric (handles negatives and decimals)
94
+ if clean.lstrip("-").replace(".", "", 1).isdigit():
95
+ try:
96
+ return float(clean) if "." in clean else int(clean)
97
+ except ValueError:
98
+ pass
99
+ return result
100
+
101
+
102
+ # ─────────────────────────────────────────────────────────────────────────────
103
+ # YAML Template Loader
104
+ # ─────────────────────────────────────────────────────────────────────────────
105
+
106
+
107
+ class YAMLTemplateLoader:
108
+ """Loads CLM YAML templates from a templates directory."""
109
+
110
+ def __init__(self, templates_dir: str | None = None):
111
+ if templates_dir:
112
+ self.templates_dir = templates_dir
113
+ else:
114
+ current_dir = os.path.dirname(os.path.abspath(__file__))
115
+ candidate_dirs = [
116
+ os.path.join(current_dir, "templates"),
117
+ os.path.abspath(
118
+ os.path.join(
119
+ current_dir,
120
+ "../../../../clm/computable_knowledge/manifests/templates",
121
+ )
122
+ ),
123
+ os.path.abspath(
124
+ os.path.join(
125
+ current_dir,
126
+ "../../../../mcard/ptr/clm/templates",
127
+ )
128
+ ),
129
+ ]
130
+ self.templates_dir = candidate_dirs[0]
131
+ for c_dir in candidate_dirs:
132
+ if os.path.exists(c_dir):
133
+ self.templates_dir = c_dir
134
+ break
135
+
136
+ def load_template(self, template_name: str) -> dict[str, Any]:
137
+ """Load a specific YAML template by name."""
138
+ for ext in CLM_EXTENSIONS:
139
+ file_path = os.path.join(self.templates_dir, f"{template_name}{ext}")
140
+ if os.path.exists(file_path):
141
+ with open(file_path) as f:
142
+ return yaml.safe_load(f)
143
+ raise FileNotFoundError(f"Template not found: {template_name}")
144
+
145
+ def load_all_templates(self) -> dict[str, dict[str, Any]]:
146
+ """Load all templates in the directory."""
147
+ templates = {}
148
+ if not os.path.exists(self.templates_dir):
149
+ return templates
150
+
151
+ for filename in os.listdir(self.templates_dir):
152
+ if filename.endswith(CLM_EXTENSIONS):
153
+ name = os.path.splitext(filename)[0]
154
+ with open(os.path.join(self.templates_dir, filename)) as f:
155
+ templates[name] = yaml.safe_load(f)
156
+ return templates
157
+
158
+
159
+ # ─────────────────────────────────────────────────────────────────────────────
160
+ # CLM Chapter Loader
161
+ # ─────────────────────────────────────────────────────────────────────────────
162
+
163
+
164
+ class CLMChapterLoader:
165
+ """Loads Chapter objects from YAML specifications."""
166
+
167
+ @staticmethod
168
+ def _parse_clm_data(data: dict, yaml_path: str) -> tuple:
169
+ """Parse CLM data and return (chapter_data, clm_data, clm_config).
170
+ Handles both 'chapter' format and raw PCard format.
171
+ """
172
+ if "chapter" in data:
173
+ chapter_data = data["chapter"]
174
+ # Provide defaults for optional fields
175
+ chapter_data.setdefault("mvp_card", "CLM Execution")
176
+ chapter_data.setdefault("pkc_task", "Runtime Execution")
177
+ clm_data = data["clm"]
178
+
179
+ # Support aliases for dimensions
180
+ abstract = clm_data.get("abstract_spec", clm_data.get("abstract", {}))
181
+ concrete = clm_data.get("concrete_impl", clm_data.get("concrete", {}))
182
+ balanced = clm_data.get("balanced_exp", clm_data.get("balanced", {}))
183
+
184
+ # Update clm_data for internal use
185
+ clm_data["abstract"] = abstract
186
+ clm_data["concrete"] = concrete
187
+ clm_data["balanced"] = balanced
188
+
189
+ # Default to lambda runtime if none specified
190
+ if "runtime" not in clm_data["concrete"]:
191
+ if "builtin" in clm_data["concrete"]:
192
+ clm_data["concrete"]["runtime"] = "python"
193
+ else:
194
+ clm_data["concrete"]["runtime"] = "lambda"
195
+
196
+ # Synthesise concrete summary from structural fields when no explicit description
197
+ concrete_desc = concrete.get(
198
+ "manifestation", concrete.get("description", None)
199
+ )
200
+ if not concrete_desc:
201
+ parts = []
202
+ if concrete.get("runtime"):
203
+ parts.append(f"runtime={concrete['runtime']}")
204
+ if concrete.get("provider"):
205
+ parts.append(f"provider={concrete['provider']}")
206
+ if concrete.get("model"):
207
+ parts.append(f"model={concrete['model']}")
208
+ if concrete.get("builtin"):
209
+ parts.append(f"builtin={concrete['builtin']}")
210
+ concrete_desc = ", ".join(parts) if parts else "Unknown"
211
+
212
+ # Synthesise balanced summary from test_cases when no explicit description
213
+ balanced_desc = balanced.get(
214
+ "expectation", balanced.get("description", None)
215
+ )
216
+ if not balanced_desc:
217
+ test_cases = balanced.get("test_cases", [])
218
+ if test_cases:
219
+ case_labels = [
220
+ tc.get("description", tc.get("given", f"case {i + 1}"))
221
+ for i, tc in enumerate(test_cases[:3])
222
+ ]
223
+ balanced_desc = f"{len(test_cases)} test case(s): {'; '.join(str(c) for c in case_labels)}"
224
+ else:
225
+ balanced_desc = "Unknown"
226
+
227
+ clm = CLMConfiguration(
228
+ abstract=abstract.get("concept", abstract.get("purpose", "Unknown")),
229
+ concrete=concrete_desc,
230
+ balanced=balanced_desc,
231
+ )
232
+ else:
233
+ # Fallback for raw PCards
234
+ metadata = data.get("metadata", {})
235
+ chapter_data = {
236
+ "id": 0,
237
+ "title": metadata.get("name", os.path.basename(yaml_path)),
238
+ "mvp_card": "Raw PCard",
239
+ "pkc_task": "Execution",
240
+ }
241
+ clm_data = data.get("clm", data)
242
+
243
+ # Support aliases for dimensions
244
+ abstract = clm_data.get("abstract_spec", clm_data.get("abstract", {}))
245
+ concrete = clm_data.get("concrete_impl", clm_data.get("concrete", {}))
246
+ balanced = clm_data.get("balanced_expc", clm_data.get("balanced", {}))
247
+
248
+ abstract_val = (
249
+ abstract
250
+ if isinstance(abstract, str)
251
+ else abstract.get("concept", abstract.get("purpose", "Unknown"))
252
+ )
253
+ if isinstance(concrete, str):
254
+ concrete_val = concrete
255
+ else:
256
+ concrete_val = concrete.get(
257
+ "manifestation",
258
+ concrete.get("operation", concrete.get("description", None)),
259
+ )
260
+ if not concrete_val:
261
+ parts = []
262
+ if concrete.get("runtime"):
263
+ parts.append(f"runtime={concrete['runtime']}")
264
+ if concrete.get("provider"):
265
+ parts.append(f"provider={concrete['provider']}")
266
+ if concrete.get("model"):
267
+ parts.append(f"model={concrete['model']}")
268
+ if concrete.get("builtin"):
269
+ parts.append(f"builtin={concrete['builtin']}")
270
+ concrete_val = ", ".join(parts) if parts else "Unknown"
271
+
272
+ if isinstance(balanced, str):
273
+ balanced_val = balanced
274
+ else:
275
+ balanced_val = balanced.get(
276
+ "expectation", balanced.get("description", None)
277
+ )
278
+ if not balanced_val:
279
+ test_cases = balanced.get("test_cases", [])
280
+ if test_cases:
281
+ case_labels = [
282
+ tc.get("description", tc.get("given", f"case {i + 1}"))
283
+ for i, tc in enumerate(test_cases[:3])
284
+ ]
285
+ balanced_val = f"{len(test_cases)} test case(s): {'; '.join(str(c) for c in case_labels)}"
286
+ else:
287
+ balanced_val = "Unknown"
288
+
289
+ clm = CLMConfiguration(
290
+ abstract=abstract_val,
291
+ concrete=concrete_val,
292
+ balanced=balanced_val,
293
+ )
294
+
295
+ # Ensure clm_data has normalized keys for the rest of the loader
296
+ clm_data["abstract"] = abstract
297
+ clm_data["concrete"] = concrete
298
+ clm_data["balanced"] = balanced
299
+
300
+ # Resolve engine mapping for backward compatibility
301
+ if (
302
+ "runtime" not in clm_data["concrete"]
303
+ and "engine" in clm_data["concrete"]
304
+ ):
305
+ engine_val = str(clm_data["concrete"]["engine"]).lower()
306
+ if "python" in engine_val:
307
+ clm_data["concrete"]["runtime"] = "python"
308
+ elif "node" in engine_val or "javascript" in engine_val:
309
+ clm_data["concrete"]["runtime"] = "javascript"
310
+ else:
311
+ clm_data["concrete"]["runtime"] = clm_data["concrete"]["engine"]
312
+
313
+ # Default runtime selection
314
+ if "runtime" not in clm_data["concrete"]:
315
+ if "builtin" in clm_data["concrete"]:
316
+ clm_data["concrete"]["runtime"] = "python"
317
+ else:
318
+ clm_data["concrete"]["runtime"] = "lambda"
319
+
320
+ return chapter_data, clm_data, clm
321
+
322
+ @staticmethod
323
+ def _is_clm_runtime(runtime: str) -> bool:
324
+ """Check if runtime is a CLM file reference."""
325
+ return any(runtime.endswith(ext) for ext in CLM_EXTENSIONS)
326
+
327
+ @staticmethod
328
+ def _create_recursive_executor(
329
+ yaml_path: str, runtime: str, chapter_data: dict, clm_data: dict
330
+ ):
331
+ """Create an executor for recursive CLM runtime."""
332
+ base_dir = os.path.dirname(yaml_path)
333
+ runtime_path = _resolve_path(base_dir, runtime)
334
+
335
+ def execute(concrete, target, ctx):
336
+ if not os.path.exists(runtime_path):
337
+ return f"Error: Recursive runtime file not found: {runtime_path}"
338
+
339
+ meta_context = ctx.copy()
340
+ meta_context["source_pcard_title"] = chapter_data.get("title", "Unknown")
341
+ meta_context["concrete"] = concrete
342
+ meta_context["abstract"] = clm_data.get("abstract", {})
343
+ meta_context["__input_content__"] = target.get_content()
344
+ meta_context["__skip_tests__"] = True
345
+
346
+ meta_chapter = CLMChapterLoader.load_from_yaml(runtime_path)
347
+ result_tuple = meta_chapter.action.execute(
348
+ meta_context, {"collection": None}
349
+ )
350
+ return result_tuple[0]
351
+
352
+ class RecursiveExecutor:
353
+ def execute(self, concrete, target, ctx):
354
+ return execute(concrete, target, ctx)
355
+
356
+ return RecursiveExecutor()
357
+
358
+ @staticmethod
359
+ def _execute_single_run(
360
+ executor, concrete: dict, config_ctx: dict, runtime: str
361
+ ) -> NarrativeMonad:
362
+ """Execute a single run (no test cases)."""
363
+ from clm.layer0.model.card import MCard
364
+
365
+ target_content = config_ctx.get("__input_content__", DEFAULT_TARGET)
366
+
367
+ try:
368
+ target = MCard(target_content)
369
+ result = executor.execute(concrete, target, config_ctx)
370
+
371
+ if isinstance(result, NarrativeMonad):
372
+
373
+ def run_with_config(_, state):
374
+ return result.run(config_ctx, state)
375
+
376
+ return NarrativeMonad(run_with_config)
377
+
378
+ result = _parse_numeric_result(result)
379
+
380
+ return NarrativeMonad.log(f"Executed {runtime} (Single): {result}").bind(
381
+ lambda _: NarrativeMonad.unit(result)
382
+ )
383
+ except (ValueError, TypeError, RuntimeError) as e:
384
+ return NarrativeMonad.log(f"Execution failed: {e}").bind(
385
+ lambda _: NarrativeMonad.unit(None)
386
+ )
387
+
388
+ @staticmethod
389
+ def _execute_test_cases(
390
+ executor, concrete: dict, config_ctx: dict, test_cases: list[dict]
391
+ ) -> NarrativeMonad:
392
+ """Execute all test cases and return a report."""
393
+ from clm.layer0.model.card import MCard
394
+
395
+ results = []
396
+ log_entries = [f"Running {len(test_cases)} test cases..."]
397
+ all_passed = True
398
+
399
+ try:
400
+ for i, case in enumerate(test_cases):
401
+ given_raw = case.get("given", "")
402
+ given_ctx = {}
403
+ if isinstance(given_raw, dict):
404
+ ctx = given_raw.get("context", {})
405
+ cond = given_raw.get("condition", {})
406
+ if isinstance(ctx, dict) and isinstance(cond, dict):
407
+ given_ctx = {**ctx, **cond}
408
+ elif isinstance(cond, dict):
409
+ given_ctx = cond
410
+ elif isinstance(ctx, dict):
411
+ given_ctx = ctx
412
+ if "description" in given_raw:
413
+ given = str(given_raw.get("description", ""))
414
+ elif "name" in given_raw:
415
+ given = str(given_raw.get("name", ""))
416
+ else:
417
+ given = str(given_raw)
418
+ else:
419
+ given = str(given_raw)
420
+ when = case.get("when", {})
421
+ then = case.get("then", {})
422
+
423
+ test_ctx = config_ctx.copy()
424
+ if isinstance(given_ctx, dict):
425
+ test_ctx.update(given_ctx)
426
+ test_ctx.update(when)
427
+ if "params" in when and isinstance(when["params"], dict):
428
+ test_ctx["params"] = when["params"]
429
+ test_ctx.update(when["params"])
430
+
431
+ test_concrete = concrete.copy()
432
+ case_executor = executor
433
+ if "assumption" in case and isinstance(case["assumption"], dict):
434
+ assumption = case["assumption"]
435
+ if "clm" in assumption and isinstance(assumption["clm"], dict):
436
+ if "concrete" in assumption["clm"] and isinstance(
437
+ assumption["clm"]["concrete"], dict
438
+ ):
439
+ test_concrete.update(assumption["clm"]["concrete"])
440
+
441
+ if "runtime" in test_concrete and test_concrete[
442
+ "runtime"
443
+ ] != concrete.get("runtime"):
444
+ rf = _resolve_runtime_factory()
445
+ if rf:
446
+ tmp_executor = rf.get_executor(test_concrete["runtime"])
447
+ if tmp_executor:
448
+ case_executor = tmp_executor
449
+
450
+ args = when.get("arguments", when.get("context", {}))
451
+ if (
452
+ not args
453
+ and "assumption" in case
454
+ and isinstance(case["assumption"], dict)
455
+ ):
456
+ args = case["assumption"].get("input_arguments", {})
457
+ if isinstance(args, dict):
458
+ test_ctx.update(args)
459
+
460
+ builtin = test_concrete.get("builtin")
461
+ if builtin in (
462
+ "isomorphism_pre",
463
+ "isomorphism_transition",
464
+ "isomorphism_post",
465
+ ):
466
+ rf = _resolve_runtime_factory()
467
+ if rf:
468
+ js_executor = rf.get_executor("javascript")
469
+ if js_executor:
470
+ case_executor = js_executor
471
+ test_concrete["runtime"] = "javascript"
472
+
473
+ if "name" in case and not given:
474
+ given = case["name"]
475
+ test_target = MCard(given)
476
+ res = case_executor.execute(test_concrete, test_target, test_ctx)
477
+
478
+ expected = then.get("result")
479
+ result_contains = then.get("result_contains")
480
+
481
+ if result_contains:
482
+ match = CLMChapterLoader._compare_contains(res, result_contains)
483
+ expected = f"contains '{result_contains}'"
484
+ else:
485
+ match = CLMChapterLoader._compare_results(
486
+ res, expected, then.get("epsilon")
487
+ )
488
+
489
+ if not match:
490
+ all_passed = False
491
+
492
+ status = "✅" if match else "❌"
493
+ log_entries.append(
494
+ f"Test {i + 1} [{given}]: {status} Got {res} (Expected {expected})"
495
+ )
496
+
497
+ results.append(
498
+ {
499
+ "case": i + 1,
500
+ "input": given,
501
+ "result": res,
502
+ "expected": expected,
503
+ "match": match,
504
+ }
505
+ )
506
+
507
+ report = {
508
+ "success": all_passed,
509
+ "total": len(results),
510
+ "passed_count": sum(1 for r in results if r["match"]),
511
+ "results": results,
512
+ }
513
+
514
+ return NarrativeMonad.log("\n".join(log_entries)).bind(
515
+ lambda _: NarrativeMonad.unit(report)
516
+ )
517
+
518
+ except (ValueError, TypeError, RuntimeError) as e:
519
+ return NarrativeMonad.log(f"Test Execution Failed: {e}").bind(
520
+ lambda _: NarrativeMonad.unit(None)
521
+ )
522
+
523
+ @staticmethod
524
+ def _compare_results(
525
+ actual: Any, expected: Any, epsilon: float | None = None
526
+ ) -> bool:
527
+ """Compare actual vs expected results with optional epsilon for floats."""
528
+ if expected is None:
529
+ return not (isinstance(actual, str) and actual.startswith("Error:"))
530
+
531
+ try:
532
+ if isinstance(expected, dict) and isinstance(actual, dict):
533
+ for k, v in expected.items():
534
+ if k not in actual:
535
+ return False
536
+ if not CLMChapterLoader._compare_results(actual[k], v, epsilon):
537
+ return False
538
+ return True
539
+
540
+ if isinstance(expected, int | float) and isinstance(actual, str):
541
+ actual_parsed = _parse_numeric_result(actual)
542
+ if isinstance(actual_parsed, int | float):
543
+ actual = actual_parsed
544
+
545
+ if isinstance(expected, int | float) and isinstance(actual, int | float):
546
+ if epsilon:
547
+ return abs(actual - expected) < float(epsilon)
548
+ return actual == expected
549
+
550
+ actual_str = str(actual).lower().strip()
551
+ expected_str = str(expected).lower().strip()
552
+
553
+ if actual_str in ("true", "false") and expected_str in ("true", "false"):
554
+ return actual_str == expected_str
555
+
556
+ return str(actual) == str(expected)
557
+ except Exception:
558
+ return str(actual) == str(expected)
559
+
560
+ @staticmethod
561
+ def _compare_contains(actual: Any, substring: str) -> bool:
562
+ """Check if actual result contains the expected substring."""
563
+ try:
564
+ return substring in str(actual)
565
+ except Exception:
566
+ return False
567
+
568
+ @staticmethod
569
+ def load_from_yaml(yaml_path: str) -> Chapter:
570
+ """Load a Chapter from a YAML file."""
571
+ with open(yaml_path) as f:
572
+ raw_content = f.read()
573
+ data = yaml.safe_load(raw_content)
574
+
575
+ from clm.layer0.model.pcard import PCard
576
+ pcard = PCard(raw_content)
577
+ base_dir = os.path.dirname(yaml_path)
578
+ chapter_data, clm_data, clm = CLMChapterLoader._parse_clm_data(data, yaml_path)
579
+
580
+ concrete = clm_data["concrete"]
581
+ runtime = concrete.get("runtime", DEFAULT_RUNTIME)
582
+ builtin = concrete.get("builtin")
583
+
584
+ def logic_func(_: Any) -> NarrativeMonad:
585
+ return NarrativeMonad.get_context().bind(
586
+ lambda ctx: NarrativeMonad.get_state().bind(
587
+ lambda state: process_with_petri_net(ctx, state)
588
+ )
589
+ )
590
+
591
+ def process_with_petri_net(ctx: dict, state: dict) -> NarrativeMonad:
592
+ collection = state.get("collection")
593
+
594
+ if collection:
595
+ try:
596
+ collection.add(pcard)
597
+ handle = pcard.get_transition_handle()
598
+ try:
599
+ collection.update_handle(handle, pcard)
600
+ except (KeyError, ValueError, AttributeError, TypeError):
601
+ try:
602
+ collection.add_with_handle(pcard, handle)
603
+ except (KeyError, ValueError, AttributeError, TypeError):
604
+ pass
605
+ except (KeyError, ValueError, AttributeError, TypeError):
606
+ pass
607
+
608
+ config_ctx = {k: v for k, v in concrete.items() if k != "logic_source"}
609
+ if not ctx.get("__skip_tests__"):
610
+ config_ctx["balanced"] = clm_data.get("balanced", {})
611
+
612
+ config_ctx.update(ctx)
613
+ config_ctx["pcard_dir"] = base_dir
614
+
615
+ _resolve_concrete_paths(concrete, base_dir, runtime)
616
+
617
+ execution_monad = _execute_core_logic(
618
+ ctx=ctx,
619
+ config_ctx=config_ctx,
620
+ concrete=concrete,
621
+ clm_data=clm_data,
622
+ chapter_data=chapter_data,
623
+ runtime=runtime,
624
+ builtin=builtin,
625
+ yaml_path=yaml_path,
626
+ )
627
+
628
+ def handle_result(result_tuple):
629
+ result = result_tuple
630
+ if collection:
631
+ try:
632
+ verified = True
633
+ if isinstance(result, dict) and result.get("success") is False:
634
+ verified = False
635
+
636
+ previous_vcard = None
637
+ previous_hash = ctx.get("previous_hash") or ctx.get(
638
+ "previousHash"
639
+ )
640
+ if previous_hash:
641
+ try:
642
+ prev_card = collection.get(previous_hash)
643
+ if prev_card:
644
+ from clm.layer0.model.vcard import VCard as VCardCls
645
+
646
+ previous_vcard = VCardCls(
647
+ prev_card.get_content(as_text=True)
648
+ )
649
+ except (KeyError, ValueError, AttributeError, TypeError):
650
+ pass
651
+
652
+ from clm.layer0.model.vcard import VCard
653
+ vcard = VCard.create_verification_vcard(
654
+ pcard=pcard,
655
+ execution_result=(
656
+ result
657
+ if isinstance(
658
+ result, dict | list | str | int | float | bool
659
+ )
660
+ else str(result)
661
+ ),
662
+ previous_vcard=previous_vcard,
663
+ verified=verified,
664
+ )
665
+
666
+ collection.add(vcard)
667
+ b_handle = pcard.get_balanced_handle()
668
+ try:
669
+ collection.update_handle(b_handle, vcard)
670
+ except (KeyError, ValueError, AttributeError, TypeError):
671
+ try:
672
+ collection.add_with_handle(vcard, b_handle)
673
+ except (KeyError, ValueError, AttributeError, TypeError):
674
+ pass
675
+
676
+ if isinstance(result, dict):
677
+ result["petriNet"] = {
678
+ "pcardHash": pcard.hash,
679
+ "vcardHash": vcard.hash,
680
+ "handle": vcard.get_token_handle(),
681
+ }
682
+
683
+ except (KeyError, ValueError, AttributeError, TypeError):
684
+ pass
685
+
686
+ return NarrativeMonad.unit(result)
687
+
688
+ return execution_monad.bind(handle_result)
689
+
690
+ def _execute_core_logic(
691
+ ctx,
692
+ config_ctx,
693
+ concrete,
694
+ clm_data,
695
+ chapter_data,
696
+ runtime,
697
+ builtin,
698
+ yaml_path,
699
+ ) -> NarrativeMonad:
700
+ handle_builtins = ("handle_version", "handle_prune")
701
+ if builtin in handle_builtins:
702
+ rf = _resolve_runtime_factory()
703
+ executor = rf.get_executor("python") if rf else None
704
+ if not executor:
705
+ return NarrativeMonad.log(
706
+ "Error: Python runtime not available"
707
+ ).bind(
708
+ lambda _: NarrativeMonad.unit(
709
+ {"success": False, "error": "Python runtime not available"}
710
+ )
711
+ )
712
+
713
+ try:
714
+ from clm.layer0.model.card import MCard
715
+
716
+ target = MCard(ctx.get("__input_content__", DEFAULT_TARGET))
717
+ result = executor.execute(concrete, target, config_ctx)
718
+ return NarrativeMonad.log(f"Executed builtin {builtin}").bind(
719
+ lambda _, r=result: NarrativeMonad.unit(r)
720
+ )
721
+ except (ValueError, TypeError, RuntimeError) as exc:
722
+ error_msg = str(exc)
723
+ return NarrativeMonad.log(
724
+ f"Builtin execution failed: {error_msg}"
725
+ ).bind(
726
+ lambda _, err=error_msg: NarrativeMonad.unit(
727
+ {"success": False, "error": err}
728
+ )
729
+ )
730
+
731
+ if builtin and (not runtime or runtime == "network"):
732
+ rf = _resolve_runtime_factory()
733
+ executor = rf.get_executor("network") if rf else None
734
+ if not executor:
735
+ return NarrativeMonad.log(
736
+ "Error: Network runtime not available"
737
+ ).bind(
738
+ lambda _: NarrativeMonad.unit(
739
+ {"success": False, "error": "Network runtime not available"}
740
+ )
741
+ )
742
+
743
+ test_cases = clm_data.get("balanced", {}).get("test_cases", [])
744
+ has_explicit_input = ctx.get("signaling_url") or ctx.get("params")
745
+
746
+ if (
747
+ test_cases
748
+ and not ctx.get("__skip_tests__")
749
+ and not has_explicit_input
750
+ ):
751
+ return CLMChapterLoader._execute_test_cases(
752
+ executor, concrete, config_ctx, test_cases
753
+ )
754
+ else:
755
+ try:
756
+ from clm.layer0.model.card import MCard
757
+
758
+ target = MCard(ctx.get("__input_content__", DEFAULT_TARGET))
759
+ result = executor.execute(concrete, target, config_ctx)
760
+ return NarrativeMonad.log(f"Executed builtin {builtin}").bind(
761
+ lambda _, r=result: NarrativeMonad.unit(r)
762
+ )
763
+ except (ValueError, TypeError, RuntimeError) as exc:
764
+ error_msg = str(exc)
765
+ return NarrativeMonad.log(
766
+ f"Builtin execution failed: {error_msg}"
767
+ ).bind(
768
+ lambda _, err=error_msg: NarrativeMonad.unit(
769
+ {"success": False, "error": err}
770
+ )
771
+ )
772
+
773
+ if CLMChapterLoader._is_clm_runtime(runtime):
774
+ executor = CLMChapterLoader._create_recursive_executor(
775
+ yaml_path, runtime, chapter_data, clm_data
776
+ )
777
+ else:
778
+ rf = _resolve_runtime_factory()
779
+ executor = rf.get_executor(runtime) if rf else None
780
+ if not executor:
781
+ return NarrativeMonad.log(
782
+ f"Error: Runtime {runtime} not available"
783
+ ).bind(lambda _: NarrativeMonad.unit(None))
784
+
785
+ balanced_section = clm_data.get(
786
+ "balanced_expc",
787
+ clm_data.get("balanced_exp", clm_data.get("balanced", {})),
788
+ )
789
+ test_cases = balanced_section.get("test_cases", [])
790
+ if not test_cases and "examples" in data:
791
+ test_cases = data["examples"]
792
+
793
+ if not test_cases or ctx.get("__skip_tests__"):
794
+ return CLMChapterLoader._execute_single_run(
795
+ executor, concrete, config_ctx, runtime
796
+ )
797
+ else:
798
+ return CLMChapterLoader._execute_test_cases(
799
+ executor, concrete, config_ctx, test_cases
800
+ )
801
+
802
+ action = NarrativeMonad.unit(None).bind(logic_func)
803
+
804
+ return Chapter(
805
+ id=chapter_data["id"],
806
+ title=chapter_data["title"],
807
+ clm=clm,
808
+ mvp_card=chapter_data["mvp_card"],
809
+ pkc_task=chapter_data["pkc_task"],
810
+ action=action,
811
+ )
812
+
813
+
814
+ __all__ = [
815
+ "CLMChapterLoader",
816
+ "CLM_EXTENSIONS",
817
+ "CODE_READABLE_RUNTIMES",
818
+ "DEFAULT_RUNTIME",
819
+ "DEFAULT_TARGET",
820
+ "MODULE_URI_PREFIX",
821
+ "YAMLTemplateLoader",
822
+ "_is_module_uri",
823
+ "_parse_numeric_result",
824
+ "_resolve_concrete_paths",
825
+ "_resolve_path",
826
+ ]