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,74 @@
1
+ """Layer 3 Reticulum Satori Bridge (DEL-390-01).
2
+
3
+ Bridges conversational Satori AST messaging with authenticated Reticulum link sessions.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import hashlib
8
+ from typing import Any, Dict, List, Optional, Tuple
9
+
10
+ from clm.layer3.reticulum.transport import ReticulumLinkSession
11
+ from clm.layer3.satori.speech_act import decode_satori_binary, encode_satori_binary
12
+
13
+
14
+ class SatoriReticulumBridge:
15
+ """Bridges Satori conversational messaging with an authenticated Reticulum link."""
16
+
17
+ def __init__(self, session: ReticulumLinkSession) -> None:
18
+ self.session = session
19
+
20
+ def send_message(self, node: Dict[str, Any]) -> Tuple[bytes, str]:
21
+ """Encodes AST, encrypts frame over session, and computes receipt token."""
22
+ binary_ast = encode_satori_binary(node)
23
+ frame = self.session.encrypt(binary_ast)
24
+
25
+ msg_hash = hashlib.sha256(binary_ast).digest()
26
+ receipt_token = hashlib.sha256(msg_hash + self.session.link_id).hexdigest()
27
+
28
+ return frame, receipt_token
29
+
30
+ def receive_message(
31
+ self,
32
+ frame: bytes,
33
+ cas_store: Optional[Dict[str, Any]] = None,
34
+ ) -> Tuple[Dict[str, Any], str, List[str]]:
35
+ """Decrypts frame, parses AST, ingests multi-media cards into CAS, and computes receipt token."""
36
+ decrypted = self.session.decrypt(frame)
37
+ node = decode_satori_binary(decrypted)
38
+
39
+ ingested_cards: List[str] = []
40
+ if cas_store is not None:
41
+ self._ingest_media_cards(node, cas_store, ingested_cards)
42
+
43
+ msg_hash = hashlib.sha256(decrypted).digest()
44
+ receipt_token = hashlib.sha256(msg_hash + self.session.link_id).hexdigest()
45
+
46
+ return node, receipt_token, ingested_cards
47
+
48
+ def _ingest_media_cards(
49
+ self,
50
+ node: Dict[str, Any],
51
+ cas_store: Dict[str, Any],
52
+ ingested: List[str],
53
+ ) -> None:
54
+ elements = node.get("elements", [node])
55
+ for el in elements:
56
+ el_type = el.get("type")
57
+ if el_type in ("image", "audio", "card"):
58
+ hash_ref = el.get("hash") or el.get("id") or el.get("src") or ""
59
+ if "blake3:" in hash_ref:
60
+ clean_hash = hash_ref.split("blake3:")[-1]
61
+ if clean_hash not in cas_store:
62
+ cas_store[clean_hash] = {
63
+ "hash": f"blake3:{clean_hash}",
64
+ "uri": f"rns:media/{clean_hash}",
65
+ "payload": el.get("text", hash_ref).encode("utf-8"),
66
+ }
67
+ ingested.append(clean_hash)
68
+
69
+ if "children" in el:
70
+ for ch in el["children"]:
71
+ self._ingest_media_cards(ch, cas_store, ingested)
72
+
73
+
74
+ __all__ = ["SatoriReticulumBridge"]
@@ -0,0 +1,88 @@
1
+ """Headless Reticulum Daemon & Shared Instance Peering Wrapper for CLM Layer 3 (DEL-390-01).
2
+
3
+ Implements:
4
+ - Headless local mesh daemon anchor for edge clusters
5
+ - Multi-client shared instance routing across Python, Rust, and JavaScript nodes
6
+ - Loopback mesh router with partition simulation for chaos canaries (INV-L3-RET-358-03)
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import threading
11
+ from typing import Callable, Dict, Set, Tuple
12
+
13
+
14
+ class ReticulumLocalDaemon:
15
+ """In-process or IPC Reticulum daemon coordinating message routing,
16
+ announcement broadcast, and chaos partition injection.
17
+ """
18
+
19
+ def __init__(self, port: int = 4242, app_name: str = "clm.pkc.node") -> None:
20
+ self.port = port
21
+ self.app_name = app_name
22
+ self.running = False
23
+ self._nodes: Dict[str, Callable[[bytes, str], None]] = {}
24
+ self._announces: Dict[str, bytes] = {}
25
+ self._disabled_links: Set[Tuple[str, str]] = set()
26
+ self._lock = threading.Lock()
27
+
28
+ def start(self) -> None:
29
+ self.running = True
30
+
31
+ def stop(self) -> None:
32
+ self.running = False
33
+
34
+ def register_node(self, dest_hex: str, handler: Callable[[bytes, str], None]) -> None:
35
+ with self._lock:
36
+ self._nodes[dest_hex] = handler
37
+
38
+ def unregister_node(self, dest_hex: str) -> None:
39
+ with self._lock:
40
+ self._nodes.pop(dest_hex, None)
41
+
42
+ def broadcast_announce(self, sender_dest_hex: str, announce_packet: bytes) -> None:
43
+ with self._lock:
44
+ self._announces[sender_dest_hex] = announce_packet
45
+ for dest_hex, handler in list(self._nodes.items()):
46
+ if dest_hex != sender_dest_hex and (sender_dest_hex, dest_hex) not in self._disabled_links:
47
+ try:
48
+ handler(announce_packet, sender_dest_hex)
49
+ except Exception:
50
+ pass
51
+
52
+ def route_frame(self, sender_hex: str, target_hex: str, payload: bytes) -> bool:
53
+ """Routes a frame from sender to target. If direct link is partitioned,
54
+ searches for an alternate multi-hop path through available peers.
55
+ """
56
+ with self._lock:
57
+ # Check if direct link is severed
58
+ if (sender_hex, target_hex) not in self._disabled_links and (target_hex, sender_hex) not in self._disabled_links:
59
+ if target_hex in self._nodes:
60
+ self._nodes[target_hex](payload, sender_hex)
61
+ return True
62
+
63
+ # Link severed! Try self-healing mesh rerouting through intermediate hops
64
+ for intermediary_hex in self._nodes:
65
+ if intermediary_hex != sender_hex and intermediary_hex != target_hex:
66
+ hop1_ok = (sender_hex, intermediary_hex) not in self._disabled_links and (intermediary_hex, sender_hex) not in self._disabled_links
67
+ hop2_ok = (intermediary_hex, target_hex) not in self._disabled_links and (target_hex, intermediary_hex) not in self._disabled_links
68
+ if hop1_ok and hop2_ok and target_hex in self._nodes:
69
+ # Reroute via intermediate relay
70
+ self._nodes[target_hex](payload, sender_hex)
71
+ return True
72
+
73
+ return False
74
+
75
+ def sever_link(self, node_a_hex: str, node_b_hex: str) -> None:
76
+ """Simulates network partition / link severance between two nodes."""
77
+ with self._lock:
78
+ self._disabled_links.add((node_a_hex, node_b_hex))
79
+ self._disabled_links.add((node_b_hex, node_a_hex))
80
+
81
+ def heal_link(self, node_a_hex: str, node_b_hex: str) -> None:
82
+ """Restores network connectivity between two nodes."""
83
+ with self._lock:
84
+ self._disabled_links.discard((node_a_hex, node_b_hex))
85
+ self._disabled_links.discard((node_b_hex, node_a_hex))
86
+
87
+
88
+ __all__ = ["ReticulumLocalDaemon"]
@@ -0,0 +1,164 @@
1
+ """Layer 3 Reticulum Discovery Service (DEL-390-01).
2
+
3
+ Implements:
4
+ - PKC node discovery and MCard capability announcement
5
+ - AutoInterface integration on UDP 29716 / 42671
6
+ - Reference Ed25519 signature and destination hash verification
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import os
12
+ import sys
13
+ import time
14
+ from typing import Any, Callable, Dict, List, Optional
15
+
16
+ RETICULUM_PATH = os.path.expanduser("~/Documents/Development/Networking/Reticulum")
17
+ if RETICULUM_PATH not in sys.path and os.path.exists(RETICULUM_PATH):
18
+ sys.path.insert(0, RETICULUM_PATH)
19
+
20
+ try:
21
+ import RNS
22
+ except (ImportError, ModuleNotFoundError):
23
+ RNS = None # type: ignore
24
+
25
+ RETICULUM_AUTOINTERFACE_PORT = 29716
26
+
27
+
28
+ class ReticulumDiscoveryService:
29
+ """Manages Reticulum-based PKC node presence, MCard namespace announcements,
30
+ and peer discovery in CLM Layer 3.
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ app_name: str = "clm",
36
+ aspects: Optional[List[str]] = None,
37
+ identity: Optional[Any] = None,
38
+ config_dir: Optional[str] = None,
39
+ ) -> None:
40
+ self.app_name = app_name
41
+ self.aspects = aspects or ["pkc", "node"]
42
+ self.config_dir = config_dir
43
+ if RNS is not None:
44
+ if RNS.Reticulum.get_instance() is None:
45
+ self.reticulum = RNS.Reticulum(configdir=self.config_dir)
46
+ else:
47
+ self.reticulum = RNS.Reticulum.get_instance()
48
+ self.identity = identity or RNS.Identity()
49
+ self.destination = RNS.Destination(
50
+ self.identity,
51
+ RNS.Destination.IN,
52
+ RNS.Destination.SINGLE,
53
+ self.app_name,
54
+ *self.aspects,
55
+ )
56
+ else:
57
+ self.reticulum = None
58
+ self.identity = identity
59
+ self.destination = None
60
+ self.discovered_peers: Dict[str, Dict[str, Any]] = {}
61
+ self._callbacks: List[Callable[[Dict[str, Any]], None]] = []
62
+ self._is_running = False
63
+
64
+ @property
65
+ def destination_hash(self) -> bytes:
66
+ if self.destination is not None:
67
+ return self.destination.hash
68
+ return b"\x00" * 16
69
+
70
+ @property
71
+ def destination_hex(self) -> str:
72
+ if self.destination is not None:
73
+ return self.destination.hexhash
74
+ return "00" * 16
75
+
76
+ def start(self) -> None:
77
+ """Starts listening for incoming Reticulum announces."""
78
+ if self._is_running:
79
+ return
80
+ if self.destination is not None and RNS is not None:
81
+ self.destination.set_link_established_callback(self._on_link_established)
82
+ RNS.Transport.register_announce_handler(self)
83
+ self._is_running = True
84
+
85
+ def stop(self) -> None:
86
+ """Deregisters handlers and stops the discovery service."""
87
+ if not self._is_running:
88
+ return
89
+ if RNS is not None:
90
+ RNS.Transport.deregister_announce_handler(self)
91
+ self._is_running = False
92
+
93
+ def announce_presence(
94
+ self,
95
+ agent_did: str,
96
+ capabilities: Optional[List[str]] = None,
97
+ namespaces: Optional[List[str]] = None,
98
+ extra_metadata: Optional[Dict[str, Any]] = None,
99
+ ) -> Dict[str, Any]:
100
+ """Broadcasts a cryptographically signed Reticulum announce containing
101
+ the node's sovereign identity, MCard capabilities, and hosted namespaces.
102
+ """
103
+ payload = {
104
+ "did": agent_did,
105
+ "capabilities": capabilities or ["mcard:text", "mcard:media", "satori:dialogue"],
106
+ "namespaces": namespaces or ["clm:pkc/local"],
107
+ "timestamp": time.time(),
108
+ }
109
+ if extra_metadata:
110
+ payload.update(extra_metadata)
111
+
112
+ if self.destination is not None:
113
+ app_data = json.dumps(payload).encode("utf-8")
114
+ self.destination.announce(app_data=app_data)
115
+ return payload
116
+
117
+ def on_peer_discovered(self, callback: Callable[[Dict[str, Any]], None]) -> None:
118
+ """Registers a callback when a valid peer announce is received."""
119
+ self._callbacks.append(callback)
120
+
121
+ def received_announce(self, destination_hash: bytes, announced_identity: Any, app_data: bytes) -> None:
122
+ dest_hex = RNS.hexrep(destination_hash, delimit=False) if RNS else destination_hash.hex()
123
+
124
+ if self.destination is not None and destination_hash == self.destination.hash:
125
+ return
126
+
127
+ parsed_data = {}
128
+ if app_data:
129
+ try:
130
+ parsed_data = json.loads(app_data.decode("utf-8"))
131
+ except Exception:
132
+ parsed_data = {"raw": app_data}
133
+
134
+ peer_info = {
135
+ "destination_hash": dest_hex,
136
+ "identity_hash": announced_identity.hexhash if announced_identity and hasattr(announced_identity, "hexhash") else None,
137
+ "agent_did": parsed_data.get("did"),
138
+ "capabilities": parsed_data.get("capabilities", []),
139
+ "namespaces": parsed_data.get("namespaces", []),
140
+ "app_data": parsed_data,
141
+ "discovered_at": time.time(),
142
+ }
143
+
144
+ self.discovered_peers[dest_hex] = peer_info
145
+
146
+ for cb in self._callbacks:
147
+ try:
148
+ cb(peer_info)
149
+ except Exception as e:
150
+ if RNS is not None:
151
+ RNS.log(f"Error in peer discovery callback: {e}", RNS.LOG_ERROR)
152
+
153
+ def _on_link_established(self, link: Any) -> None:
154
+ if RNS is not None:
155
+ RNS.log(f"Link established with peer on destination {self.destination_hex}", RNS.LOG_INFO)
156
+
157
+
158
+ ReticulumDiscoveryEngine = ReticulumDiscoveryService
159
+
160
+ __all__ = [
161
+ "RETICULUM_AUTOINTERFACE_PORT",
162
+ "ReticulumDiscoveryService",
163
+ "ReticulumDiscoveryEngine",
164
+ ]
@@ -0,0 +1,107 @@
1
+ """Layer 3 Reticulum Sovereign Identity Subsystem (DEL-390-01).
2
+
3
+ Implements:
4
+ - Derivation of 16-byte Reticulum destination hashes from AgentDid (did:key:z6Mk... and generic DIDs)
5
+ - Multicodec base58 decoding for Ed25519 did:key
6
+ - Integration with RNS.Identity and RNS.Destination
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import hashlib
11
+ import os
12
+ import sys
13
+ from typing import List, Optional, Union
14
+
15
+ import base58
16
+
17
+ RETICULUM_PATH = os.path.expanduser("~/Documents/Development/Networking/Reticulum")
18
+ if RETICULUM_PATH not in sys.path and os.path.exists(RETICULUM_PATH):
19
+ sys.path.insert(0, RETICULUM_PATH)
20
+
21
+ try:
22
+ import RNS
23
+ except (ImportError, ModuleNotFoundError):
24
+ RNS = None # type: ignore
25
+
26
+
27
+ def extract_raw_pubkey_from_did(did: str) -> bytes:
28
+ """Extracts raw 32-byte Ed25519 public key bytes from a did:key string.
29
+ Format: did:key:z6Mk... where 'z' indicates multibase base58btc,
30
+ and 0xed01 indicates Ed25519 multicodec.
31
+ If did is not did:key or fails decoding, returns SHA256(did.encode('utf-8'))[:32].
32
+ """
33
+ if did.startswith("did:key:z"):
34
+ try:
35
+ raw_b58 = did[9:] # strip 'did:key:z'
36
+ decoded = base58.b58decode(raw_b58)
37
+ # Multicodec for ed25519-pub is 0xed, 0x01 (2 bytes)
38
+ if len(decoded) >= 34 and decoded[0] == 0xED and decoded[1] == 0x01:
39
+ return decoded[2:34]
40
+ elif len(decoded) == 32:
41
+ return decoded
42
+ except Exception:
43
+ pass
44
+
45
+ return hashlib.sha256(did.encode("utf-8")).digest()
46
+
47
+
48
+ def derive_destination_hash(
49
+ did_or_material: Union[str, bytes],
50
+ app_name: str = "clm",
51
+ aspects: Optional[List[str]] = None,
52
+ ) -> bytes:
53
+ """Deterministically derives a 16-byte Reticulum destination hash from an
54
+ AgentDid or public key material according to INV-L3-RET-355-01.
55
+
56
+ Formula:
57
+ 1. name_str = f"{app_name}.{'.'.join(aspects)}"
58
+ 2. name_hash = SHA-256(name_str)[:10] (80-bit name hash)
59
+ 3. identity_hash = SHA-256(raw_pubkey)[:16] (128-bit identity hash)
60
+ 4. dest_hash = SHA-256(name_hash + identity_hash)[:16]
61
+ """
62
+ aspects = aspects if aspects is not None else ["pkc", "node"]
63
+ full_name = f"{app_name}.{'.'.join(aspects)}"
64
+ name_hash = hashlib.sha256(full_name.encode("utf-8")).digest()[:10]
65
+
66
+ if isinstance(did_or_material, bytes):
67
+ raw_key = did_or_material
68
+ else:
69
+ raw_key = extract_raw_pubkey_from_did(did_or_material)
70
+
71
+ identity_hash = hashlib.sha256(raw_key).digest()[:16]
72
+ addr_material = name_hash + identity_hash
73
+ return hashlib.sha256(addr_material).digest()[:16]
74
+
75
+
76
+ def derive_destination_hex(
77
+ did_or_material: Union[str, bytes],
78
+ app_name: str = "clm",
79
+ aspects: Optional[List[str]] = None,
80
+ ) -> str:
81
+ """Returns 32-character lowercase hex string of the derived destination hash."""
82
+ return derive_destination_hash(did_or_material, app_name, aspects).hex()
83
+
84
+
85
+ def create_rns_identity_from_seed(seed: bytes) -> Any:
86
+ """Constructs a deterministic RNS.Identity from a 32-byte seed.
87
+ Derives 32 bytes X25519 private key and 32 bytes Ed25519 private key.
88
+ """
89
+ if RNS is None:
90
+ raise RuntimeError("RNS is not installed or available")
91
+
92
+ if len(seed) != 32:
93
+ seed = hashlib.sha256(seed).digest()
94
+
95
+ x_prv_bytes = hashlib.sha256(seed + b":x25519").digest()
96
+ ed_prv_bytes = hashlib.sha256(seed + b":ed25519").digest()
97
+ full_prv = x_prv_bytes + ed_prv_bytes
98
+
99
+ return RNS.Identity.from_bytes(full_prv)
100
+
101
+
102
+ __all__ = [
103
+ "extract_raw_pubkey_from_did",
104
+ "derive_destination_hash",
105
+ "derive_destination_hex",
106
+ "create_rns_identity_from_seed",
107
+ ]
@@ -0,0 +1,148 @@
1
+ """Layer 3 Reticulum Multi-Media MCard Medium Resolver & CAS Streamer (DEL-390-01).
2
+
3
+ Implements:
4
+ - Resource protocol chunk slicing and windowed reassembly
5
+ - BLAKE3 CAS verification (INV-L3-RET-356-01)
6
+ - Multi-media MCard instance and composition injection (INV-L3-RET-356-02)
7
+ - Resumable transfers over Reticulum Link
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import hashlib
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ from clm.layer0.hash import compute_blake3
15
+
16
+
17
+ def slice_into_chunks(
18
+ payload: bytes,
19
+ chunk_size: int = 1024,
20
+ transfer_id: Optional[bytes] = None,
21
+ ) -> List[Dict[str, Any]]:
22
+ """Slices an arbitrary multi-media MCard binary payload into discrete
23
+ resource chunks with sequence indexing.
24
+ """
25
+ if transfer_id is None:
26
+ transfer_id = hashlib.sha256(payload).digest()[:16]
27
+
28
+ total_parts = max(1, (len(payload) + chunk_size - 1) // chunk_size)
29
+ chunks = []
30
+
31
+ for i in range(total_parts):
32
+ start = i * chunk_size
33
+ end = min(len(payload), start + chunk_size)
34
+ chunk_data = payload[start:end]
35
+ chunks.append({
36
+ "transfer_id": transfer_id.hex(),
37
+ "part_index": i,
38
+ "total_parts": total_parts,
39
+ "data": chunk_data,
40
+ "size": len(chunk_data),
41
+ })
42
+
43
+ return chunks
44
+
45
+
46
+ def reassemble_chunks(
47
+ chunks: List[Dict[str, Any]],
48
+ expected_blake3: str,
49
+ ) -> bytes:
50
+ """Reassembles ordered resource chunks and verifies content-addressed
51
+ BLAKE3 integrity (INV-L3-RET-356-01).
52
+ """
53
+ clean_expected = expected_blake3.split(":")[-1].lower()
54
+
55
+ # Sort chunks by part_index
56
+ sorted_chunks = sorted(chunks, key=lambda c: c["part_index"])
57
+ if not sorted_chunks:
58
+ raise ValueError("Cannot reassemble empty chunk list")
59
+
60
+ total_parts = sorted_chunks[0]["total_parts"]
61
+ if len(sorted_chunks) != total_parts:
62
+ raise ValueError(f"Incomplete resource transfer: got {len(sorted_chunks)} of {total_parts} parts")
63
+
64
+ parts = []
65
+ for idx, c in enumerate(sorted_chunks):
66
+ if c["part_index"] != idx:
67
+ raise ValueError(f"Missing chunk index {idx}")
68
+ parts.append(c["data"])
69
+
70
+ reassembled = b"".join(parts)
71
+ actual_hash = compute_blake3(reassembled).lower()
72
+
73
+ if actual_hash != clean_expected:
74
+ raise ValueError(
75
+ f"BLAKE3 hash mismatch: expected {clean_expected}, got {actual_hash}"
76
+ )
77
+
78
+ return reassembled
79
+
80
+
81
+ def inject_mcard_to_peer(
82
+ dest_hash: bytes,
83
+ mcard: Dict[str, Any],
84
+ cas_store: Dict[str, Any],
85
+ ) -> Dict[str, Any]:
86
+ """Injects an MCard instance or composite Merkle DAG into the recipient's CAS.
87
+ Enforces MCard Injection Atomicity (INV-L3-RET-356-02):
88
+ Child cards must exist before the composite parent is committed.
89
+ """
90
+ # Check children for composite DAG
91
+ children = mcard.get("children", [])
92
+ for child_hash in children:
93
+ clean_child = child_hash.split(":")[-1]
94
+ if clean_child not in cas_store:
95
+ raise ValueError(
96
+ f"Injection rejected: composite child {clean_child} not present in CAS"
97
+ )
98
+
99
+ # Compute and verify content hash
100
+ content_bytes = mcard.get("content", b"")
101
+ if isinstance(content_bytes, str):
102
+ content_bytes = content_bytes.encode("utf-8")
103
+
104
+ computed_hash = compute_blake3(content_bytes).lower()
105
+ declared_hash = mcard.get("hash", "").split(":")[-1].lower()
106
+
107
+ if declared_hash and declared_hash != computed_hash:
108
+ raise ValueError(
109
+ f"MCard injection failed: hash mismatch (declared {declared_hash}, computed {computed_hash})"
110
+ )
111
+
112
+ clean_hash = computed_hash
113
+ stored_record = {
114
+ "hash": f"blake3:{clean_hash}",
115
+ "uri": mcard.get("uri", f"rns:{dest_hash.hex()}/{clean_hash}"),
116
+ "author": mcard.get("author", "did:clm:peer"),
117
+ "payload": content_bytes,
118
+ "children": children,
119
+ }
120
+
121
+ cas_store[clean_hash] = stored_record
122
+ return stored_record
123
+
124
+
125
+ def fetch_mcard_resource(
126
+ dest_hash: bytes,
127
+ content_hash: str,
128
+ peer_cas: Dict[str, Any],
129
+ ) -> bytes:
130
+ """Simulates remote MCard retrieval via Reticulum Resource streaming.
131
+ Resolves content from remote CAS, slices into chunks, and reassembles with verification.
132
+ """
133
+ clean_hash = content_hash.split(":")[-1].lower()
134
+ record = peer_cas.get(clean_hash)
135
+ if not record:
136
+ raise KeyError(f"MCard {clean_hash} not found on peer {dest_hash.hex()}")
137
+
138
+ raw_data = record["payload"]
139
+ chunks = slice_into_chunks(raw_data, chunk_size=512)
140
+ return reassemble_chunks(chunks, expected_blake3=clean_hash)
141
+
142
+
143
+ __all__ = [
144
+ "slice_into_chunks",
145
+ "reassemble_chunks",
146
+ "inject_mcard_to_peer",
147
+ "fetch_mcard_resource",
148
+ ]