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
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""CLM Manifest IO helpers (Sprint 133.1).
|
|
2
|
+
|
|
3
|
+
Extracted from ``algebra.py``. Handles loading, normalizing, and parsing
|
|
4
|
+
CLM YAML manifest files.
|
|
5
|
+
"""
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
import yaml
|
|
11
|
+
|
|
12
|
+
from clm.layer0.utils import HASH_PREFIX, clm_hash_string
|
|
13
|
+
|
|
14
|
+
from .utils import resolve_clm_path
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def load_normalized_manifest_str(clm_root: str, clm_file: str) -> str:
|
|
18
|
+
"""Loads and normalizes the contents of a CLM manifest file as a string."""
|
|
19
|
+
clm_file = resolve_clm_path(clm_root, clm_file)
|
|
20
|
+
normalizer_py = os.path.join(clm_root, "computable_knowledge/Concrete/layer5_system/bootstrap/layer2_storage/clm_normalize_syntax.py")
|
|
21
|
+
if os.path.exists(normalizer_py):
|
|
22
|
+
proc = subprocess.Popen([sys.executable, normalizer_py, clm_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
23
|
+
stdout_data, _ = proc.communicate()
|
|
24
|
+
if proc.returncode == 0:
|
|
25
|
+
temp_path = stdout_data.strip()
|
|
26
|
+
if os.path.exists(temp_path):
|
|
27
|
+
try:
|
|
28
|
+
with open(temp_path, encoding='utf-8') as f:
|
|
29
|
+
norm_content = f.read()
|
|
30
|
+
os.remove(temp_path)
|
|
31
|
+
return norm_content
|
|
32
|
+
except Exception:
|
|
33
|
+
pass
|
|
34
|
+
with open(clm_file, encoding='utf-8') as f:
|
|
35
|
+
return f.read()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def load_normalized_manifest(clm_root: str, clm_file: str) -> dict:
|
|
39
|
+
"""Loads and normalizes a CLM manifest, parsing it as a dictionary."""
|
|
40
|
+
clm_file = resolve_clm_path(clm_root, clm_file)
|
|
41
|
+
content_str = load_normalized_manifest_str(clm_root, clm_file)
|
|
42
|
+
return yaml.safe_load(content_str)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def compute_stripped_file_hash_py(filepath: str) -> str:
|
|
46
|
+
"""Computes SHA-256 of a file after stripping trailing CR/LF."""
|
|
47
|
+
if not os.path.exists(filepath):
|
|
48
|
+
return f"{HASH_PREFIX}unknown"
|
|
49
|
+
with open(filepath, encoding='utf-8') as f:
|
|
50
|
+
content = f.read()
|
|
51
|
+
trimmed = content.rstrip('\r\n')
|
|
52
|
+
return clm_hash_string(trimmed)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def execute_pcard_py(clm_root: str, clm_file: str, payload: str) -> str:
|
|
56
|
+
"""Executes a PCard in a nested sandbox."""
|
|
57
|
+
engine_py = os.path.join(clm_root, "kernel/scripts/clm_runner.py")
|
|
58
|
+
if not os.path.exists(engine_py):
|
|
59
|
+
engine_py = __file__
|
|
60
|
+
|
|
61
|
+
cmd = [sys.executable, engine_py, "evaluate", clm_file, payload]
|
|
62
|
+
env = os.environ.copy()
|
|
63
|
+
env["CLM_PAYLOAD"] = payload
|
|
64
|
+
env["CLM_NESTED_EXEC"] = "1"
|
|
65
|
+
env["CLM_ZERO_FS"] = "true"
|
|
66
|
+
env["CLM_SKIP_GRAMMAR"] = "1"
|
|
67
|
+
|
|
68
|
+
proc = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
69
|
+
stdout_data, _ = proc.communicate()
|
|
70
|
+
if proc.returncode == 0:
|
|
71
|
+
stdout_str = stdout_data
|
|
72
|
+
idx = stdout_str.find("[POST] V_post:")
|
|
73
|
+
if idx != -1:
|
|
74
|
+
stdout_str = stdout_str[:idx]
|
|
75
|
+
return stdout_str.strip()
|
|
76
|
+
else:
|
|
77
|
+
return ""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def parse_json_or_yaml_py(s: str):
|
|
81
|
+
"""Parses a string as JSON or YAML, falling back to YAML if JSON fails."""
|
|
82
|
+
s_trimmed = s.strip()
|
|
83
|
+
if not s_trimmed:
|
|
84
|
+
return None
|
|
85
|
+
try:
|
|
86
|
+
import json
|
|
87
|
+
return json.loads(s_trimmed)
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
90
|
+
try:
|
|
91
|
+
return yaml.safe_load(s_trimmed)
|
|
92
|
+
except Exception:
|
|
93
|
+
pass
|
|
94
|
+
raise Exception("Not valid JSON or YAML")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def canonical_value_py(val):
|
|
98
|
+
"""Recursively sorts dictionary keys to produce canonical representation."""
|
|
99
|
+
if isinstance(val, dict):
|
|
100
|
+
sorted_keys = sorted(val.keys())
|
|
101
|
+
return {k: canonical_value_py(val[k]) for k in sorted_keys}
|
|
102
|
+
elif isinstance(val, list):
|
|
103
|
+
return [canonical_value_py(item) for item in val]
|
|
104
|
+
else:
|
|
105
|
+
return val
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def clean_data_py(val):
|
|
109
|
+
"""Recursively removes metadata keys to allow comparison of core data."""
|
|
110
|
+
if isinstance(val, dict):
|
|
111
|
+
cleaned = {}
|
|
112
|
+
for k, v in val.items():
|
|
113
|
+
if k in (
|
|
114
|
+
"timestamp", "g_time", "run_id", "previous_hash", "changed_at",
|
|
115
|
+
"created_at", "updated_at", "witness_trail", "performance_differential",
|
|
116
|
+
"agent_did", "uuid", "g_time_note", "genesis_hash", "genesis_note"
|
|
117
|
+
):
|
|
118
|
+
continue
|
|
119
|
+
cleaned[k] = clean_data_py(v)
|
|
120
|
+
return cleaned
|
|
121
|
+
elif isinstance(val, list):
|
|
122
|
+
import json
|
|
123
|
+
cleaned_list = [clean_data_py(item) for item in val]
|
|
124
|
+
cleaned_list.sort(key=lambda x: json.dumps(canonical_value_py(x), sort_keys=True, separators=(',', ':')))
|
|
125
|
+
return cleaned_list
|
|
126
|
+
else:
|
|
127
|
+
return val
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def compare_numerical_py(s_a: str, s_b: str) -> bool:
|
|
131
|
+
"""Compares two numerical strings for approximate equivalence."""
|
|
132
|
+
try:
|
|
133
|
+
a = float(s_a.strip())
|
|
134
|
+
b = float(s_b.strip())
|
|
135
|
+
return abs(a - b) <= 1e-6
|
|
136
|
+
except Exception:
|
|
137
|
+
return False
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def check_content_equivalent_py(clm_root: str, hash_a: str, hash_b: str) -> bool:
|
|
141
|
+
"""Checks if two hashes resolve to the exact same content in the CLM database."""
|
|
142
|
+
if hash_a == hash_b:
|
|
143
|
+
return True
|
|
144
|
+
from .db import CLMDB
|
|
145
|
+
db = CLMDB(clm_root)
|
|
146
|
+
sql = "SELECT content FROM card WHERE hash = ?;"
|
|
147
|
+
try:
|
|
148
|
+
res_a = db.execute("content_memory", sql, [hash_a])
|
|
149
|
+
res_b = db.execute("content_memory", sql, [hash_b])
|
|
150
|
+
content_a = res_a.strip() if res_a else ""
|
|
151
|
+
content_b = res_b.strip() if res_b else ""
|
|
152
|
+
if content_a and content_b:
|
|
153
|
+
return content_a == content_b
|
|
154
|
+
except Exception:
|
|
155
|
+
pass
|
|
156
|
+
return False
|
clm/layer0/assembler.py
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
"""CLM Assembler - Dynamic assembly of CLM components using MCard Collections (Layer 0).
|
|
2
|
+
|
|
3
|
+
Part of Phase 7 (Sprint 383: Layer 0 Kenotic Core & Parser Unification).
|
|
4
|
+
Provides functionality to dynamically assemble complete CLM specifications
|
|
5
|
+
from individual Abstract, Concrete, and Balanced components stored as MCards.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
import yaml
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
from clm.layer0.model.card import MCard
|
|
19
|
+
except ImportError:
|
|
20
|
+
from clm.layer0.mcard import MCard
|
|
21
|
+
|
|
22
|
+
from clm.layer0.loader import YAMLTemplateLoader
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class CLMComponent:
|
|
27
|
+
"""Individual CLM component (Abstract, Concrete, or Balanced)"""
|
|
28
|
+
|
|
29
|
+
dimension: str # 'abstract', 'concrete', or 'balanced'
|
|
30
|
+
name: str
|
|
31
|
+
content: dict[str, Any]
|
|
32
|
+
mcard_hash: str
|
|
33
|
+
version: str = "1.0.0"
|
|
34
|
+
dependencies: list[str] | None = None # Hashes of dependent components
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class AssembledCLM:
|
|
39
|
+
"""Complete assembled CLM specification"""
|
|
40
|
+
|
|
41
|
+
name: str
|
|
42
|
+
abstract: CLMComponent
|
|
43
|
+
concrete: CLMComponent
|
|
44
|
+
balanced: CLMComponent
|
|
45
|
+
assembly_hash: str # Hash of the assembled CLM MCard
|
|
46
|
+
created_at: datetime
|
|
47
|
+
validation_result: ValidationResult | None = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class ValidationResult:
|
|
52
|
+
"""Result of CLM assembly validation"""
|
|
53
|
+
|
|
54
|
+
is_valid: bool
|
|
55
|
+
errors: list[str]
|
|
56
|
+
warnings: list[str]
|
|
57
|
+
consistency_checks: dict[str, bool]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class CLMAssembler:
|
|
61
|
+
"""Assembler for dynamic CLM construction using MCard Collections.
|
|
62
|
+
|
|
63
|
+
This class enables:
|
|
64
|
+
- Loading CLM components from MCard storage
|
|
65
|
+
- Assembling complete CLM specifications
|
|
66
|
+
- Validating assembled CLMs
|
|
67
|
+
- Storing and retrieving assembled CLMs
|
|
68
|
+
- Managing component dependencies
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self, storage_collection=None, template_loader: YAMLTemplateLoader | None = None
|
|
73
|
+
):
|
|
74
|
+
self.logger = logging.getLogger(__name__)
|
|
75
|
+
self.collection = storage_collection
|
|
76
|
+
self.template_loader = template_loader or YAMLTemplateLoader(storage_collection)
|
|
77
|
+
self.component_cache: dict[str, CLMComponent] = {}
|
|
78
|
+
self.assembly_cache: dict[str, AssembledCLM] = {}
|
|
79
|
+
|
|
80
|
+
self.logger.info("CLM Assembler initialized")
|
|
81
|
+
|
|
82
|
+
def load_component_from_mcard(self, component_hash: str) -> CLMComponent:
|
|
83
|
+
"""Load a CLM component from MCard storage.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
component_hash: Hash of the component MCard
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
CLMComponent object
|
|
90
|
+
"""
|
|
91
|
+
if component_hash in self.component_cache:
|
|
92
|
+
return self.component_cache[component_hash]
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
component_mcard = self.collection.get(component_hash)
|
|
96
|
+
if not component_mcard:
|
|
97
|
+
raise ValueError(f"Component MCard not found: {component_hash}")
|
|
98
|
+
|
|
99
|
+
content_bytes = component_mcard.get_content()
|
|
100
|
+
component_yaml = (
|
|
101
|
+
content_bytes.decode("utf-8")
|
|
102
|
+
if isinstance(content_bytes, bytes)
|
|
103
|
+
else str(content_bytes)
|
|
104
|
+
)
|
|
105
|
+
component_data = yaml.safe_load(component_yaml)
|
|
106
|
+
|
|
107
|
+
metadata = component_data.get("metadata", {})
|
|
108
|
+
content = component_data.get("template", component_data.get("content", {}))
|
|
109
|
+
|
|
110
|
+
component = CLMComponent(
|
|
111
|
+
dimension=metadata.get("dimension", "unknown"),
|
|
112
|
+
name=metadata.get("name", "unknown"),
|
|
113
|
+
content=content,
|
|
114
|
+
mcard_hash=component_hash,
|
|
115
|
+
version=metadata.get("version", "1.0.0"),
|
|
116
|
+
dependencies=metadata.get("dependencies", []),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
self.component_cache[component_hash] = component
|
|
120
|
+
|
|
121
|
+
self.logger.info(
|
|
122
|
+
f"Loaded component {component.name} ({component.dimension}) from MCard"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
return component
|
|
126
|
+
|
|
127
|
+
except (
|
|
128
|
+
yaml.YAMLError,
|
|
129
|
+
ValueError,
|
|
130
|
+
TypeError,
|
|
131
|
+
KeyError,
|
|
132
|
+
UnicodeDecodeError,
|
|
133
|
+
) as e:
|
|
134
|
+
self.logger.error(
|
|
135
|
+
f"Failed to load component from MCard {component_hash}: {str(e)}",
|
|
136
|
+
exc_info=True,
|
|
137
|
+
)
|
|
138
|
+
raise ValueError(f"Component loading failed: {str(e)}") from e
|
|
139
|
+
|
|
140
|
+
def create_component_from_template(
|
|
141
|
+
self,
|
|
142
|
+
dimension: str,
|
|
143
|
+
name: str,
|
|
144
|
+
template_data: dict[str, Any],
|
|
145
|
+
dependencies: list[str] | None = None,
|
|
146
|
+
) -> CLMComponent:
|
|
147
|
+
"""Create a CLM component from template data.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
dimension: CLM dimension ('abstract', 'concrete', or 'balanced')
|
|
151
|
+
name: Component name
|
|
152
|
+
template_data: Template content
|
|
153
|
+
dependencies: List of dependent component hashes
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
CLMComponent object
|
|
157
|
+
"""
|
|
158
|
+
try:
|
|
159
|
+
component_metadata = {
|
|
160
|
+
"type": "CLM_Component",
|
|
161
|
+
"dimension": dimension,
|
|
162
|
+
"name": name,
|
|
163
|
+
"version": "1.0.0",
|
|
164
|
+
"dependencies": dependencies or [],
|
|
165
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
component_data = {"metadata": component_metadata, "content": template_data}
|
|
169
|
+
component_yaml = yaml.safe_dump(component_data, default_flow_style=False)
|
|
170
|
+
component_mcard = MCard(component_yaml)
|
|
171
|
+
component_hash = self.collection.add(component_mcard)
|
|
172
|
+
|
|
173
|
+
component = CLMComponent(
|
|
174
|
+
dimension=dimension,
|
|
175
|
+
name=name,
|
|
176
|
+
content=template_data,
|
|
177
|
+
mcard_hash=component_hash,
|
|
178
|
+
version="1.0.0",
|
|
179
|
+
dependencies=dependencies or [],
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
self.component_cache[component_hash] = component
|
|
183
|
+
|
|
184
|
+
self.logger.info(
|
|
185
|
+
f"Created component {name} ({dimension}) as MCard: {component_hash}"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return component
|
|
189
|
+
|
|
190
|
+
except (yaml.YAMLError, ValueError, TypeError, KeyError) as e:
|
|
191
|
+
self.logger.error(
|
|
192
|
+
f"Failed to create component from template: {str(e)}", exc_info=True
|
|
193
|
+
)
|
|
194
|
+
raise ValueError(f"Component creation failed: {str(e)}") from e
|
|
195
|
+
|
|
196
|
+
def assemble_clm(
|
|
197
|
+
self,
|
|
198
|
+
abstract_hash: str,
|
|
199
|
+
concrete_hash: str,
|
|
200
|
+
balanced_hash: str,
|
|
201
|
+
name: str | None = None,
|
|
202
|
+
) -> AssembledCLM:
|
|
203
|
+
"""Assemble a complete CLM from individual components.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
abstract_hash: Hash of abstract component
|
|
207
|
+
concrete_hash: Hash of concrete component
|
|
208
|
+
balanced_hash: Hash of balanced component
|
|
209
|
+
name: Optional name for the assembled CLM
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
AssembledCLM object
|
|
213
|
+
"""
|
|
214
|
+
try:
|
|
215
|
+
abstract = self.load_component_from_mcard(abstract_hash)
|
|
216
|
+
concrete = self.load_component_from_mcard(concrete_hash)
|
|
217
|
+
balanced = self.load_component_from_mcard(balanced_hash)
|
|
218
|
+
|
|
219
|
+
if abstract.dimension != "abstract":
|
|
220
|
+
raise ValueError(
|
|
221
|
+
f"Expected abstract component, got {abstract.dimension}"
|
|
222
|
+
)
|
|
223
|
+
if concrete.dimension != "concrete":
|
|
224
|
+
raise ValueError(
|
|
225
|
+
f"Expected concrete component, got {concrete.dimension}"
|
|
226
|
+
)
|
|
227
|
+
if balanced.dimension != "balanced":
|
|
228
|
+
raise ValueError(
|
|
229
|
+
f"Expected balanced component, got {balanced.dimension}"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
if not name:
|
|
233
|
+
name = f"CLM_{abstract.name}_{concrete.name}_{balanced.name}"
|
|
234
|
+
|
|
235
|
+
validation_result = self._validate_clm_assembly(
|
|
236
|
+
abstract, concrete, balanced
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
assembled_data = {
|
|
240
|
+
"type": "Assembled_CLM",
|
|
241
|
+
"name": name,
|
|
242
|
+
"version": "1.0.0",
|
|
243
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
244
|
+
"components": {
|
|
245
|
+
"abstract": {
|
|
246
|
+
"name": abstract.name,
|
|
247
|
+
"hash": abstract_hash,
|
|
248
|
+
"version": abstract.version,
|
|
249
|
+
},
|
|
250
|
+
"concrete": {
|
|
251
|
+
"name": concrete.name,
|
|
252
|
+
"hash": concrete_hash,
|
|
253
|
+
"version": concrete.version,
|
|
254
|
+
},
|
|
255
|
+
"balanced": {
|
|
256
|
+
"name": balanced.name,
|
|
257
|
+
"hash": balanced_hash,
|
|
258
|
+
"version": balanced.version,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
"content": {
|
|
262
|
+
"abstract": abstract.content,
|
|
263
|
+
"concrete": concrete.content,
|
|
264
|
+
"balanced": balanced.content,
|
|
265
|
+
},
|
|
266
|
+
"validation": {
|
|
267
|
+
"is_valid": validation_result.is_valid,
|
|
268
|
+
"errors": validation_result.errors,
|
|
269
|
+
"warnings": validation_result.warnings,
|
|
270
|
+
"consistency_checks": validation_result.consistency_checks,
|
|
271
|
+
},
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
assembled_yaml = yaml.safe_dump(assembled_data, default_flow_style=False)
|
|
275
|
+
assembled_mcard = MCard(assembled_yaml)
|
|
276
|
+
assembly_hash = self.collection.add(assembled_mcard)
|
|
277
|
+
|
|
278
|
+
assembled_clm = AssembledCLM(
|
|
279
|
+
name=name,
|
|
280
|
+
abstract=abstract,
|
|
281
|
+
concrete=concrete,
|
|
282
|
+
balanced=balanced,
|
|
283
|
+
assembly_hash=assembly_hash,
|
|
284
|
+
created_at=datetime.now(timezone.utc),
|
|
285
|
+
validation_result=validation_result,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
self.assembly_cache[assembly_hash] = assembled_clm
|
|
289
|
+
|
|
290
|
+
self.logger.info(
|
|
291
|
+
f"Assembled CLM {name}: {'VALID' if validation_result.is_valid else 'INVALID'}"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
return assembled_clm
|
|
295
|
+
|
|
296
|
+
except (yaml.YAMLError, ValueError, TypeError, KeyError) as e:
|
|
297
|
+
self.logger.error(f"Failed to assemble CLM: {str(e)}", exc_info=True)
|
|
298
|
+
raise ValueError(f"CLM assembly failed: {str(e)}") from e
|
|
299
|
+
|
|
300
|
+
def load_assembled_clm(self, assembly_hash: str) -> AssembledCLM:
|
|
301
|
+
"""Load an assembled CLM from MCard storage.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
assembly_hash: Hash of the assembled CLM MCard
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
AssembledCLM object
|
|
308
|
+
"""
|
|
309
|
+
if assembly_hash in self.assembly_cache:
|
|
310
|
+
return self.assembly_cache[assembly_hash]
|
|
311
|
+
|
|
312
|
+
try:
|
|
313
|
+
assembled_mcard = self.collection.get(assembly_hash)
|
|
314
|
+
if not assembled_mcard:
|
|
315
|
+
raise ValueError(f"Assembled CLM not found: {assembly_hash}")
|
|
316
|
+
|
|
317
|
+
content_bytes = assembled_mcard.get_content()
|
|
318
|
+
assembled_yaml = (
|
|
319
|
+
content_bytes.decode("utf-8")
|
|
320
|
+
if isinstance(content_bytes, bytes)
|
|
321
|
+
else str(content_bytes)
|
|
322
|
+
)
|
|
323
|
+
assembled_data = yaml.safe_load(assembled_yaml)
|
|
324
|
+
|
|
325
|
+
components = assembled_data.get("components", {})
|
|
326
|
+
abstract_info = components.get("abstract", {})
|
|
327
|
+
concrete_info = components.get("concrete", {})
|
|
328
|
+
balanced_info = components.get("balanced", {})
|
|
329
|
+
|
|
330
|
+
abstract = self.load_component_from_mcard(abstract_info["hash"])
|
|
331
|
+
concrete = self.load_component_from_mcard(concrete_info["hash"])
|
|
332
|
+
balanced = self.load_component_from_mcard(balanced_info["hash"])
|
|
333
|
+
|
|
334
|
+
validation_data = assembled_data.get("validation", {})
|
|
335
|
+
validation_result = ValidationResult(
|
|
336
|
+
is_valid=validation_data.get("is_valid", True),
|
|
337
|
+
errors=validation_data.get("errors", []),
|
|
338
|
+
warnings=validation_data.get("warnings", []),
|
|
339
|
+
consistency_checks=validation_data.get("consistency_checks", {}),
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
created_at_str = assembled_data.get(
|
|
343
|
+
"created_at", datetime.now(timezone.utc).isoformat()
|
|
344
|
+
)
|
|
345
|
+
assembled_clm = AssembledCLM(
|
|
346
|
+
name=assembled_data.get("name", "unknown"),
|
|
347
|
+
abstract=abstract,
|
|
348
|
+
concrete=concrete,
|
|
349
|
+
balanced=balanced,
|
|
350
|
+
assembly_hash=assembly_hash,
|
|
351
|
+
created_at=datetime.fromisoformat(created_at_str),
|
|
352
|
+
validation_result=validation_result,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
self.assembly_cache[assembly_hash] = assembled_clm
|
|
356
|
+
|
|
357
|
+
self.logger.info(f"Loaded assembled CLM {assembled_clm.name} from MCard")
|
|
358
|
+
|
|
359
|
+
return assembled_clm
|
|
360
|
+
|
|
361
|
+
except (
|
|
362
|
+
yaml.YAMLError,
|
|
363
|
+
ValueError,
|
|
364
|
+
TypeError,
|
|
365
|
+
KeyError,
|
|
366
|
+
UnicodeDecodeError,
|
|
367
|
+
) as e:
|
|
368
|
+
self.logger.error(
|
|
369
|
+
f"Failed to load assembled CLM {assembly_hash}: {str(e)}", exc_info=True
|
|
370
|
+
)
|
|
371
|
+
raise ValueError(f"Assembled CLM loading failed: {str(e)}") from e
|
|
372
|
+
|
|
373
|
+
def find_compatible_components(
|
|
374
|
+
self, dimension: str, filters: dict[str, Any] | None = None
|
|
375
|
+
) -> list[CLMComponent]:
|
|
376
|
+
"""Find compatible components for a given dimension."""
|
|
377
|
+
try:
|
|
378
|
+
search_term = f"CLM_Component_{dimension}"
|
|
379
|
+
if filters and "name" in filters:
|
|
380
|
+
search_term = f"{search_term}_{filters['name']}"
|
|
381
|
+
|
|
382
|
+
found_cards = self.collection.search_by_string(search_term)
|
|
383
|
+
components = []
|
|
384
|
+
|
|
385
|
+
for card in found_cards.items:
|
|
386
|
+
try:
|
|
387
|
+
component = self.load_component_from_mcard(card.hash)
|
|
388
|
+
|
|
389
|
+
if filters:
|
|
390
|
+
match = True
|
|
391
|
+
for key, value in filters.items():
|
|
392
|
+
if key == "name" and component.name != value or key == "version" and component.version != value:
|
|
393
|
+
match = False
|
|
394
|
+
break
|
|
395
|
+
if not match:
|
|
396
|
+
continue
|
|
397
|
+
|
|
398
|
+
components.append(component)
|
|
399
|
+
|
|
400
|
+
except (ValueError, KeyError, TypeError) as e:
|
|
401
|
+
self.logger.warning(
|
|
402
|
+
f"Failed to load component {card.hash}: {str(e)}"
|
|
403
|
+
)
|
|
404
|
+
continue
|
|
405
|
+
|
|
406
|
+
self.logger.info(
|
|
407
|
+
f"Found {len(components)} compatible components for {dimension}"
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
return components
|
|
411
|
+
|
|
412
|
+
except (ValueError, TypeError, KeyError, AttributeError) as e:
|
|
413
|
+
self.logger.error(
|
|
414
|
+
f"Failed to find compatible components: {str(e)}", exc_info=True
|
|
415
|
+
)
|
|
416
|
+
return []
|
|
417
|
+
|
|
418
|
+
def _validate_clm_assembly(
|
|
419
|
+
self, abstract: CLMComponent, concrete: CLMComponent, balanced: CLMComponent
|
|
420
|
+
) -> ValidationResult:
|
|
421
|
+
"""Validate the consistency of assembled CLM components."""
|
|
422
|
+
errors = []
|
|
423
|
+
warnings = []
|
|
424
|
+
consistency_checks = {
|
|
425
|
+
"input_consistency": True,
|
|
426
|
+
"output_coverage": True,
|
|
427
|
+
"operation_testing": True,
|
|
428
|
+
"semantic_consistency": True,
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
try:
|
|
432
|
+
is_valid = True
|
|
433
|
+
self.logger.info("CLM assembly validation: VALID (lenient mode)")
|
|
434
|
+
|
|
435
|
+
return ValidationResult(
|
|
436
|
+
is_valid=is_valid,
|
|
437
|
+
errors=errors,
|
|
438
|
+
warnings=warnings,
|
|
439
|
+
consistency_checks=consistency_checks,
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
except (ValueError, TypeError, KeyError) as e:
|
|
443
|
+
self.logger.error(f"CLM assembly validation error: {str(e)}", exc_info=True)
|
|
444
|
+
return ValidationResult(
|
|
445
|
+
is_valid=False,
|
|
446
|
+
errors=[f"Validation error: {str(e)}"],
|
|
447
|
+
warnings=[],
|
|
448
|
+
consistency_checks={},
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
def list_assembled_clms(self) -> list[AssembledCLM]:
|
|
452
|
+
"""List all assembled CLMs in the collection."""
|
|
453
|
+
try:
|
|
454
|
+
found_cards = self.collection.search_by_string("Assembled_CLM")
|
|
455
|
+
assembled_clms = []
|
|
456
|
+
|
|
457
|
+
for card in found_cards.items:
|
|
458
|
+
try:
|
|
459
|
+
assembled_clm = self.load_assembled_clm(card.hash)
|
|
460
|
+
assembled_clms.append(assembled_clm)
|
|
461
|
+
except (ValueError, KeyError, TypeError) as e:
|
|
462
|
+
self.logger.warning(
|
|
463
|
+
f"Failed to load assembled CLM {card.hash}: {str(e)}"
|
|
464
|
+
)
|
|
465
|
+
continue
|
|
466
|
+
|
|
467
|
+
self.logger.info(f"Found {len(assembled_clms)} assembled CLMs")
|
|
468
|
+
|
|
469
|
+
return assembled_clms
|
|
470
|
+
|
|
471
|
+
except (ValueError, TypeError, KeyError, AttributeError) as e:
|
|
472
|
+
self.logger.error(f"Failed to list assembled CLMs: {str(e)}", exc_info=True)
|
|
473
|
+
return []
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
__all__ = [
|
|
477
|
+
"AssembledCLM",
|
|
478
|
+
"CLMAssembler",
|
|
479
|
+
"CLMComponent",
|
|
480
|
+
"ValidationResult",
|
|
481
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Pure CEL Expression Models and AST Schemas in Layer 0 (Sprint 384 / DEL-384-04).
|
|
2
|
+
|
|
3
|
+
Stateless Kenotic core representation for Common Expression Language ASTs,
|
|
4
|
+
predicates, field assertions, and RLCD meet contracts.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from clm.layer0.cel_eval import (
|
|
10
|
+
BailVerdict,
|
|
11
|
+
CelEvaluationResult,
|
|
12
|
+
CelEvaluator,
|
|
13
|
+
evaluate_cel_condition,
|
|
14
|
+
evaluate_vcard_meet,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"BailVerdict",
|
|
19
|
+
"CelEvaluationResult",
|
|
20
|
+
"CelEvaluator",
|
|
21
|
+
"evaluate_cel_condition",
|
|
22
|
+
"evaluate_vcard_meet",
|
|
23
|
+
]
|