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.
- clm/__init__.py +230 -0
- clm/__main__.py +25 -0
- clm/cross_cutting/__init__.py +50 -0
- clm/cross_cutting/_test_runner.py +36 -0
- clm/cross_cutting/async_utils.py +25 -0
- clm/cross_cutting/cel_builder.py +123 -0
- clm/cross_cutting/cel_converter.py +697 -0
- clm/cross_cutting/cel_engine.py +252 -0
- clm/cross_cutting/cel_ops.py +72 -0
- clm/cross_cutting/cel_ops_db.py +157 -0
- clm/cross_cutting/cel_ops_files.py +99 -0
- clm/cross_cutting/cel_ops_state.py +71 -0
- clm/cross_cutting/cel_ops_strings.py +64 -0
- clm/cross_cutting/cel_resolver.py +63 -0
- clm/cross_cutting/cel_slices.py +56 -0
- clm/cross_cutting/cel_store.py +330 -0
- clm/cross_cutting/clm_logger.py +140 -0
- clm/cross_cutting/config/__init__.py +155 -0
- clm/cross_cutting/config/config_constants.py +392 -0
- clm/cross_cutting/config/env_parameters.py +90 -0
- clm/cross_cutting/config/logging.py +378 -0
- clm/cross_cutting/config/settings.py +504 -0
- clm/cross_cutting/context.py +5 -0
- clm/cross_cutting/domain_models.py +55 -0
- clm/cross_cutting/domain_types.py +61 -0
- clm/cross_cutting/effects.py +67 -0
- clm/cross_cutting/errors.py +153 -0
- clm/cross_cutting/governance.py +331 -0
- clm/cross_cutting/guards.py +41 -0
- clm/cross_cutting/mcard.py +321 -0
- clm/cross_cutting/native.py +185 -0
- clm/cross_cutting/observability.py +289 -0
- clm/cross_cutting/pcard.py +434 -0
- clm/cross_cutting/registry.py +71 -0
- clm/cross_cutting/resources.py +84 -0
- clm/cross_cutting/secrets.py +44 -0
- clm/cross_cutting/subprocess_utils.py +118 -0
- clm/cross_cutting/telemetry.py +164 -0
- clm/cross_cutting/testing/__init__.py +8 -0
- clm/cross_cutting/testing/comparator.py +187 -0
- clm/cross_cutting/testing/datasets.py +87 -0
- clm/cross_cutting/timeutil.py +20 -0
- clm/cross_cutting/types/new_type_check.py +0 -0
- clm/cross_cutting/utils/__init__.py +1 -0
- clm/cross_cutting/utils/url_safety.py +50 -0
- clm/cross_cutting/vcard.py +560 -0
- clm/cross_cutting/writer.py +118 -0
- clm/layer0/README.md +50 -0
- clm/layer0/__init__.py +223 -0
- clm/layer0/algebra.py +60 -0
- clm/layer0/algebra_baldwin.py +133 -0
- clm/layer0/algebra_baldwin_generators.py +36 -0
- clm/layer0/algebra_equivalence.py +262 -0
- clm/layer0/algebra_ingest.py +306 -0
- clm/layer0/algebra_manifest_io.py +156 -0
- clm/layer0/assembler.py +481 -0
- clm/layer0/cel/__init__.py +23 -0
- clm/layer0/cel_eval.py +491 -0
- clm/layer0/codec.py +106 -0
- clm/layer0/context.py +122 -0
- clm/layer0/db.py +160 -0
- clm/layer0/exceptions.py +73 -0
- clm/layer0/fibration.py +106 -0
- clm/layer0/gates.py +50 -0
- clm/layer0/hash.py +80 -0
- clm/layer0/loader.py +826 -0
- clm/layer0/math_utils.py +163 -0
- clm/layer0/mcard.py +96 -0
- clm/layer0/model/__init__.py +0 -0
- clm/layer0/model/action.py +223 -0
- clm/layer0/model/card.py +280 -0
- clm/layer0/model/card_triad.py +427 -0
- clm/layer0/model/compatibility.py +60 -0
- clm/layer0/model/dictionary.py +46 -0
- clm/layer0/model/dots.py +331 -0
- clm/layer0/model/event_producer.py +88 -0
- clm/layer0/model/g_time.py +89 -0
- clm/layer0/model/handle.py +163 -0
- clm/layer0/model/hash/__init__.py +6 -0
- clm/layer0/model/hash/algorithms/__init__.py +3 -0
- clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
- clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
- clm/layer0/model/hash/constants.py +53 -0
- clm/layer0/model/hash/enums.py +60 -0
- clm/layer0/model/hash/validator.py +307 -0
- clm/layer0/model/interpreter.py +275 -0
- clm/layer0/model/pagination.py +45 -0
- clm/layer0/model/pcard.py +716 -0
- clm/layer0/model/schema.py +44 -0
- clm/layer0/model/utils/__init__.py +1 -0
- clm/layer0/model/utils/content_analyzer.py +152 -0
- clm/layer0/model/validators/__init__.py +1 -0
- clm/layer0/model/validators/base_validator.py +44 -0
- clm/layer0/model/validators/binary_validator.py +66 -0
- clm/layer0/model/validators/text_validator.py +82 -0
- clm/layer0/model/validators/validation_registry.py +49 -0
- clm/layer0/model/vcard.py +823 -0
- clm/layer0/model/vcard_ext/__init__.py +39 -0
- clm/layer0/model/vcard_ext/core.py +60 -0
- clm/layer0/model/vcard_ext/network.py +23 -0
- clm/layer0/model/vcard_ext/observability.py +63 -0
- clm/layer0/model/vcard_ext/storage.py +60 -0
- clm/layer0/model/vcard_ext/vendors.py +211 -0
- clm/layer0/model/vcard_sandwich.py +119 -0
- clm/layer0/model/vcard_vocabulary.py +463 -0
- clm/layer0/model/workflow.py +274 -0
- clm/layer0/narrative.py +431 -0
- clm/layer0/ontology/collection.py +125 -0
- clm/layer0/parser.py +429 -0
- clm/layer0/relations.py +73 -0
- clm/layer0/rule_evaluator.py +251 -0
- clm/layer0/schema/__init__.py +38 -0
- clm/layer0/schema/ddl.py +97 -0
- clm/layer0/templates/abstract.yaml +99 -0
- clm/layer0/templates/balanced.yaml +253 -0
- clm/layer0/templates/concrete.yaml +172 -0
- clm/layer0/type_registry.py +223 -0
- clm/layer0/types.py +204 -0
- clm/layer0/utils.py +886 -0
- clm/layer0/verifier_core.py +262 -0
- clm/layer1/__init__.py +31 -0
- clm/layer1/action_dispatcher.py +275 -0
- clm/layer1/adapter_registry.py +233 -0
- clm/layer1/algebra_baldwin_generators.py +192 -0
- clm/layer1/arrow_compiler.py +525 -0
- clm/layer1/batch_processor.py +152 -0
- clm/layer1/cel/__init__.py +27 -0
- clm/layer1/cel/builder.py +173 -0
- clm/layer1/engine.py +759 -0
- clm/layer1/engine_async.py +89 -0
- clm/layer1/eval_callback.py +49 -0
- clm/layer1/gate_composer.py +229 -0
- clm/layer1/hoare_sandwich.py +298 -0
- clm/layer1/identity_guard.py +348 -0
- clm/layer1/matrix.py +138 -0
- clm/layer1/neural_runtime.py +221 -0
- clm/layer1/operations/__init__.py +123 -0
- clm/layer1/operations/augment.py +156 -0
- clm/layer1/operations/base.py +109 -0
- clm/layer1/operations/builtins.py +338 -0
- clm/layer1/operations/dispatch.py +144 -0
- clm/layer1/operations/exclude.py +107 -0
- clm/layer1/operations/handle.py +197 -0
- clm/layer1/operations/identity.py +139 -0
- clm/layer1/operations/invert.py +66 -0
- clm/layer1/operations/loader.py +116 -0
- clm/layer1/operations/manipulators/__init__.py +23 -0
- clm/layer1/operations/manipulators/document.py +211 -0
- clm/layer1/operations/manipulators/media.py +134 -0
- clm/layer1/operations/manipulators/structured.py +159 -0
- clm/layer1/operations/manipulators/tabular.py +334 -0
- clm/layer1/operations/port.py +65 -0
- clm/layer1/operations/services.py +529 -0
- clm/layer1/operations/split.py +117 -0
- clm/layer1/operations/substitute.py +75 -0
- clm/layer1/petri.py +1052 -0
- clm/layer1/pocketflow_orchestrator.py +408 -0
- clm/layer1/pocketflow_scheduler.py +519 -0
- clm/layer1/protocols.py +197 -0
- clm/layer1/runtime_adapter.py +718 -0
- clm/layer1/runtimes/__init__.py +71 -0
- clm/layer1/runtimes/_generated_assertions.py +125 -0
- clm/layer1/runtimes/_generated_types.py +42 -0
- clm/layer1/runtimes/base.py +265 -0
- clm/layer1/runtimes/binary.py +101 -0
- clm/layer1/runtimes/factory.py +203 -0
- clm/layer1/runtimes/javascript.py +321 -0
- clm/layer1/runtimes/javascript_runtime.js +33 -0
- clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
- clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
- clm/layer1/runtimes/lambda_calc.py +126 -0
- clm/layer1/runtimes/python.py +288 -0
- clm/layer1/runtimes/python_runtime.py +41 -0
- clm/layer1/runtimes/script.py +114 -0
- clm/layer1/sandbox.py +334 -0
- clm/layer1/savepoint_guard.py +136 -0
- clm/layer1/sparse_net.py +122 -0
- clm/layer1/spec_tester.py +165 -0
- clm/layer1/store.py +295 -0
- clm/layer1/test_runner.py +498 -0
- clm/layer1/type_inspector.py +166 -0
- clm/layer1/verifier.py +772 -0
- clm/layer1/vm.py +91 -0
- clm/layer2/__init__.py +78 -0
- clm/layer2/card_collection.py +678 -0
- clm/layer2/classifier.py +479 -0
- clm/layer2/engine/__init__.py +1 -0
- clm/layer2/engine/abstract_sql_engine.py +320 -0
- clm/layer2/engine/base.py +193 -0
- clm/layer2/engine/duckdb_engine.py +576 -0
- clm/layer2/engine/sqlite_engine.py +518 -0
- clm/layer2/fiber/__init__.py +31 -0
- clm/layer2/fiber/context.py +89 -0
- clm/layer2/fiber/disposable.py +163 -0
- clm/layer2/fiber/fiber.py +125 -0
- clm/layer2/fiber/hoare.py +191 -0
- clm/layer2/file_io.py +376 -0
- clm/layer2/file_registrar.py +77 -0
- clm/layer2/ingest.py +202 -0
- clm/layer2/lineage.py +322 -0
- clm/layer2/mcard_fs.py +262 -0
- clm/layer2/merkle.py +11 -0
- clm/layer2/mime.py +244 -0
- clm/layer2/mime_detector.py +245 -0
- clm/layer2/private_collection.py +118 -0
- clm/layer2/shared_store.py +11 -0
- clm/layer2/storage/__init__.py +190 -0
- clm/layer2/storage/db_bitemporal.py +141 -0
- clm/layer2/storage/db_driver.py +331 -0
- clm/layer2/storage/db_hyperlinks.py +214 -0
- clm/layer2/storage/db_pool.py +139 -0
- clm/layer2/storage/db_repository.py +229 -0
- clm/layer2/storage/savepoint.py +78 -0
- clm/layer2/storage/sqlite_wal.py +74 -0
- clm/layer2/tridb.py +245 -0
- clm/layer2/vcard_receipt.py +71 -0
- clm/layer2/vfs.py +17 -0
- clm/layer3/__init__.py +141 -0
- clm/layer3/agency/__init__.py +19 -0
- clm/layer3/agency/config.py +220 -0
- clm/layer3/agency/providers/__init__.py +15 -0
- clm/layer3/agency/providers/base.py +91 -0
- clm/layer3/agency/providers/mlc_llm.py +169 -0
- clm/layer3/agency/providers/ollama.py +203 -0
- clm/layer3/agency/router.py +71 -0
- clm/layer3/agency/runtime.py +524 -0
- clm/layer3/gateway.py +353 -0
- clm/layer3/open_interpreter_adapter.py +159 -0
- clm/layer3/rag/__init__.py +70 -0
- clm/layer3/rag/cli.py +228 -0
- clm/layer3/rag/config.py +153 -0
- clm/layer3/rag/embeddings/__init__.py +16 -0
- clm/layer3/rag/embeddings/base.py +79 -0
- clm/layer3/rag/embeddings/ollama.py +211 -0
- clm/layer3/rag/embeddings/vision.py +290 -0
- clm/layer3/rag/engine.py +276 -0
- clm/layer3/rag/graph/__init__.py +22 -0
- clm/layer3/rag/graph/community.py +198 -0
- clm/layer3/rag/graph/engine.py +433 -0
- clm/layer3/rag/graph/extractor.py +255 -0
- clm/layer3/rag/graph/schema.py +115 -0
- clm/layer3/rag/graph/store.py +641 -0
- clm/layer3/rag/indexer.py +333 -0
- clm/layer3/rag/llm_providers.json +52 -0
- clm/layer3/rag/semantic_versioning.py +313 -0
- clm/layer3/rag/vector/__init__.py +28 -0
- clm/layer3/rag/vector/handle_vector_store.py +749 -0
- clm/layer3/rag/vector/schema.py +151 -0
- clm/layer3/rag/vector/store.py +632 -0
- clm/layer3/reticulum/__init__.py +55 -0
- clm/layer3/reticulum/bridge.py +74 -0
- clm/layer3/reticulum/daemon.py +88 -0
- clm/layer3/reticulum/discovery.py +164 -0
- clm/layer3/reticulum/identity.py +107 -0
- clm/layer3/reticulum/media.py +148 -0
- clm/layer3/reticulum/transport.py +133 -0
- clm/layer3/satori/__init__.py +209 -0
- clm/layer3/satori/alpha_conversion.py +168 -0
- clm/layer3/satori/beta_reduction.py +359 -0
- clm/layer3/satori/continuation.py +38 -0
- clm/layer3/satori/eta_conversion.py +205 -0
- clm/layer3/satori/free_variables.py +163 -0
- clm/layer3/satori/io_effects.py +370 -0
- clm/layer3/satori/lambda_runtime.py +726 -0
- clm/layer3/satori/lambda_term.py +230 -0
- clm/layer3/satori/sheaf_audit.py +261 -0
- clm/layer3/satori/speech_act.py +279 -0
- clm/layer4/README.md +9 -0
- clm/layer4/__init__.py +67 -0
- clm/layer4/_sovereign_executor.py +580 -0
- clm/layer4/action_commands.py +719 -0
- clm/layer4/api.py +236 -0
- clm/layer4/bootstrap/__init__.py +13 -0
- clm/layer4/bootstrap/bootstrapper.py +118 -0
- clm/layer4/bootstrap/cleanup.py +44 -0
- clm/layer4/bootstrap/clm_hooks.py +49 -0
- clm/layer4/bootstrap/genesis.py +77 -0
- clm/layer4/bootstrap/injection.py +125 -0
- clm/layer4/cli.py +549 -0
- clm/layer4/collection_manager.py +553 -0
- clm/layer4/commands/__init__.py +81 -0
- clm/layer4/commands/action_cmd.py +42 -0
- clm/layer4/commands/check_cmd.py +82 -0
- clm/layer4/commands/envelope.py +73 -0
- clm/layer4/commands/evaluate_cmd.py +224 -0
- clm/layer4/commands/mcard_cmd.py +24 -0
- clm/layer4/commands/petri_cmd.py +92 -0
- clm/layer4/commands/tridb_cmd.py +319 -0
- clm/layer4/commands/version_cmd.py +27 -0
- clm/layer4/diff_commands.py +167 -0
- clm/layer4/eoa_sponsor.py +232 -0
- clm/layer4/events.py +69 -0
- clm/layer4/flux_gateway.py +133 -0
- clm/layer4/gateway.py +91 -0
- clm/layer4/loader.py +307 -0
- clm/layer4/mcard_commands.py +166 -0
- clm/layer4/membrane.py +273 -0
- clm/layer4/navigation.py +50 -0
- clm/layer4/protocol/protocol_entry_python.py +108 -0
- clm/layer4/protocol/python_sync.py +126 -0
- clm/layer4/runner.py +150 -0
- clm/layer4/satori.py +262 -0
- clm/layer4/server/python_sync_client.py +150 -0
- clm/layer4/server/python_sync_server.py +139 -0
- clm/layer4/server/service_api.py +315 -0
- clm/layer4/server/start_servers.py +107 -0
- clm/layer4/server/stop_servers.py +24 -0
- clm/layer4/simulated_optimization_fix.py +0 -0
- clm/layer4/storage.py +463 -0
- clm/layer4/tridb_admin.py +268 -0
- clm/layer4/websocket/test_ws_client.py +104 -0
- clm/layer4/websocket/test_ws_server.py +138 -0
- clm/layer4/websocket/ws_server_local.py +160 -0
- clm/layer5/__init__.py +51 -0
- clm/layer5/async_batch_writer.py +133 -0
- clm/layer5/learning.py +276 -0
- clm/layer5/telemetry_hook.py +107 -0
- clm/layer5/type_lattice.py +238 -0
- clm/py.typed +0 -0
- clm/schemas/__init__.py +652 -0
- clm/schemas/abstract_face_schema.yaml +77 -0
- clm/schemas/cel_schema.yaml +416 -0
- clm/schemas/lifecycle/__init__.py +45 -0
- clm/schemas/lifecycle/models.py +123 -0
- clm/schemas/lifecycle/service.py +364 -0
- clm/schemas/mcard_schema.sql +192 -0
- clm/schemas/mcard_vector_schema.sql +283 -0
- clm/schemas/mlp-context-v1.json +91 -0
- clm_kernel-0.0.0.dist-info/METADATA +121 -0
- clm_kernel-0.0.0.dist-info/RECORD +333 -0
- clm_kernel-0.0.0.dist-info/WHEEL +4 -0
- clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
- 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")
|