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,718 @@
|
|
|
1
|
+
"""CLM Runtime Adapter — Polyglot runtime execution and cross-runtime parity verification.
|
|
2
|
+
|
|
3
|
+
Handles the dispatch of CLM payloads to different runtimes (shell, python, node, rust),
|
|
4
|
+
cross-runtime parity verification, composite evaluation, and internal reference tests.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import subprocess as _sp
|
|
10
|
+
import sys
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import yaml
|
|
14
|
+
|
|
15
|
+
from clm.cross_cutting.clm_logger import get_logger
|
|
16
|
+
from clm.cross_cutting.vcard import vcard_sandwich
|
|
17
|
+
from clm.layer0.context import CLMContext
|
|
18
|
+
from clm.layer0.utils import (
|
|
19
|
+
clm_hash_file,
|
|
20
|
+
clm_hash_string,
|
|
21
|
+
detect_host_os,
|
|
22
|
+
get_bash_command,
|
|
23
|
+
resolve_clm_path,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from .verifier import (
|
|
27
|
+
check_precondition_py,
|
|
28
|
+
emit_exec_mcard_py,
|
|
29
|
+
get_load_manifest,
|
|
30
|
+
normalize_output_py,
|
|
31
|
+
resolve_active_hashes_py,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
_logger = get_logger("clm.layer1.runtime_adapter")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _resolve_rust_binary(clm_root: str) -> str | None:
|
|
38
|
+
"""Locate the compiled clm_rust_core binary.
|
|
39
|
+
|
|
40
|
+
Sprint 144 (GAP-15): Try manifest-based resolution first via
|
|
41
|
+
`clm_rust_core resolve-binary --handle runtime:clm_rust_core`.
|
|
42
|
+
Fall back to hardcoded path list for first-boot / no-database scenarios.
|
|
43
|
+
"""
|
|
44
|
+
base = os.path.join(clm_root, "kernel", "clm_rust_core", "target")
|
|
45
|
+
candidates = []
|
|
46
|
+
for profile in ("release", "debug"):
|
|
47
|
+
candidate = os.path.join(base, profile, "clm_rust_core")
|
|
48
|
+
candidates.append(candidate)
|
|
49
|
+
|
|
50
|
+
# Find any available Rust binary to call resolve-binary
|
|
51
|
+
rust_bin_for_resolve = None
|
|
52
|
+
for path in candidates:
|
|
53
|
+
if os.path.exists(path):
|
|
54
|
+
rust_bin_for_resolve = path
|
|
55
|
+
break
|
|
56
|
+
|
|
57
|
+
# Try manifest-based resolution first (GAP-15)
|
|
58
|
+
if rust_bin_for_resolve:
|
|
59
|
+
try:
|
|
60
|
+
proc = _sp.Popen(
|
|
61
|
+
[rust_bin_for_resolve, "resolve-binary", "--handle", "runtime:clm_rust_core"],
|
|
62
|
+
stdout=_sp.PIPE, stderr=_sp.PIPE, text=True
|
|
63
|
+
)
|
|
64
|
+
stdout, _ = proc.communicate(timeout=5)
|
|
65
|
+
if proc.returncode == 0 and stdout.strip():
|
|
66
|
+
resolved = stdout.strip()
|
|
67
|
+
if os.path.exists(resolved):
|
|
68
|
+
return resolved
|
|
69
|
+
except Exception:
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
# Fallback: hardcoded path list
|
|
73
|
+
for path in candidates:
|
|
74
|
+
if os.path.exists(path):
|
|
75
|
+
return path
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _call_rust_binary(
|
|
80
|
+
exe: str,
|
|
81
|
+
args: list[str],
|
|
82
|
+
env: dict[str, str] | None = None,
|
|
83
|
+
stdin_data: str | None = None,
|
|
84
|
+
) -> tuple[int, str, str]:
|
|
85
|
+
"""Invoke the Rust binary with optional stdin and return (exit_code, stdout, stderr)."""
|
|
86
|
+
cmd = [exe] + args
|
|
87
|
+
proc = _sp.Popen(
|
|
88
|
+
cmd,
|
|
89
|
+
stdout=_sp.PIPE,
|
|
90
|
+
stderr=_sp.PIPE,
|
|
91
|
+
stdin=_sp.PIPE if stdin_data is not None else None,
|
|
92
|
+
text=True,
|
|
93
|
+
encoding="utf-8",
|
|
94
|
+
env=env or os.environ.copy(),
|
|
95
|
+
)
|
|
96
|
+
stdout_data, stderr_data = proc.communicate(input=stdin_data)
|
|
97
|
+
return proc.returncode, stdout_data, stderr_data
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def run_internal_reference_test(clm_root: str, clm_file: str, module_name: str) -> int:
|
|
101
|
+
"""
|
|
102
|
+
Runs an internal reference test for a specific module, simulating execution context.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
clm_root (str): The root directory of the CLM workspace.
|
|
106
|
+
clm_file (str): The path to the CLM PCard.
|
|
107
|
+
module_name (str): The name of the internal module/test to run.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
int: The exit code of the test.
|
|
111
|
+
"""
|
|
112
|
+
if module_name == "clm_rust_core::integration::test_mdns_peer_discovery":
|
|
113
|
+
_logger.warning("⚠️ STUB: mDNS peer discovery test not implemented in Python runtime; requires Rust binary (clm_rust_core)")
|
|
114
|
+
return 1
|
|
115
|
+
|
|
116
|
+
test_name = module_name.split("::")[-1]
|
|
117
|
+
overrides = {
|
|
118
|
+
"test_petri_net_suite": "petri_net_cases.sh",
|
|
119
|
+
"test_petri_binding_suite": "petri_binding_cases.sh",
|
|
120
|
+
"test_petri_invariants": "petri_invariant_cases.sh",
|
|
121
|
+
"test_monadic_pcard_resolve_handle": "test_monadic_pcards.sh",
|
|
122
|
+
"test_monadic_pcard_check_precondition": "test_monadic_pcards.sh",
|
|
123
|
+
"test_monadic_pcard_execute_payload": "test_monadic_pcards.sh",
|
|
124
|
+
"test_monadic_pcard_validate_postcondition": "test_monadic_pcards.sh",
|
|
125
|
+
"test_vcard_pre": "test_monadic_pcards.sh",
|
|
126
|
+
}
|
|
127
|
+
target_filename = overrides.get(test_name, f"{test_name}.sh")
|
|
128
|
+
script_rel = None
|
|
129
|
+
for layer in ("00_microkernel", "01_cpn_vm", "02_storage", "03_network"):
|
|
130
|
+
candidate = f"tests/{layer}/{target_filename}"
|
|
131
|
+
if os.path.exists(os.path.join(clm_root, candidate)):
|
|
132
|
+
script_rel = candidate
|
|
133
|
+
break
|
|
134
|
+
|
|
135
|
+
if not script_rel:
|
|
136
|
+
for root, _dirs, files in os.walk(os.path.join(clm_root, "tests")):
|
|
137
|
+
if target_filename in files:
|
|
138
|
+
script_rel = os.path.relpath(os.path.join(root, target_filename), clm_root)
|
|
139
|
+
break
|
|
140
|
+
|
|
141
|
+
if not script_rel:
|
|
142
|
+
_logger.info(f"ERROR: Unknown internal reference module '{module_name}' (script not found)")
|
|
143
|
+
return 1
|
|
144
|
+
|
|
145
|
+
test_func = test_name
|
|
146
|
+
if test_name == "test_petri_math":
|
|
147
|
+
test_func = "test_petri_math_suite"
|
|
148
|
+
elif test_name == "test_petri_invariants":
|
|
149
|
+
test_func = "test_petri_invariant_suite"
|
|
150
|
+
elif test_name == "test_vcard_pre":
|
|
151
|
+
test_func = "test_monadic_pcard_check_precondition"
|
|
152
|
+
script_path = os.path.join(clm_root, script_rel)
|
|
153
|
+
|
|
154
|
+
host_os = detect_host_os()
|
|
155
|
+
import platform as _plat
|
|
156
|
+
arch = "amd64" if _plat.machine() in ("x86_64", "AMD64") else "arm64"
|
|
157
|
+
script_content = f"""
|
|
158
|
+
export CLM_ROOT="{clm_root}"
|
|
159
|
+
export CLM_RUNNER="rust"
|
|
160
|
+
export PATH="$CLM_ROOT/.venv/Scripts:$CLM_ROOT/.venv/bin:$CLM_ROOT/kernel/bin/{host_os}-{arch}:$CLM_ROOT/kernel/scripts:$PATH"
|
|
161
|
+
clm_root() {{ echo "$CLM_ROOT"; }}
|
|
162
|
+
export -f clm_root
|
|
163
|
+
|
|
164
|
+
# Intercept exit to prevent bootstrap scripts from terminating the shell
|
|
165
|
+
exit() {{ return "${{1:-0}}"; }}
|
|
166
|
+
|
|
167
|
+
while IFS= read -r f; do
|
|
168
|
+
if [[ "$f" != *"clmEval.sh"* && "$f" != *"main.sh"* && "$f" != *"evaluator.sh"* && "$f" != *"install_vs_buildtools.sh"* && "$f" != *"patch_mcard_venv.sh"* ]]; then
|
|
169
|
+
source "$f" 2>/dev/null || true
|
|
170
|
+
fi
|
|
171
|
+
done < <(find "$CLM_ROOT/computable_knowledge/Concrete/layer5_system/bootstrap" -name "node_modules" -prune -o -name "*.sh" -print)
|
|
172
|
+
|
|
173
|
+
unset -f exit
|
|
174
|
+
|
|
175
|
+
source "{script_path}" && {test_func}
|
|
176
|
+
"""
|
|
177
|
+
rust_exe = _resolve_rust_binary(clm_root)
|
|
178
|
+
if rust_exe:
|
|
179
|
+
import json as _json
|
|
180
|
+
script_input = {
|
|
181
|
+
"runtime": "shell",
|
|
182
|
+
"script": script_content,
|
|
183
|
+
"env": dict(os.environ),
|
|
184
|
+
"entry_point": "",
|
|
185
|
+
"cargo_test": "",
|
|
186
|
+
"args": [],
|
|
187
|
+
"clm_root": clm_root,
|
|
188
|
+
}
|
|
189
|
+
result = _call_rust_binary(rust_exe, ["exec-runtime-script"], env=None, stdin_data=_json.dumps(script_input))
|
|
190
|
+
if result[0] == 0:
|
|
191
|
+
try:
|
|
192
|
+
output = _json.loads(result[1])
|
|
193
|
+
return output.get("exit_code", 1)
|
|
194
|
+
except Exception:
|
|
195
|
+
pass
|
|
196
|
+
return result[0]
|
|
197
|
+
proc = _sp.Popen([get_bash_command(), "-c", script_content])
|
|
198
|
+
proc.wait()
|
|
199
|
+
return proc.returncode
|
|
200
|
+
|
|
201
|
+
def _extract_ctx(clm_root: str, runtime: str, script_content: str, inputs: dict[str, Any], entry_point: str, cargo_test: str, a_hash: str, c_hash: str) -> CLMContext:
|
|
202
|
+
return CLMContext.create_default(clm_root)
|
|
203
|
+
|
|
204
|
+
def _extract_meta(clm_root: str, runtime: str, script_content: str, inputs: dict[str, Any], entry_point: str, cargo_test: str, a_hash: str, c_hash: str) -> dict[str, Any]:
|
|
205
|
+
from clm.layer0.utils import clm_hash_string
|
|
206
|
+
return {
|
|
207
|
+
"operation": f"polyglot_execution_{runtime}",
|
|
208
|
+
"runtime": runtime,
|
|
209
|
+
"script_hash": clm_hash_string(script_content),
|
|
210
|
+
"input_place_hashes": [],
|
|
211
|
+
"agent_did": os.environ.get("ACTIVE_AGENT_DID", "did:clm:bootstrap"),
|
|
212
|
+
"sponsor_did": ""
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@vcard_sandwich(extract_ctx_func=_extract_ctx, extract_meta_func=_extract_meta)
|
|
216
|
+
def _polyglot_runtime_execute(clm_root: str, runtime: str, script_content: str, inputs: dict[str, Any], entry_point: str, cargo_test: str, a_hash: str, c_hash: str) -> tuple[int, str, str]:
|
|
217
|
+
run_status = 0
|
|
218
|
+
stdout_data = ""
|
|
219
|
+
stderr_data = ""
|
|
220
|
+
|
|
221
|
+
env = os.environ.copy()
|
|
222
|
+
for k, v in inputs.items():
|
|
223
|
+
env[k] = str(v)
|
|
224
|
+
|
|
225
|
+
args = [str(v) for v in inputs.values()]
|
|
226
|
+
|
|
227
|
+
rust_exe = _resolve_rust_binary(clm_root)
|
|
228
|
+
if rust_exe and runtime in ("shell", "python", "node", "rust"):
|
|
229
|
+
import json as _json
|
|
230
|
+
script_input = {
|
|
231
|
+
"runtime": runtime,
|
|
232
|
+
"script": script_content,
|
|
233
|
+
"env": {k: str(v) for k, v in env.items()},
|
|
234
|
+
"entry_point": entry_point or "",
|
|
235
|
+
"cargo_test": cargo_test or "",
|
|
236
|
+
"args": args,
|
|
237
|
+
"clm_root": clm_root,
|
|
238
|
+
}
|
|
239
|
+
result = _call_rust_binary(rust_exe, ["exec-runtime-script"], env=None, stdin_data=_json.dumps(script_input))
|
|
240
|
+
if result[0] == 0:
|
|
241
|
+
try:
|
|
242
|
+
output = _json.loads(result[1])
|
|
243
|
+
return output.get("exit_code", 1), output.get("stdout", ""), output.get("stderr", "")
|
|
244
|
+
except Exception:
|
|
245
|
+
pass
|
|
246
|
+
return result[0], result[1], result[2]
|
|
247
|
+
|
|
248
|
+
if runtime == "shell":
|
|
249
|
+
body = script_content
|
|
250
|
+
if entry_point:
|
|
251
|
+
body += f"\n\nif type {entry_point} &>/dev/null; then\n {entry_point} " + " ".join([f'"{a}"' for a in args]) + "\nfi\n"
|
|
252
|
+
|
|
253
|
+
proc = _sp.Popen([get_bash_command(), "-c", body], stdout=_sp.PIPE, stderr=_sp.PIPE, text=True, encoding="utf-8", env=env)
|
|
254
|
+
stdout_data, stderr_data = proc.communicate()
|
|
255
|
+
run_status = proc.returncode
|
|
256
|
+
elif runtime == "python":
|
|
257
|
+
proc = _sp.Popen([sys.executable, "-c", script_content] + args, stdout=_sp.PIPE, stderr=_sp.PIPE, text=True, encoding="utf-8", env=env)
|
|
258
|
+
stdout_data, stderr_data = proc.communicate()
|
|
259
|
+
run_status = proc.returncode
|
|
260
|
+
elif runtime == "node":
|
|
261
|
+
proc = _sp.Popen(["node", "-e", script_content] + args, stdout=_sp.PIPE, stderr=_sp.PIPE, text=True, encoding="utf-8", env=env)
|
|
262
|
+
stdout_data, stderr_data = proc.communicate()
|
|
263
|
+
run_status = proc.returncode
|
|
264
|
+
elif runtime == "rust":
|
|
265
|
+
if cargo_test:
|
|
266
|
+
pwd_orig = os.getcwd()
|
|
267
|
+
try:
|
|
268
|
+
os.chdir(os.path.join(clm_root, "kernel/clm_rust_core"))
|
|
269
|
+
proc = _sp.Popen(["./target/release/clm_rust_core", "run-test", cargo_test], stdout=_sp.PIPE, stderr=_sp.PIPE, text=True, encoding="utf-8", env=env)
|
|
270
|
+
stdout_data, stderr_data = proc.communicate()
|
|
271
|
+
run_status = proc.returncode
|
|
272
|
+
except Exception:
|
|
273
|
+
cmd = ["./target/debug/clm_rust_core", "run-test", cargo_test]
|
|
274
|
+
if not os.path.exists(cmd[0]):
|
|
275
|
+
cmd = ["cargo", "test", "--manifest-path", "Cargo.toml", "--", cargo_test]
|
|
276
|
+
proc = _sp.Popen(cmd, stdout=_sp.PIPE, stderr=_sp.PIPE, text=True, encoding="utf-8", env=env)
|
|
277
|
+
stdout_data, stderr_data = proc.communicate()
|
|
278
|
+
run_status = proc.returncode
|
|
279
|
+
finally:
|
|
280
|
+
os.chdir(pwd_orig)
|
|
281
|
+
else:
|
|
282
|
+
import tempfile
|
|
283
|
+
temp_dir = tempfile.mkdtemp()
|
|
284
|
+
src_file = os.path.join(temp_dir, "main.rs")
|
|
285
|
+
bin_file = os.path.join(temp_dir, "app.exe" if sys.platform == "win32" else "app")
|
|
286
|
+
if "fn main" not in script_content:
|
|
287
|
+
wrapped_content = "use std::io::{self, Read};\nfn main() {\n" + script_content + "\n}\n"
|
|
288
|
+
else:
|
|
289
|
+
wrapped_content = script_content
|
|
290
|
+
with open(src_file, "w", encoding="utf-8") as fh:
|
|
291
|
+
fh.write(wrapped_content)
|
|
292
|
+
try:
|
|
293
|
+
compile_proc = _sp.Popen(["rustc", "-O", "-o", bin_file, src_file], stdout=_sp.PIPE, stderr=_sp.PIPE, text=True, encoding="utf-8")
|
|
294
|
+
compile_out, compile_err = compile_proc.communicate()
|
|
295
|
+
if compile_proc.returncode != 0:
|
|
296
|
+
if "linking with `link.exe` failed" in compile_err or "link: extra operand" in compile_err:
|
|
297
|
+
_logger.warning(f"[PAL:polyglot] ⚠️ Rust compilation skipped (linker unavailable): {compile_err.strip()}")
|
|
298
|
+
return 0, "", "skipped: rustc linker unavailable"
|
|
299
|
+
_logger.error(f"[PAL:polyglot] ❌ Rust compilation failed:\n{compile_err}")
|
|
300
|
+
return 1, "", compile_err
|
|
301
|
+
proc = _sp.Popen([bin_file] + args, stdout=_sp.PIPE, stderr=_sp.PIPE, text=True, encoding="utf-8", env=env)
|
|
302
|
+
stdout_data, stderr_data = proc.communicate()
|
|
303
|
+
run_status = proc.returncode
|
|
304
|
+
finally:
|
|
305
|
+
import shutil
|
|
306
|
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
307
|
+
|
|
308
|
+
return run_status, stdout_data, stderr_data
|
|
309
|
+
def evaluate_polyglot(clm_root: str, clm_file: str, yaml_data: dict[str, Any], extra_args: list[str] | None) -> int:
|
|
310
|
+
"""
|
|
311
|
+
Evaluates a polyglot CLM process, executing it in the specified target runtimes (e.g. Python, Rust, Node).
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
clm_root (str): The root directory of the CLM workspace.
|
|
315
|
+
clm_file (str): The path to the CLM PCard.
|
|
316
|
+
yaml_data (Dict[str, Any]): The parsed manifest data.
|
|
317
|
+
extra_args (Optional[List[str]]): Additional command-line arguments.
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
int: The overall exit code from execution.
|
|
321
|
+
"""
|
|
322
|
+
inner = yaml_data.get("clm", yaml_data)
|
|
323
|
+
concrete = inner.get("concrete_impl", {})
|
|
324
|
+
process = concrete.get("process", {})
|
|
325
|
+
entry_point = process.get("entry_point") or concrete.get("operation")
|
|
326
|
+
|
|
327
|
+
balanced_exp = inner.get("balanced_exp", {})
|
|
328
|
+
polyglot_cases = balanced_exp.get("polyglot_cases", [])
|
|
329
|
+
|
|
330
|
+
case_name = None
|
|
331
|
+
if extra_args:
|
|
332
|
+
for arg in extra_args:
|
|
333
|
+
for case in polyglot_cases:
|
|
334
|
+
if case.get("name") == arg:
|
|
335
|
+
case_name = arg
|
|
336
|
+
break
|
|
337
|
+
if case_name:
|
|
338
|
+
break
|
|
339
|
+
|
|
340
|
+
if not case_name and polyglot_cases:
|
|
341
|
+
case_name = polyglot_cases[0].get("name")
|
|
342
|
+
|
|
343
|
+
case_dict = None
|
|
344
|
+
for case in polyglot_cases:
|
|
345
|
+
if case.get("name") == case_name:
|
|
346
|
+
case_dict = case
|
|
347
|
+
break
|
|
348
|
+
|
|
349
|
+
if not case_dict:
|
|
350
|
+
_logger.error(f"[PAL:polyglot] ❌ No case found for name '{case_name}' in: {clm_file}")
|
|
351
|
+
return 1
|
|
352
|
+
|
|
353
|
+
given = case_dict.get("given", {})
|
|
354
|
+
runtimes = given.get("runtimes", [])
|
|
355
|
+
if not runtimes:
|
|
356
|
+
_logger.error("[PAL:polyglot] ❌ No runtimes specified in Gherkin cover")
|
|
357
|
+
return 1
|
|
358
|
+
|
|
359
|
+
inputs = {k: v for k, v in given.items() if k not in ("runtimes", "requires")}
|
|
360
|
+
a_hash, c_hash = resolve_active_hashes_py(clm_file)
|
|
361
|
+
|
|
362
|
+
env_runtime = os.environ.get("CLM_POLYGLOT_RUNTIME")
|
|
363
|
+
active_runtimes = [env_runtime] if env_runtime else runtimes
|
|
364
|
+
|
|
365
|
+
executed_runtimes = []
|
|
366
|
+
runtime_outputs = []
|
|
367
|
+
runtime_exit_codes = []
|
|
368
|
+
runtime_exec_hashes = []
|
|
369
|
+
|
|
370
|
+
for runtime in active_runtimes:
|
|
371
|
+
if runtime not in runtimes:
|
|
372
|
+
_logger.info(f"[PAL:polyglot] ⏭️ Target runtime '{runtime}' not requested in Gherkin cover: {runtimes}")
|
|
373
|
+
continue
|
|
374
|
+
|
|
375
|
+
if runtime not in ("shell", "python", "rust", "node", "channel", "wasm", "javascript-browser", "llm"):
|
|
376
|
+
if env_runtime:
|
|
377
|
+
_logger.error(f"[PAL:polyglot] ❌ Target runtime '{runtime}' is not supported")
|
|
378
|
+
return 1
|
|
379
|
+
else:
|
|
380
|
+
_logger.info(f"[PAL:polyglot] ⏭️ Skipping unsupported runtime '{runtime}' in cover")
|
|
381
|
+
continue
|
|
382
|
+
|
|
383
|
+
requires = given.get("requires", {})
|
|
384
|
+
req_guard = requires.get(runtime)
|
|
385
|
+
if req_guard and not check_precondition_py(req_guard):
|
|
386
|
+
_logger.info(f"[PAL:polyglot] ⏭️ Pruning runtime '{runtime}' (precondition not met: {req_guard})")
|
|
387
|
+
continue
|
|
388
|
+
|
|
389
|
+
impls = process.get("implementations", {})
|
|
390
|
+
rt_impl = impls.get(runtime, {})
|
|
391
|
+
script_content = rt_impl.get("script", "")
|
|
392
|
+
script_handle = rt_impl.get("script_handle", "")
|
|
393
|
+
cargo_test = rt_impl.get("cargo_test", "")
|
|
394
|
+
|
|
395
|
+
if not script_content:
|
|
396
|
+
if script_handle and script_handle.startswith("script:"):
|
|
397
|
+
target = "clm.layer2.storage"
|
|
398
|
+
mod = sys.modules.get(target)
|
|
399
|
+
if mod is None:
|
|
400
|
+
__import__(target)
|
|
401
|
+
mod = sys.modules.get(target)
|
|
402
|
+
script_content = mod.resolve_handle_content(clm_root, script_handle) if mod else ""
|
|
403
|
+
elif cargo_test and runtime == "rust":
|
|
404
|
+
script_content = "CARGO_TEST_EXECUTION"
|
|
405
|
+
|
|
406
|
+
if not script_content:
|
|
407
|
+
if script_handle:
|
|
408
|
+
print(yaml.dump({
|
|
409
|
+
"type": "meta/content_missing",
|
|
410
|
+
"handle": script_handle,
|
|
411
|
+
"medium_hint": "db",
|
|
412
|
+
"uri": f"db://content_memory/{script_handle}"
|
|
413
|
+
}))
|
|
414
|
+
return 2
|
|
415
|
+
else:
|
|
416
|
+
_logger.error(f"[PAL:polyglot] ❌ No script or cargo_test implementation found for runtime '{runtime}' in: {clm_file}")
|
|
417
|
+
return 1
|
|
418
|
+
|
|
419
|
+
run_status, stdout_data, stderr_data = _polyglot_runtime_execute(clm_root, runtime, script_content, inputs, entry_point, cargo_test, a_hash or "", c_hash or "")
|
|
420
|
+
|
|
421
|
+
if stderr_data:
|
|
422
|
+
sys.stderr.write(stderr_data)
|
|
423
|
+
|
|
424
|
+
inputs_json_str = json.dumps(inputs, indent=2)
|
|
425
|
+
exec_hash_input = f"inputs: {inputs_json_str} | outputs: {stdout_data} | exit_code: {run_status} | runtime_facts: {os.environ.get('CLM_RUNTIME_FACTS', '')}"
|
|
426
|
+
exec_hash = clm_hash_string(exec_hash_input)
|
|
427
|
+
|
|
428
|
+
executed_runtimes.append(runtime)
|
|
429
|
+
runtime_outputs.append(stdout_data)
|
|
430
|
+
runtime_exit_codes.append(run_status)
|
|
431
|
+
runtime_exec_hashes.append(exec_hash)
|
|
432
|
+
|
|
433
|
+
if not executed_runtimes:
|
|
434
|
+
|
|
435
|
+
_logger.error("[PAL:polyglot] ❌ No runtimes were successfully executed.")
|
|
436
|
+
return 1
|
|
437
|
+
|
|
438
|
+
first_out = runtime_outputs[0]
|
|
439
|
+
first_code = runtime_exit_codes[0]
|
|
440
|
+
first_norm = normalize_output_py(first_out)
|
|
441
|
+
|
|
442
|
+
parity_failed = False
|
|
443
|
+
mismatch_rt = ""
|
|
444
|
+
mismatch_out = ""
|
|
445
|
+
|
|
446
|
+
for i in range(1, len(executed_runtimes)):
|
|
447
|
+
r_name = executed_runtimes[i]
|
|
448
|
+
r_out = runtime_outputs[i]
|
|
449
|
+
r_code = runtime_exit_codes[i]
|
|
450
|
+
r_norm = normalize_output_py(r_out)
|
|
451
|
+
|
|
452
|
+
if r_code != first_code:
|
|
453
|
+
parity_failed = True
|
|
454
|
+
mismatch_rt = r_name
|
|
455
|
+
mismatch_out = f"Exit code mismatch: {executed_runtimes[0]}={first_code} vs {r_name}={r_code}"
|
|
456
|
+
break
|
|
457
|
+
if r_norm != first_norm:
|
|
458
|
+
parity_failed = True
|
|
459
|
+
mismatch_rt = r_name
|
|
460
|
+
mismatch_out = r_out
|
|
461
|
+
break
|
|
462
|
+
|
|
463
|
+
if parity_failed:
|
|
464
|
+
_logger.info("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓")
|
|
465
|
+
_logger.info("┃ COHOMOLOGICAL OBSTRUCTION: Cross-Runtime Parity Fail ┃")
|
|
466
|
+
_logger.info("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛")
|
|
467
|
+
_logger.info(f" Divergence detected between '{executed_runtimes[0]}' and '{mismatch_rt}'!")
|
|
468
|
+
_logger.info(" -------------------------------------------------")
|
|
469
|
+
_logger.info(f" Output of '{executed_runtimes[0]}':")
|
|
470
|
+
_logger.info(first_out)
|
|
471
|
+
_logger.info(f" Output of '{mismatch_rt}':")
|
|
472
|
+
_logger.info(mismatch_out)
|
|
473
|
+
_logger.info(" -------------------------------------------------")
|
|
474
|
+
|
|
475
|
+
import difflib
|
|
476
|
+
diff_lines = list(difflib.unified_diff(
|
|
477
|
+
first_norm.splitlines(keepends=True),
|
|
478
|
+
normalize_output_py(mismatch_out).splitlines(keepends=True),
|
|
479
|
+
fromfile=f"norm_{executed_runtimes[0]}",
|
|
480
|
+
tofile=f"norm_{mismatch_rt}"
|
|
481
|
+
))
|
|
482
|
+
sys.stderr.writelines(diff_lines)
|
|
483
|
+
return 1
|
|
484
|
+
|
|
485
|
+
if len(executed_runtimes) > 1:
|
|
486
|
+
sorted_hashes = sorted(runtime_exec_hashes)
|
|
487
|
+
fold_input = "".join(sorted_hashes)
|
|
488
|
+
parity_hash = clm_hash_string(fold_input)
|
|
489
|
+
|
|
490
|
+
runtimes_str = ", ".join([f'"{r}"' for r in executed_runtimes])
|
|
491
|
+
extra_parity = f'parity_hash: "{parity_hash}"\nruntimes: [{runtimes_str}]'
|
|
492
|
+
parity_file = emit_exec_mcard_py(clm_root, "polyglot_parity", parity_hash, extra_parity, a_hash or "", c_hash or "")
|
|
493
|
+
if parity_file:
|
|
494
|
+
_logger.info(f"[PAL:polyglot] ✅ Parity verified. parity_hash = {parity_hash} ({parity_file})")
|
|
495
|
+
|
|
496
|
+
print(first_out, end="")
|
|
497
|
+
return first_code
|
|
498
|
+
|
|
499
|
+
def evaluate_compose(clm_root: str, clm_file: str, block: dict[str, Any], extra_args: list[str] | None) -> int:
|
|
500
|
+
"""
|
|
501
|
+
Evaluates a composite operation, evaluating step by step sequentially or otherwise.
|
|
502
|
+
|
|
503
|
+
Args:
|
|
504
|
+
clm_root (str): The root directory of the CLM workspace.
|
|
505
|
+
clm_file (str): The path to the parent CLM PCard.
|
|
506
|
+
block (Dict[str, Any]): The process block declaring steps.
|
|
507
|
+
extra_args (Optional[List[str]]): Additional execution arguments.
|
|
508
|
+
|
|
509
|
+
Returns:
|
|
510
|
+
int: The exit code (0 if all steps succeed).
|
|
511
|
+
"""
|
|
512
|
+
load_normalized_manifest_fn = get_load_manifest()
|
|
513
|
+
_logger.info("[PAL] Dispatching to compose runtime adapter...")
|
|
514
|
+
compose_mode = block.get("compose_mode", "sequential")
|
|
515
|
+
steps = block.get("steps", [])
|
|
516
|
+
|
|
517
|
+
if not steps:
|
|
518
|
+
print("[COMPOSE_FN] No steps declared — identity (no-op)")
|
|
519
|
+
return 0
|
|
520
|
+
|
|
521
|
+
print(f"[COMPOSE_FN] Mode: {compose_mode} | Steps: {len(steps)}")
|
|
522
|
+
|
|
523
|
+
# Lazy import evaluate_cmd dynamically to prevent circular dependencies
|
|
524
|
+
from clm.layer1.eval_callback import evaluate_or_fail
|
|
525
|
+
|
|
526
|
+
for i, step_ref in enumerate(steps):
|
|
527
|
+
step_file = resolve_clm_path(clm_root, step_ref)
|
|
528
|
+
if not step_file or not os.path.exists(step_file):
|
|
529
|
+
_logger.error(f"[COMPOSE_FN] Step {i+1}: failed to load '{step_ref}'")
|
|
530
|
+
return 1
|
|
531
|
+
|
|
532
|
+
try:
|
|
533
|
+
step_data = load_normalized_manifest_fn(clm_root, step_file)
|
|
534
|
+
inner_step = step_data.get("clm", step_data)
|
|
535
|
+
step_op = inner_step.get("concrete_impl", {}).get("operation", "unknown")
|
|
536
|
+
except Exception:
|
|
537
|
+
step_op = "unknown"
|
|
538
|
+
|
|
539
|
+
print(f"[COMPOSE_FN] Step {i+1}: {step_op} (from {step_ref})")
|
|
540
|
+
|
|
541
|
+
rc = evaluate_or_fail(clm_root, step_file, extra_args)
|
|
542
|
+
if rc != 0:
|
|
543
|
+
return rc
|
|
544
|
+
|
|
545
|
+
return 0
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
# ---------------------------------------------------------------------------
|
|
549
|
+
# Sprint 130.1 — Dynamic Triad Runner
|
|
550
|
+
# ---------------------------------------------------------------------------
|
|
551
|
+
|
|
552
|
+
def evaluate_triad(clm_root: str, clm_file: str, block: dict[str, Any], extra_args: list[str] | None) -> int:
|
|
553
|
+
"""Evaluate a Model Card Triad (Abstract, Concrete, Balanced) sequentially.
|
|
554
|
+
|
|
555
|
+
1. Loads the Abstract face (Face A) -> computes content hash
|
|
556
|
+
2. Loads the Concrete face (Face C) -> computes content hash
|
|
557
|
+
3. Injects A and C hashes into env vars for CelStore to capture
|
|
558
|
+
4. Evaluates the Balanced face (Face B) under this enriched context
|
|
559
|
+
5. Cleans up triad env vars to prevent cross-stage contamination
|
|
560
|
+
|
|
561
|
+
Uses CLMLogger with structured fields for cross-runtime traceability.
|
|
562
|
+
"""
|
|
563
|
+
# Lazy import via callback registry to avoid Layer 1→3 upward dependency
|
|
564
|
+
from clm.layer1.eval_callback import evaluate_or_fail
|
|
565
|
+
|
|
566
|
+
stage = block.get("stage")
|
|
567
|
+
name = block.get("name")
|
|
568
|
+
operation = f"stage{stage}_{name}"
|
|
569
|
+
|
|
570
|
+
_logger.info("Triad validation starting", op=operation)
|
|
571
|
+
|
|
572
|
+
# 1. Resolve paths to A, C, and B faces
|
|
573
|
+
import yaml
|
|
574
|
+
layer = "0"
|
|
575
|
+
try:
|
|
576
|
+
with open(clm_file, "r") as f:
|
|
577
|
+
data = yaml.safe_load(f)
|
|
578
|
+
layer = str(data.get("clm", {}).get("layer", "0"))
|
|
579
|
+
except Exception:
|
|
580
|
+
# fallback to parsing path
|
|
581
|
+
for l in ("0", "1", "2", "3", "4"):
|
|
582
|
+
if f"layer{l}" in clm_file:
|
|
583
|
+
layer = l
|
|
584
|
+
break
|
|
585
|
+
|
|
586
|
+
abstract_path = resolve_clm_path(clm_root, f"computable_knowledge/Abstract/layer{layer}/stage{stage}_{name}.yaml")
|
|
587
|
+
concrete_path = resolve_clm_path(clm_root, f"computable_knowledge/Concrete/layer{layer}/stage{stage}_{name}.yaml")
|
|
588
|
+
balanced_path = resolve_clm_path(clm_root, f"computable_knowledge/Balanced/layer{layer}/stage{stage}_{name}.yaml")
|
|
589
|
+
|
|
590
|
+
if not abstract_path or not os.path.exists(abstract_path):
|
|
591
|
+
_logger.error(f"Triad Face A not found: stage{stage}_{name}", op=operation)
|
|
592
|
+
return 1
|
|
593
|
+
if not concrete_path or not os.path.exists(concrete_path):
|
|
594
|
+
_logger.error(f"Triad Face C not found: stage{stage}_{name}", op=operation)
|
|
595
|
+
return 1
|
|
596
|
+
if not balanced_path or not os.path.exists(balanced_path):
|
|
597
|
+
_logger.error(f"Triad Face B not found: stage{stage}_{name}", op=operation)
|
|
598
|
+
return 1
|
|
599
|
+
|
|
600
|
+
# 2. Evaluate Abstract and Concrete (computes hashes and registers in DB)
|
|
601
|
+
rc = evaluate_or_fail(clm_root, abstract_path, extra_args)
|
|
602
|
+
if rc != 0:
|
|
603
|
+
_logger.error("Triad Face A (Abstract) failed", op=operation)
|
|
604
|
+
return rc
|
|
605
|
+
|
|
606
|
+
rc = evaluate_or_fail(clm_root, concrete_path, extra_args)
|
|
607
|
+
if rc != 0:
|
|
608
|
+
_logger.error("Triad Face C (Concrete) failed", op=operation)
|
|
609
|
+
return rc
|
|
610
|
+
|
|
611
|
+
# 3. Compute hashes for Triadic Coherence
|
|
612
|
+
a_hash = clm_hash_file(abstract_path)
|
|
613
|
+
c_hash = clm_hash_file(concrete_path)
|
|
614
|
+
|
|
615
|
+
_logger.info("Triad hashes computed", op=operation, pcard_hash=a_hash)
|
|
616
|
+
|
|
617
|
+
# 4. Inject hashes into env vars for CelStore to capture during Face B
|
|
618
|
+
os.environ["CLM_TRIAD_ABSTRACT_HASH"] = a_hash
|
|
619
|
+
os.environ["CLM_TRIAD_CONCRETE_HASH"] = c_hash
|
|
620
|
+
|
|
621
|
+
# 5. Evaluate Balanced Face
|
|
622
|
+
rc = evaluate_or_fail(clm_root, balanced_path, extra_args)
|
|
623
|
+
if rc == 0:
|
|
624
|
+
_logger.info("Triad validation passed", op=operation)
|
|
625
|
+
else:
|
|
626
|
+
_logger.error("Triad Face B (Balanced) failed", op=operation)
|
|
627
|
+
|
|
628
|
+
# 6. Clean up triad env vars to prevent cross-stage contamination
|
|
629
|
+
os.environ.pop("CLM_TRIAD_ABSTRACT_HASH", None)
|
|
630
|
+
os.environ.pop("CLM_TRIAD_CONCRETE_HASH", None)
|
|
631
|
+
|
|
632
|
+
return rc
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
# ---------------------------------------------------------------------------
|
|
636
|
+
# Sprint 130.4 — Monadic Pipeline Chaining
|
|
637
|
+
# ---------------------------------------------------------------------------
|
|
638
|
+
|
|
639
|
+
def evaluate_triad_pipeline(clm_root: str, clm_file: str, block: dict[str, Any], extra_args: list[str] | None) -> int:
|
|
640
|
+
"""Chain multiple triad stages via CelStore.bind() (monadic >>=).
|
|
641
|
+
|
|
642
|
+
Each stage's output state token becomes the next stage's precondition
|
|
643
|
+
input. After each stage, flush_action_log() persists the action_log
|
|
644
|
+
to execution_log.db, making the Flux event store durable.
|
|
645
|
+
"""
|
|
646
|
+
from types import SimpleNamespace
|
|
647
|
+
|
|
648
|
+
from clm.cross_cutting.cel_store import CelStore, EnvSlice, StateSlice
|
|
649
|
+
from clm.layer0.utils import clm_hash_string
|
|
650
|
+
|
|
651
|
+
stages = block.get("stages", [])
|
|
652
|
+
if not stages:
|
|
653
|
+
_logger.error("No stages defined in triad_pipeline")
|
|
654
|
+
return 1
|
|
655
|
+
|
|
656
|
+
# Detect layer name dynamically
|
|
657
|
+
layer_name = "layer0"
|
|
658
|
+
try:
|
|
659
|
+
import yaml
|
|
660
|
+
with open(clm_file, "r") as f:
|
|
661
|
+
data = yaml.safe_load(f)
|
|
662
|
+
layer_val = data.get("clm", {}).get("layer", "0")
|
|
663
|
+
layer_name = f"layer{layer_val}"
|
|
664
|
+
except Exception:
|
|
665
|
+
for l in ("0", "1", "2", "3", "4"):
|
|
666
|
+
if f"layer{l}" in clm_file:
|
|
667
|
+
layer_name = f"layer{l}"
|
|
668
|
+
break
|
|
669
|
+
|
|
670
|
+
# Initialize monadic state with unit() — the "seed" store
|
|
671
|
+
pipeline_store = CelStore(
|
|
672
|
+
state=StateSlice(inputs={"pipeline": layer_name}),
|
|
673
|
+
env=EnvSlice(clm_root=clm_root, os=os),
|
|
674
|
+
)
|
|
675
|
+
pipeline_store = pipeline_store.unit({"pipeline": layer_name, "stage": 0})
|
|
676
|
+
|
|
677
|
+
overall_rc = 0
|
|
678
|
+
flush_ctx = SimpleNamespace(root=clm_root)
|
|
679
|
+
|
|
680
|
+
for stage_block in stages:
|
|
681
|
+
stage = stage_block["stage"]
|
|
682
|
+
name = stage_block["name"]
|
|
683
|
+
operation = f"stage{stage}_{name}"
|
|
684
|
+
|
|
685
|
+
_logger.info(f"Pipeline stage {stage} starting", op=operation)
|
|
686
|
+
|
|
687
|
+
def _run_stage(store: CelStore, prev_result: Any, _stage: str = stage, _name: str = name, _op: str = operation) -> tuple[CelStore, int]:
|
|
688
|
+
rc = evaluate_triad(clm_root, clm_file,
|
|
689
|
+
{"stage": _stage, "name": _name}, extra_args)
|
|
690
|
+
if rc != 0:
|
|
691
|
+
_logger.error(f"Pipeline stage {_stage} failed", op=_op)
|
|
692
|
+
return store, rc
|
|
693
|
+
|
|
694
|
+
# Capture this stage's output hash as the next stage's precondition
|
|
695
|
+
stage_output_hash = clm_hash_string(
|
|
696
|
+
f"{_op}:{prev_result}"
|
|
697
|
+
)
|
|
698
|
+
store.state.inputs[f"stage{_stage}_output_hash"] = stage_output_hash
|
|
699
|
+
|
|
700
|
+
# Flush action_log for this stage to execution_log.db
|
|
701
|
+
store.flush_action_log(flush_ctx)
|
|
702
|
+
|
|
703
|
+
_logger.info(f"Pipeline stage {_stage} completed", op=_op,
|
|
704
|
+
pcard_hash=stage_output_hash)
|
|
705
|
+
return store, 0
|
|
706
|
+
|
|
707
|
+
pipeline_store, stage_rc = pipeline_store.bind(_run_stage)
|
|
708
|
+
|
|
709
|
+
if stage_rc != 0:
|
|
710
|
+
overall_rc = stage_rc
|
|
711
|
+
break
|
|
712
|
+
|
|
713
|
+
if overall_rc == 0:
|
|
714
|
+
_logger.info("Layer 0 pipeline completed successfully")
|
|
715
|
+
else:
|
|
716
|
+
_logger.error(f"Layer 0 pipeline failed at stage {stage}")
|
|
717
|
+
|
|
718
|
+
return overall_rc
|