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/layer4/storage.py ADDED
@@ -0,0 +1,463 @@
1
+ """
2
+ MCard Storage - Storage interface for PTR using MCard Collections
3
+
4
+ Provides a high-level storage interface for PTR components,
5
+ leveraging MCard's content-addressable storage for immutability
6
+ and versioning.
7
+ """
8
+
9
+ import logging
10
+ from dataclasses import dataclass
11
+ from datetime import datetime, timezone
12
+ from typing import Any
13
+
14
+ import yaml
15
+
16
+ from clm.layer2.card_collection import CardCollection, MCard
17
+
18
+
19
+ @dataclass
20
+ class StorageResult:
21
+ """Result of a storage operation"""
22
+
23
+ success: bool
24
+ hash: str | None = None
25
+ error_message: str | None = None
26
+ metadata: dict[str, Any] = None
27
+
28
+
29
+ @dataclass
30
+ class RetrievalResult:
31
+ """Result of a retrieval operation"""
32
+
33
+ success: bool
34
+ content: Any | None = None
35
+ metadata: dict[str, Any] = None
36
+ error_message: str | None = None
37
+
38
+
39
+ class MCardStorage:
40
+ """
41
+ High-level storage interface for PTR using MCard Collections.
42
+
43
+ This class provides:
44
+ - Content-addressable storage with automatic hashing
45
+ - Metadata management and indexing
46
+ - Search and retrieval capabilities
47
+ - Version tracking and history
48
+ """
49
+
50
+ def __init__(self, collection: CardCollection = None):
51
+ self.logger = logging.getLogger(__name__)
52
+ self.collection = collection or CardCollection()
53
+ self.metadata_cache = {} # Cache for metadata lookups
54
+
55
+ self.logger.info("MCard Storage initialized")
56
+
57
+ def store_pcard(
58
+ self, pcard_data: dict[str, Any], metadata: dict[str, Any] = None
59
+ ) -> StorageResult:
60
+ """
61
+ Store a PCard with its CLM dimensions.
62
+
63
+ Args:
64
+ pcard_data: PCard content with abstract, concrete, balanced dimensions
65
+ metadata: Additional metadata for the PCard
66
+
67
+ Returns:
68
+ StorageResult with hash and metadata
69
+ """
70
+ try:
71
+ # Validate PCard structure
72
+ validation_result = self._validate_pcard_structure(pcard_data)
73
+ if not validation_result["valid"]:
74
+ return StorageResult(
75
+ success=False,
76
+ error_message=f"Invalid PCard structure: {validation_result['errors']}",
77
+ )
78
+
79
+ # Create PCard metadata
80
+ pcard_metadata = {
81
+ "type": "PCard",
82
+ "version": "1.0.0",
83
+ "created_at": datetime.now(timezone.utc).isoformat(),
84
+ "clm_dimensions": {
85
+ "has_abstract": "abstract" in pcard_data,
86
+ "has_concrete": "concrete" in pcard_data,
87
+ "has_balanced": "balanced" in pcard_data,
88
+ },
89
+ }
90
+
91
+ # Merge with provided metadata
92
+ if metadata:
93
+ pcard_metadata.update(metadata)
94
+
95
+ # Combine metadata and content
96
+ storage_data = {"metadata": pcard_metadata, "content": pcard_data}
97
+
98
+ # Store as MCard
99
+ storage_yaml = yaml.safe_dump(storage_data, default_flow_style=False)
100
+ pcard_mcard = MCard(storage_yaml)
101
+ pcard_hash = self.collection.add(pcard_mcard)
102
+
103
+ # Cache metadata
104
+ self.metadata_cache[pcard_hash] = pcard_metadata
105
+
106
+ self.logger.info(f"Stored PCard with hash: {pcard_hash}")
107
+
108
+ return StorageResult(success=True, hash=pcard_hash, metadata=pcard_metadata)
109
+
110
+ except (yaml.YAMLError, ValueError, TypeError, KeyError) as e:
111
+ self.logger.error(f"Failed to store PCard: {str(e)}", exc_info=True)
112
+ return StorageResult(success=False, error_message=str(e))
113
+
114
+ def retrieve_pcard(self, pcard_hash: str) -> RetrievalResult:
115
+ """
116
+ Retrieve a PCard by its hash.
117
+
118
+ Args:
119
+ pcard_hash: Hash of the PCard to retrieve
120
+
121
+ Returns:
122
+ RetrievalResult with PCard content and metadata
123
+ """
124
+ try:
125
+ # Retrieve MCard
126
+ pcard_mcard = self.collection.get(pcard_hash)
127
+ if not pcard_mcard:
128
+ return RetrievalResult(
129
+ success=False, error_message=f"PCard not found: {pcard_hash}"
130
+ )
131
+
132
+ # Parse PCard data
133
+ pcard_yaml = pcard_mcard.get_content().decode("utf-8")
134
+ pcard_data = yaml.safe_load(pcard_yaml)
135
+
136
+ # Extract metadata and content
137
+ metadata = pcard_data.get("metadata", {})
138
+ content = pcard_data.get("content", pcard_data)
139
+
140
+ # Validate it's a PCard
141
+ if metadata.get("type") != "PCard":
142
+ return RetrievalResult(
143
+ success=False, error_message=f"Not a PCard: {pcard_hash}"
144
+ )
145
+
146
+ # Cache metadata
147
+ self.metadata_cache[pcard_hash] = metadata
148
+
149
+ self.logger.info(f"Retrieved PCard: {pcard_hash}")
150
+
151
+ return RetrievalResult(success=True, content=content, metadata=metadata)
152
+
153
+ except (
154
+ yaml.YAMLError,
155
+ ValueError,
156
+ TypeError,
157
+ KeyError,
158
+ UnicodeDecodeError,
159
+ ) as e:
160
+ self.logger.error(
161
+ f"Failed to retrieve PCard {pcard_hash}: {str(e)}", exc_info=True
162
+ )
163
+ return RetrievalResult(success=False, error_message=str(e))
164
+
165
+ def store_vcard(
166
+ self, vcard_data: dict[str, Any], metadata: dict[str, Any] = None
167
+ ) -> StorageResult:
168
+ """
169
+ Store a VCard (verification card) with audit evidence.
170
+
171
+ Args:
172
+ vcard_data: VCard content with verification evidence
173
+ metadata: Additional metadata for the VCard
174
+
175
+ Returns:
176
+ StorageResult with hash and metadata
177
+ """
178
+ try:
179
+ # Create VCard metadata
180
+ vcard_metadata = {
181
+ "type": "VCard",
182
+ "version": "1.0.0",
183
+ "created_at": datetime.now(timezone.utc).isoformat(),
184
+ "verification_type": vcard_data.get("type", "unknown"),
185
+ }
186
+
187
+ # Merge with provided metadata
188
+ if metadata:
189
+ vcard_metadata.update(metadata)
190
+
191
+ # Combine metadata and content
192
+ storage_data = {"metadata": vcard_metadata, "content": vcard_data}
193
+
194
+ # Store as MCard
195
+ storage_yaml = yaml.safe_dump(storage_data, default_flow_style=False)
196
+ vcard_mcard = MCard(storage_yaml)
197
+ vcard_hash = self.collection.add(vcard_mcard)
198
+
199
+ # Cache metadata
200
+ self.metadata_cache[vcard_hash] = vcard_metadata
201
+
202
+ self.logger.info(f"Stored VCard with hash: {vcard_hash}")
203
+
204
+ return StorageResult(success=True, hash=vcard_hash, metadata=vcard_metadata)
205
+
206
+ except (yaml.YAMLError, ValueError, TypeError, KeyError) as e:
207
+ self.logger.error(f"Failed to store VCard: {str(e)}", exc_info=True)
208
+ return StorageResult(success=False, error_message=str(e))
209
+
210
+ def retrieve_vcard(self, vcard_hash: str) -> RetrievalResult:
211
+ """
212
+ Retrieve a VCard by its hash.
213
+
214
+ Args:
215
+ vcard_hash: Hash of the VCard to retrieve
216
+
217
+ Returns:
218
+ RetrievalResult with VCard content and metadata
219
+ """
220
+ try:
221
+ # Retrieve MCard
222
+ vcard_mcard = self.collection.get(vcard_hash)
223
+ if not vcard_mcard:
224
+ return RetrievalResult(
225
+ success=False, error_message=f"VCard not found: {vcard_hash}"
226
+ )
227
+
228
+ # Parse VCard data
229
+ vcard_yaml = vcard_mcard.get_content().decode("utf-8")
230
+ vcard_data = yaml.safe_load(vcard_yaml)
231
+
232
+ # Extract metadata and content
233
+ metadata = vcard_data.get("metadata", {})
234
+ content = vcard_data.get("content", vcard_data)
235
+
236
+ # Validate it's a VCard
237
+ if metadata.get("type") != "VCard":
238
+ return RetrievalResult(
239
+ success=False, error_message=f"Not a VCard: {vcard_hash}"
240
+ )
241
+
242
+ # Cache metadata
243
+ self.metadata_cache[vcard_hash] = metadata
244
+
245
+ self.logger.info(f"Retrieved VCard: {vcard_hash}")
246
+
247
+ return RetrievalResult(success=True, content=content, metadata=metadata)
248
+
249
+ except (
250
+ yaml.YAMLError,
251
+ ValueError,
252
+ TypeError,
253
+ KeyError,
254
+ UnicodeDecodeError,
255
+ ) as e:
256
+ self.logger.error(
257
+ f"Failed to retrieve VCard {vcard_hash}: {str(e)}", exc_info=True
258
+ )
259
+ return RetrievalResult(success=False, error_message=str(e))
260
+
261
+ def search_pcards(
262
+ self, query: str, filters: dict[str, Any] = None
263
+ ) -> list[RetrievalResult]:
264
+ """
265
+ Search for PCards using text search and filters.
266
+
267
+ Args:
268
+ query: Search query string
269
+ filters: Optional filters to apply
270
+
271
+ Returns:
272
+ List of RetrievalResult objects
273
+ """
274
+ try:
275
+ # Perform text search
276
+ found_cards = self.collection.search_by_string(query)
277
+ results = []
278
+
279
+ for card in found_cards.items:
280
+ try:
281
+ # Retrieve and validate it's a PCard
282
+ retrieval = self.retrieve_pcard(card.hash)
283
+ if retrieval.success:
284
+ # Apply filters
285
+ if filters:
286
+ match = True
287
+ metadata = retrieval.metadata
288
+
289
+ for key, value in filters.items():
290
+ if (
291
+ key == "type"
292
+ and metadata.get("verification_type") != value
293
+ ):
294
+ match = False
295
+ break
296
+ elif key == "created_after" and metadata.get(
297
+ "created_at"
298
+ ):
299
+ created_at = datetime.fromisoformat(
300
+ metadata["created_at"]
301
+ )
302
+ filter_date = datetime.fromisoformat(value)
303
+ if created_at < filter_date:
304
+ match = False
305
+ break
306
+
307
+ if not match:
308
+ continue
309
+
310
+ results.append(retrieval)
311
+
312
+ except (ValueError, KeyError, TypeError) as e:
313
+ self.logger.warning(
314
+ f"Failed to process search result {card.hash}: {str(e)}"
315
+ )
316
+ continue
317
+
318
+ self.logger.info(f"Found {len(results)} PCards matching query: {query}")
319
+
320
+ return results
321
+
322
+ except (ValueError, TypeError, KeyError, AttributeError) as e:
323
+ self.logger.error(f"Failed to search PCards: {str(e)}", exc_info=True)
324
+ return []
325
+
326
+ def search_vcards(
327
+ self, query: str, filters: dict[str, Any] = None
328
+ ) -> list[RetrievalResult]:
329
+ """
330
+ Search for VCards using text search and filters.
331
+
332
+ Args:
333
+ query: Search query string
334
+ filters: Optional filters to apply
335
+
336
+ Returns:
337
+ List of RetrievalResult objects
338
+ """
339
+ try:
340
+ # Perform text search
341
+ found_cards = self.collection.search_by_string(query)
342
+ results = []
343
+
344
+ for card in found_cards.items:
345
+ try:
346
+ # Retrieve and validate it's a VCard
347
+ retrieval = self.retrieve_vcard(card.hash)
348
+ if retrieval.success:
349
+ # Apply filters
350
+ if filters:
351
+ match = True
352
+ metadata = retrieval.metadata
353
+
354
+ for key, value in filters.items():
355
+ if (
356
+ key == "verification_type"
357
+ and metadata.get("verification_type") != value
358
+ ):
359
+ match = False
360
+ break
361
+ elif key == "created_after" and metadata.get(
362
+ "created_at"
363
+ ):
364
+ created_at = datetime.fromisoformat(
365
+ metadata["created_at"]
366
+ )
367
+ filter_date = datetime.fromisoformat(value)
368
+ if created_at < filter_date:
369
+ match = False
370
+ break
371
+
372
+ if not match:
373
+ continue
374
+
375
+ results.append(retrieval)
376
+
377
+ except (ValueError, KeyError, TypeError) as e:
378
+ self.logger.warning(
379
+ f"Failed to process search result {card.hash}: {str(e)}"
380
+ )
381
+ continue
382
+
383
+ self.logger.info(f"Found {len(results)} VCards matching query: {query}")
384
+
385
+ return results
386
+
387
+ except (ValueError, TypeError, KeyError, AttributeError) as e:
388
+ self.logger.error(f"Failed to search VCards: {str(e)}", exc_info=True)
389
+ return []
390
+
391
+ def get_storage_statistics(self) -> dict[str, Any]:
392
+ """
393
+ Get storage statistics and metrics.
394
+
395
+ Returns:
396
+ Dictionary with storage statistics
397
+ """
398
+ try:
399
+ total_cards = self.collection.count()
400
+
401
+ # Count by type (using search)
402
+ pcard_count = len(self.collection.search_by_string("PCard").items)
403
+ vcard_count = len(self.collection.search_by_string("VCard").items)
404
+ other_count = total_cards - pcard_count - vcard_count
405
+
406
+ # Cache statistics
407
+ cache_size = len(self.metadata_cache)
408
+
409
+ statistics = {
410
+ "total_cards": total_cards,
411
+ "by_type": {
412
+ "pcard": pcard_count,
413
+ "vcard": vcard_count,
414
+ "other": other_count,
415
+ },
416
+ "cache": {
417
+ "entries": cache_size,
418
+ "hit_rate": "N/A", # Would need tracking implementation
419
+ },
420
+ "collection_path": getattr(
421
+ self.collection.engine.connection, "db_path", "in-memory"
422
+ ),
423
+ }
424
+
425
+ return statistics
426
+
427
+ except (ValueError, TypeError, KeyError, AttributeError) as e:
428
+ self.logger.error(
429
+ f"Failed to get storage statistics: {str(e)}", exc_info=True
430
+ )
431
+ return {"error": str(e)}
432
+
433
+ def _validate_pcard_structure(self, pcard_data: dict[str, Any]) -> dict[str, Any]:
434
+ """
435
+ Validate the structure of a PCard.
436
+
437
+ Args:
438
+ pcard_data: PCard data to validate
439
+
440
+ Returns:
441
+ Dictionary with validation result and errors
442
+ """
443
+ errors = []
444
+
445
+ if not isinstance(pcard_data, dict):
446
+ errors.append("PCard content must be a dictionary")
447
+ return {"valid": False, "errors": errors}
448
+
449
+ # Check for at least one CLM dimension
450
+ clm_dimensions = ["abstract", "concrete", "balanced"]
451
+ has_dimensions = any(dim in pcard_data for dim in clm_dimensions)
452
+
453
+ if not has_dimensions:
454
+ errors.append(
455
+ "PCard must contain at least one CLM dimension (abstract, concrete, or balanced)"
456
+ )
457
+
458
+ return {"valid": len(errors) == 0, "errors": errors}
459
+
460
+ def clear_cache(self) -> None:
461
+ """Clear the metadata cache."""
462
+ self.metadata_cache.clear()
463
+ self.logger.info("Metadata cache cleared")