pgc-runtime 2.0.0__tar.gz → 2.0.1__tar.gz
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.
- {pgc_runtime-2.0.0/pgc_runtime.egg-info → pgc_runtime-2.0.1}/PKG-INFO +1 -1
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1/pgc_runtime.egg-info}/PKG-INFO +1 -1
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/pyproject.toml +1 -1
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/ct_executor.py +50 -2
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/dispatcher.py +119 -10
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/LICENSE +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/MANIFEST.in +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/NOTICE +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/README.md +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/pgc_runtime.egg-info/SOURCES.txt +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/pgc_runtime.egg-info/dependency_links.txt +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/pgc_runtime.egg-info/entry_points.txt +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/pgc_runtime.egg-info/requires.txt +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/pgc_runtime.egg-info/top_level.txt +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/__init__.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/api.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/boot.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/cli.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/conformance.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/ct_errors.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/ct_execute.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/evidence.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/examine/__init__.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/examine/classifier.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/examine/cli.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/examine/hint_engine.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/examine/locator.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/examine/parser.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/examine/reporter.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/loader.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/memory.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/scheduler.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/runtime/trace_viz.py +0 -0
- {pgc_runtime-2.0.0 → pgc_runtime-2.0.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pgc-runtime
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: PGC protocol runtime — executes a sealed snapshot as governed DAG traversal and emits traces (import package: runtime)
|
|
5
5
|
Author-email: Bhash Ganti <bachipeachy@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pgc-runtime
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: PGC protocol runtime — executes a sealed snapshot as governed DAG traversal and emits traces (import package: runtime)
|
|
5
5
|
Author-email: Bhash Ganti <bachipeachy@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pgc-runtime"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.1"
|
|
8
8
|
description = "PGC protocol runtime — executes a sealed snapshot as governed DAG traversal and emits traces (import package: runtime)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -17,6 +17,22 @@ class CTExecutionError(StructuredError):
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
class CTArtifactNotFound(StructuredError):
|
|
21
|
+
"""The sealed handler_ref names something that is not present.
|
|
22
|
+
|
|
23
|
+
Distinct from CT_EXECUTION_FAILED: nothing was executed and nothing could be. The snapshot
|
|
24
|
+
named a module or callable, and resolution of that name failed.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, message: str, cause: Exception | None = None):
|
|
28
|
+
super().__init__(
|
|
29
|
+
error_code="CT_ARTIFACT_NOT_FOUND",
|
|
30
|
+
node_category="CT",
|
|
31
|
+
message=message,
|
|
32
|
+
cause=cause,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
20
36
|
class CTExecutor:
|
|
21
37
|
def __init__(self):
|
|
22
38
|
pass
|
|
@@ -83,8 +99,40 @@ class CTExecutor:
|
|
|
83
99
|
if not module_path or not callable_name:
|
|
84
100
|
raise CTExecutionError(f"Incomplete handler_ref on step: {step.get('atom')}")
|
|
85
101
|
|
|
86
|
-
|
|
87
|
-
|
|
102
|
+
# Importing a sealed handler_ref is a resolution step, and it fails in two ways that mean
|
|
103
|
+
# different things. The module named by the snapshot may be absent — a closure failure. Or
|
|
104
|
+
# the module may be present and one of *its* imports absent, which is what happens when a
|
|
105
|
+
# domain's optional dependency is not installed. Neither may escape as a bare
|
|
106
|
+
# ModuleNotFoundError: an ungoverned crash is not a declared outcome.
|
|
107
|
+
try:
|
|
108
|
+
mod = importlib.import_module(module_path)
|
|
109
|
+
except ModuleNotFoundError as exc:
|
|
110
|
+
missing = exc.name or ""
|
|
111
|
+
if missing == module_path or module_path.startswith(missing + "."):
|
|
112
|
+
raise CTArtifactNotFound(
|
|
113
|
+
f"handler_ref names module {module_path!r} for atom "
|
|
114
|
+
f"{step.get('atom')!r} and it is not importable",
|
|
115
|
+
cause=exc,
|
|
116
|
+
) from exc
|
|
117
|
+
raise CTExecutionError(
|
|
118
|
+
f"handler_ref module {module_path!r} for atom {step.get('atom')!r} requires "
|
|
119
|
+
f"{missing!r}, which is not installed — the domain's optional dependency is "
|
|
120
|
+
f"missing, not the transform"
|
|
121
|
+
) from exc
|
|
122
|
+
except ImportError as exc:
|
|
123
|
+
raise CTExecutionError(
|
|
124
|
+
f"handler_ref module {module_path!r} for atom {step.get('atom')!r} "
|
|
125
|
+
f"failed to import: {exc}"
|
|
126
|
+
) from exc
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
execute_fn = getattr(mod, callable_name)
|
|
130
|
+
except AttributeError as exc:
|
|
131
|
+
raise CTArtifactNotFound(
|
|
132
|
+
f"handler_ref names callable {callable_name!r} in {module_path!r} for atom "
|
|
133
|
+
f"{step.get('atom')!r} and the module does not define it",
|
|
134
|
+
cause=exc,
|
|
135
|
+
) from exc
|
|
88
136
|
|
|
89
137
|
# Adapter logic (migrated from atom_registry._register_execute_atom):
|
|
90
138
|
# Resolve $.path references; skip reserved and metadata keys.
|
|
@@ -48,6 +48,41 @@ from typing import Any
|
|
|
48
48
|
from runtime.loader import RuntimePackage
|
|
49
49
|
from runtime.evidence import TraceWriter
|
|
50
50
|
from runtime.ct_execute import execute_ct
|
|
51
|
+
from runtime.ct_errors import StructuredError
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _violation_payload(exc: StructuredError) -> dict[str, Any]:
|
|
55
|
+
"""A structured refusal, rendered into the shape a step result carries.
|
|
56
|
+
|
|
57
|
+
Refusals reach the workflow as a VIOLATION result and route on it — the same channel the reach
|
|
58
|
+
refusal uses. An exception escaping the dispatcher would bypass routing and the trace both.
|
|
59
|
+
"""
|
|
60
|
+
return {
|
|
61
|
+
"result_status": "VIOLATION",
|
|
62
|
+
"refusal": exc.error_code,
|
|
63
|
+
"node_category": exc.node_category,
|
|
64
|
+
"message": str(exc),
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class CSExecutionError(StructuredError):
|
|
69
|
+
"""A CS step could not be executed.
|
|
70
|
+
|
|
71
|
+
`CS_EXECUTION_FAILED` is the only CS code the trace schema admits, so the distinction between
|
|
72
|
+
an absent handler, an absent callable, a missing optional dependency and a failing capability
|
|
73
|
+
is carried in the message rather than in a code this snapshot does not declare.
|
|
74
|
+
|
|
75
|
+
Distinct from a VIOLATION return: a violation is governance deciding no, and it routes through
|
|
76
|
+
the workflow. This is the environment being unable to run the step at all.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def __init__(self, message: str, cause: Exception | None = None):
|
|
80
|
+
super().__init__(
|
|
81
|
+
error_code="CS_EXECUTION_FAILED",
|
|
82
|
+
node_category="CS",
|
|
83
|
+
message=message,
|
|
84
|
+
cause=cause,
|
|
85
|
+
)
|
|
51
86
|
|
|
52
87
|
|
|
53
88
|
# ---------------------------------------------------------------------------
|
|
@@ -112,9 +147,14 @@ def execute_cc(
|
|
|
112
147
|
result_status, raw_result = _execute_ct_step(step_addr, resolved_inputs, pkg)
|
|
113
148
|
else:
|
|
114
149
|
# CS step — controlled side effect via declared handler
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
150
|
+
try:
|
|
151
|
+
result_status, raw_result = _execute_cs_step(
|
|
152
|
+
step_addr, op, resolved_inputs, rb_addr, pkg, data_root, wf_executor, wf_addr
|
|
153
|
+
)
|
|
154
|
+
except StructuredError as exc:
|
|
155
|
+
# Symmetry with the CT branch: a CS that cannot be loaded or that raises is a
|
|
156
|
+
# VIOLATION the workflow routes on, not a traceback the caller receives.
|
|
157
|
+
result_status, raw_result = "VIOLATION", _violation_payload(exc)
|
|
118
158
|
|
|
119
159
|
# Apply outputs mapping: {cc_field: "$.capability_result.<ct_field>"} → surface fragment
|
|
120
160
|
surface_fragment = _apply_outputs(outputs_spec, raw_result, step_results)
|
|
@@ -181,9 +221,19 @@ def _execute_ct_step(
|
|
|
181
221
|
try:
|
|
182
222
|
raw_result = execute_ct(ct_ir, resolved_inputs)
|
|
183
223
|
return "SUCCESS", (raw_result if isinstance(raw_result, dict) else {})
|
|
184
|
-
except
|
|
185
|
-
# CT
|
|
186
|
-
|
|
224
|
+
except StructuredError as exc:
|
|
225
|
+
# CT refusal → protocol VIOLATION, carrying what was refused. Returning a bare {} here
|
|
226
|
+
# discarded the only account of why the step failed, which left an operator with a status
|
|
227
|
+
# and no cause.
|
|
228
|
+
return "VIOLATION", _violation_payload(exc)
|
|
229
|
+
except Exception as exc:
|
|
230
|
+
# An unstructured exception from a transform is still a VIOLATION and still must not
|
|
231
|
+
# propagate, but it is named rather than swallowed.
|
|
232
|
+
return "VIOLATION", {
|
|
233
|
+
"result_status": "VIOLATION",
|
|
234
|
+
"refusal": "CT_EXECUTION_FAILED",
|
|
235
|
+
"message": f"{type(exc).__name__}: {exc}",
|
|
236
|
+
}
|
|
187
237
|
|
|
188
238
|
|
|
189
239
|
def _make_workflow_executor(
|
|
@@ -283,9 +333,57 @@ def _execute_cs_step(
|
|
|
283
333
|
cs_metadata = cs_entry.get("cs_metadata", {})
|
|
284
334
|
cs_fqdn = pkg.vocab.fqdn(cs_addr)
|
|
285
335
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
336
|
+
# Loading a sealed handler_ref runs code this package does not own. Every step of that —
|
|
337
|
+
# importing the module, finding the callable, constructing it — may raise, and none of it may
|
|
338
|
+
# escape as a bare ModuleNotFoundError or AttributeError. An ungoverned crash is not a declared
|
|
339
|
+
# outcome, and the trace cannot record what it never sees.
|
|
340
|
+
module_path = handler_ref.get("module")
|
|
341
|
+
callable_name = handler_ref.get("callable")
|
|
342
|
+
if not module_path or not callable_name:
|
|
343
|
+
raise CSExecutionError(
|
|
344
|
+
f"incomplete handler_ref for CS {cs_fqdn}: module={module_path!r} "
|
|
345
|
+
f"callable={callable_name!r}"
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
try:
|
|
349
|
+
mod = importlib.import_module(module_path)
|
|
350
|
+
except ModuleNotFoundError as exc:
|
|
351
|
+
missing = exc.name or ""
|
|
352
|
+
if missing == module_path or module_path.startswith(missing + "."):
|
|
353
|
+
raise CSExecutionError(
|
|
354
|
+
f"handler_ref names module {module_path!r} for CS {cs_fqdn} and it is not "
|
|
355
|
+
f"importable — the snapshot names an implementation this environment does not carry",
|
|
356
|
+
cause=exc,
|
|
357
|
+
) from exc
|
|
358
|
+
raise CSExecutionError(
|
|
359
|
+
f"handler_ref module {module_path!r} for CS {cs_fqdn} requires {missing!r}, which is "
|
|
360
|
+
f"not installed — the domain's optional dependency is missing, not the capability",
|
|
361
|
+
cause=exc,
|
|
362
|
+
) from exc
|
|
363
|
+
except ImportError as exc:
|
|
364
|
+
raise CSExecutionError(
|
|
365
|
+
f"handler_ref module {module_path!r} for CS {cs_fqdn} failed to import: {exc}",
|
|
366
|
+
cause=exc,
|
|
367
|
+
) from exc
|
|
368
|
+
|
|
369
|
+
try:
|
|
370
|
+
cls = getattr(mod, callable_name)
|
|
371
|
+
except AttributeError as exc:
|
|
372
|
+
raise CSExecutionError(
|
|
373
|
+
f"handler_ref names callable {callable_name!r} in {module_path!r} for CS {cs_fqdn} "
|
|
374
|
+
f"and the module does not define it",
|
|
375
|
+
cause=exc,
|
|
376
|
+
) from exc
|
|
377
|
+
|
|
378
|
+
try:
|
|
379
|
+
runtime = cls(config=policy, metadata=cs_metadata, capability_code=cs_fqdn)
|
|
380
|
+
except StructuredError:
|
|
381
|
+
raise
|
|
382
|
+
except Exception as exc:
|
|
383
|
+
raise CSExecutionError(
|
|
384
|
+
f"CS {cs_fqdn} ({module_path}.{callable_name}) raised while being constructed: {exc}",
|
|
385
|
+
cause=exc,
|
|
386
|
+
) from exc
|
|
289
387
|
|
|
290
388
|
# Translate __store__ (compiler-emitted entity tag) to __pgs_store_entity__ (CS protocol key)
|
|
291
389
|
store_entity = resolved_inputs.get("__store__")
|
|
@@ -293,7 +391,18 @@ def _execute_cs_step(
|
|
|
293
391
|
if store_entity:
|
|
294
392
|
cs_inputs["__pgs_store_entity__"] = store_entity
|
|
295
393
|
|
|
296
|
-
|
|
394
|
+
# The capability itself is external code. The CT path already wraps its atom call; this is the
|
|
395
|
+
# same boundary, and it was the one place a domain exception could still reach the caller
|
|
396
|
+
# unstructured.
|
|
397
|
+
try:
|
|
398
|
+
raw_result = runtime.execute(op=op, payload=cs_inputs)
|
|
399
|
+
except StructuredError:
|
|
400
|
+
raise
|
|
401
|
+
except Exception as exc:
|
|
402
|
+
raise CSExecutionError(
|
|
403
|
+
f"CS {cs_fqdn} raised during op {op!r}: {type(exc).__name__}: {exc}",
|
|
404
|
+
cause=exc,
|
|
405
|
+
) from exc
|
|
297
406
|
if not isinstance(raw_result, dict):
|
|
298
407
|
raw_result = {}
|
|
299
408
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|