rocket-engine 0.0.2b1__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.
- rocket_engine/__init__.py +8 -0
- rocket_engine/__main__.py +12 -0
- rocket_engine/adapters/README.md +54 -0
- rocket_engine/adapters/__init__.py +7 -0
- rocket_engine/adapters/api.py +39 -0
- rocket_engine/adapters/base.py +46 -0
- rocket_engine/adapters/cace/__init__.py +163 -0
- rocket_engine/adapters/circulax/README.md +10 -0
- rocket_engine/adapters/circulax/__init__.py +112 -0
- rocket_engine/adapters/circulax/_driver.py +190 -0
- rocket_engine/adapters/circulax/adapter.py +538 -0
- rocket_engine/adapters/circulax/results.py +291 -0
- rocket_engine/adapters/cli/README.md +34 -0
- rocket_engine/adapters/cli/__init__.py +305 -0
- rocket_engine/adapters/connectivity/__init__.py +196 -0
- rocket_engine/adapters/connectivity/results.py +214 -0
- rocket_engine/adapters/cosim/README.md +9 -0
- rocket_engine/adapters/cosim/__init__.py +1390 -0
- rocket_engine/adapters/cosim/results.py +214 -0
- rocket_engine/adapters/devsim/__init__.py +171 -0
- rocket_engine/adapters/digital_flow/README.md +9 -0
- rocket_engine/adapters/digital_flow/__init__.py +1121 -0
- rocket_engine/adapters/digital_flow/results.py +227 -0
- rocket_engine/adapters/digital_flow/state.py +462 -0
- rocket_engine/adapters/drc/README.klayout.md +7 -0
- rocket_engine/adapters/drc/README.md +7 -0
- rocket_engine/adapters/drc/__init__.py +1 -0
- rocket_engine/adapters/drc/klayout.py +952 -0
- rocket_engine/adapters/drc/magic.py +287 -0
- rocket_engine/adapters/drc/results.py +184 -0
- rocket_engine/adapters/drc/results_kl.py +188 -0
- rocket_engine/adapters/elmer/__init__.py +163 -0
- rocket_engine/adapters/envelope.py +120 -0
- rocket_engine/adapters/equivalence/__init__.py +156 -0
- rocket_engine/adapters/errors.py +181 -0
- rocket_engine/adapters/extract_magic/README.md +15 -0
- rocket_engine/adapters/extract_magic/__init__.py +425 -0
- rocket_engine/adapters/extract_magic/results.py +209 -0
- rocket_engine/adapters/formal_sby/README.md +7 -0
- rocket_engine/adapters/formal_sby/__init__.py +773 -0
- rocket_engine/adapters/formal_sby/formal_edge.py +195 -0
- rocket_engine/adapters/formal_sby/results.py +185 -0
- rocket_engine/adapters/gdsfactory/__init__.py +194 -0
- rocket_engine/adapters/gdsfactory/_driver.py +459 -0
- rocket_engine/adapters/gdsfactory/adapter.py +609 -0
- rocket_engine/adapters/gdsfactory/results.py +181 -0
- rocket_engine/adapters/hdl_sim/README.md +7 -0
- rocket_engine/adapters/hdl_sim/__init__.py +369 -0
- rocket_engine/adapters/hdl_sim/ghdl.py +155 -0
- rocket_engine/adapters/hdl_sim/results.py +178 -0
- rocket_engine/adapters/hdl_sim/verilator.py +167 -0
- rocket_engine/adapters/http/README.md +15 -0
- rocket_engine/adapters/http/__init__.py +458 -0
- rocket_engine/adapters/http/events.py +63 -0
- rocket_engine/adapters/ipc/README.md +9 -0
- rocket_engine/adapters/ipc/__init__.py +111 -0
- rocket_engine/adapters/lvs_netgen/README.md +20 -0
- rocket_engine/adapters/lvs_netgen/__init__.py +889 -0
- rocket_engine/adapters/lvs_netgen/results.py +168 -0
- rocket_engine/adapters/mcp/README.md +19 -0
- rocket_engine/adapters/mcp/__init__.py +85 -0
- rocket_engine/adapters/mcp/api-schema.json +6107 -0
- rocket_engine/adapters/mcp/pull.py +246 -0
- rocket_engine/adapters/mcp/server.py +794 -0
- rocket_engine/adapters/meep/__init__.py +167 -0
- rocket_engine/adapters/meow/README.md +7 -0
- rocket_engine/adapters/meow/__init__.py +190 -0
- rocket_engine/adapters/meow/_driver.py +227 -0
- rocket_engine/adapters/meow/_envelope.py +108 -0
- rocket_engine/adapters/meow/adapter.py +491 -0
- rocket_engine/adapters/meow/results.py +218 -0
- rocket_engine/adapters/mutation/__init__.py +192 -0
- rocket_engine/adapters/ngspice/README.md +28 -0
- rocket_engine/adapters/ngspice/__init__.py +627 -0
- rocket_engine/adapters/ngspice/results.py +215 -0
- rocket_engine/adapters/postlayout/README.md +28 -0
- rocket_engine/adapters/postlayout/__init__.py +17 -0
- rocket_engine/adapters/postlayout/adapter.py +1062 -0
- rocket_engine/adapters/postlayout/results.py +330 -0
- rocket_engine/adapters/postlayout/translate.py +71 -0
- rocket_engine/adapters/profile.py +220 -0
- rocket_engine/adapters/sax/README.md +23 -0
- rocket_engine/adapters/sax/__init__.py +516 -0
- rocket_engine/adapters/sax/_driver.py +148 -0
- rocket_engine/adapters/sax/results.py +291 -0
- rocket_engine/adapters/stdio_console.py +1151 -0
- rocket_engine/adapters/syntax/README.md +5 -0
- rocket_engine/adapters/syntax/__init__.py +366 -0
- rocket_engine/adapters/syntax/results.py +181 -0
- rocket_engine/adapters/synth_yosys/README.md +7 -0
- rocket_engine/adapters/synth_yosys/__init__.py +655 -0
- rocket_engine/adapters/synth_yosys/amaranth.py +120 -0
- rocket_engine/adapters/synth_yosys/ghdl.py +128 -0
- rocket_engine/adapters/synth_yosys/results.py +173 -0
- rocket_engine/adapters/timing_sta/README.md +9 -0
- rocket_engine/adapters/timing_sta/__init__.py +726 -0
- rocket_engine/adapters/view_sync/__init__.py +185 -0
- rocket_engine/adapters/view_sync/results.py +189 -0
- rocket_engine/adapters/vlsir/__init__.py +142 -0
- rocket_engine/adapters/xschem/__init__.py +440 -0
- rocket_engine/adapters/xschem/deck.py +266 -0
- rocket_engine/clients/__init__.py +5 -0
- rocket_engine/clients/runtime.py +255 -0
- rocket_engine/composition.py +2279 -0
- rocket_engine/execution/README.md +30 -0
- rocket_engine/execution/__init__.py +150 -0
- rocket_engine/execution/apig/__init__.py +1 -0
- rocket_engine/execution/apig/pool.py +463 -0
- rocket_engine/execution/apig/submit.py +124 -0
- rocket_engine/execution/block_runs_scope.py +479 -0
- rocket_engine/execution/coalesce.py +414 -0
- rocket_engine/execution/console/__init__.py +1 -0
- rocket_engine/execution/console/apply_session.py +318 -0
- rocket_engine/execution/console/lifecycle.py +265 -0
- rocket_engine/execution/dispatch.py +205 -0
- rocket_engine/execution/errors.py +31 -0
- rocket_engine/execution/ports.py +797 -0
- rocket_engine/execution/pyexec/__init__.py +1 -0
- rocket_engine/execution/pyexec/apply_context.py +547 -0
- rocket_engine/execution/pyexec/approvals.py +173 -0
- rocket_engine/execution/pyexec/runner.py +404 -0
- rocket_engine/execution/pyexec/support.py +464 -0
- rocket_engine/execution/python_exec.py +897 -0
- rocket_engine/execution/queue.py +85 -0
- rocket_engine/execution/replay_safe.py +601 -0
- rocket_engine/execution/routing/__init__.py +1 -0
- rocket_engine/execution/routing/calls.py +364 -0
- rocket_engine/execution/routing/namespace.py +785 -0
- rocket_engine/execution/routing/ports.py +102 -0
- rocket_engine/execution/routing/tools.py +346 -0
- rocket_engine/execution/runner.py +311 -0
- rocket_engine/execution/runtime.py +1149 -0
- rocket_engine/execution/service.py +279 -0
- rocket_engine/execution/worker.py +464 -0
- rocket_engine/interfaces/README.md +26 -0
- rocket_engine/interfaces/__init__.py +58 -0
- rocket_engine/interfaces/apig_assets.py +407 -0
- rocket_engine/interfaces/celllink.py +461 -0
- rocket_engine/interfaces/documents.py +92 -0
- rocket_engine/interfaces/envelopes.py +131 -0
- rocket_engine/interfaces/errors.py +16 -0
- rocket_engine/interfaces/layout.py +410 -0
- rocket_engine/interfaces/layout_schema.yaml +278 -0
- rocket_engine/interfaces/paths.py +223 -0
- rocket_engine/interfaces/pdks.py +550 -0
- rocket_engine/interfaces/ports.py +72 -0
- rocket_engine/interfaces/references.py +115 -0
- rocket_engine/interfaces/refs.py +85 -0
- rocket_engine/interfaces/runparams.py +304 -0
- rocket_engine/interfaces/setup.py +552 -0
- rocket_engine/interfaces/setup_catalogue.yaml +243 -0
- rocket_engine/interfaces/setup_probes.py +66 -0
- rocket_engine/interfaces/vocabulary.py +58 -0
- rocket_engine/interfaces/yaml_dump.py +31 -0
- rocket_engine/library/README.md +22 -0
- rocket_engine/library/__init__.py +13 -0
- rocket_engine/library/apig_catalog.py +371 -0
- rocket_engine/library/catalog.py +185 -0
- rocket_engine/library/errors.py +16 -0
- rocket_engine/mutate/__init__.py +776 -0
- rocket_engine/mutate/operators.py +700 -0
- rocket_engine/ops/__init__.py +1 -0
- rocket_engine/ops/deferred.py +279 -0
- rocket_engine/ops/editors.py +404 -0
- rocket_engine/ops/evidence.py +194 -0
- rocket_engine/ops/gates.py +262 -0
- rocket_engine/ops/ports.py +76 -0
- rocket_engine/ops/queries.py +417 -0
- rocket_engine/ops/runs.py +553 -0
- rocket_engine/ops/submit.py +614 -0
- rocket_engine/project/README.md +27 -0
- rocket_engine/project/__init__.py +6 -0
- rocket_engine/project/canvas/__init__.py +55 -0
- rocket_engine/project/canvas/compile.py +109 -0
- rocket_engine/project/canvas/integrate.py +48 -0
- rocket_engine/project/canvas/schema.py +241 -0
- rocket_engine/project/canvas/templates.py +46 -0
- rocket_engine/project/canvas/validate.py +603 -0
- rocket_engine/project/edit/__init__.py +5 -0
- rocket_engine/project/edit/cas.py +87 -0
- rocket_engine/project/edit/transactions.py +282 -0
- rocket_engine/project/errors.py +16 -0
- rocket_engine/project/frontend13.py +685 -0
- rocket_engine/project/geometry/__init__.py +23 -0
- rocket_engine/project/geometry/ops.py +451 -0
- rocket_engine/project/geometry/snap.py +103 -0
- rocket_engine/project/ip/__init__.py +1 -0
- rocket_engine/project/ip/blocks.py +195 -0
- rocket_engine/project/ip/entry.schema.json +78 -0
- rocket_engine/project/ip/lifecycle.py +402 -0
- rocket_engine/project/ip/verbs.py +123 -0
- rocket_engine/project/layers/__init__.py +6 -0
- rocket_engine/project/layers/bindings.py +115 -0
- rocket_engine/project/layers/catalog.py +228 -0
- rocket_engine/project/layers/presets.py +43 -0
- rocket_engine/project/ledger/__init__.py +1 -0
- rocket_engine/project/ledger/docs.py +167 -0
- rocket_engine/project/ledger/entities.py +176 -0
- rocket_engine/project/ledger/events.py +29 -0
- rocket_engine/project/ledger/runs.py +257 -0
- rocket_engine/project/ledger/shared.py +174 -0
- rocket_engine/project/ledger/snapshots.py +385 -0
- rocket_engine/project/ledger/wires.py +552 -0
- rocket_engine/project/process/__init__.py +14 -0
- rocket_engine/project/process/model.py +193 -0
- rocket_engine/project/process/recipes.py +121 -0
- rocket_engine/project/schematic/__init__.py +1 -0
- rocket_engine/project/schematic/hierarchy.py +312 -0
- rocket_engine/project/schematic/instances.py +393 -0
- rocket_engine/project/schematic/sheets.py +198 -0
- rocket_engine/project/service.py +2941 -0
- rocket_engine/project/symbols/__init__.py +1 -0
- rocket_engine/project/symbols/cells.py +324 -0
- rocket_engine/project/symbols/linkage.py +356 -0
- rocket_engine/project/symbols/symbols.py +352 -0
- rocket_engine/project/templates/__init__.py +303 -0
- rocket_engine/project/templates/errors.py +25 -0
- rocket_engine/project/testbench/__init__.py +49 -0
- rocket_engine/project/testbench/blocks.py +619 -0
- rocket_engine/project/testbench/templates.py +134 -0
- rocket_engine/stores/README.md +12 -0
- rocket_engine/stores/__init__.py +6 -0
- rocket_engine/stores/ecs.py +1508 -0
- rocket_engine/stores/layers.py +1023 -0
- rocket_engine/stores/settings.py +1188 -0
- rocket_engine/stores/wireplace.py +1324 -0
- rocket_engine/workflows/README.md +18 -0
- rocket_engine/workflows/__init__.py +53 -0
- rocket_engine/workflows/capability_plan.py +102 -0
- rocket_engine/workflows/completion.py +228 -0
- rocket_engine/workflows/connectgraph.py +734 -0
- rocket_engine/workflows/connectgraph_emit.py +336 -0
- rocket_engine/workflows/gates.py +144 -0
- rocket_engine/workflows/photonic_wire.py +76 -0
- rocket_engine/workflows/stages.py +324 -0
- rocket_engine/workflows/viewsync.py +399 -0
- rocket_engine-0.0.2b1.dist-info/METADATA +200 -0
- rocket_engine-0.0.2b1.dist-info/RECORD +241 -0
- rocket_engine-0.0.2b1.dist-info/WHEEL +4 -0
- rocket_engine-0.0.2b1.dist-info/entry_points.txt +2 -0
- rocket_engine-0.0.2b1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
"""Tier-2 call shapes, effects reports, and addressing."""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
from ruamel.yaml import YAML
|
|
7
|
+
|
|
8
|
+
from ...stores import ecs
|
|
9
|
+
from ..errors import ExecutionError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
#: Doc writes: the CRUD document verbs, newest revision wins by gate.
|
|
13
|
+
DOC_VERBS = ("apply_mutations", "delete_doc", "write_doc")
|
|
14
|
+
|
|
15
|
+
#: Cell add/place: catalogue instances landing as component docs.
|
|
16
|
+
CELL_VERBS = ("place_cell",)
|
|
17
|
+
|
|
18
|
+
#: Entity store verbs (ENGINE-ECS): components over projected docs.
|
|
19
|
+
ECS_VERBS = (
|
|
20
|
+
"attach_component",
|
|
21
|
+
"create_entity",
|
|
22
|
+
"delete_entity",
|
|
23
|
+
"detach_component",
|
|
24
|
+
"set_component",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
#: Wire/junction verbs (WIRE-PLACE): connectivity as durable data.
|
|
28
|
+
WIRE_VERBS = (
|
|
29
|
+
"connect_endpoint",
|
|
30
|
+
"delete_junction",
|
|
31
|
+
"delete_wire",
|
|
32
|
+
"materialize_nets",
|
|
33
|
+
"move_wire",
|
|
34
|
+
"place_junction",
|
|
35
|
+
"place_wire",
|
|
36
|
+
"split_wire",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
#: Sibling project mutations sharing the identical admission path.
|
|
40
|
+
PROJECT_VERBS = ("create_project", "rewind", "write_settings")
|
|
41
|
+
|
|
42
|
+
#: Every console tier-2 operation: project-state mutations admitted
|
|
43
|
+
#: through the ledger. Reads, solver runs, and unknown names stay
|
|
44
|
+
#: tier-1 (dispatch and the vocabulary gate own those).
|
|
45
|
+
TIER_2_OPERATIONS = frozenset(
|
|
46
|
+
list(DOC_VERBS) + list(CELL_VERBS) + list(ECS_VERBS)
|
|
47
|
+
+ list(WIRE_VERBS) + list(PROJECT_VERBS)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
#: Console namespace verbs, sorted: one wrapper per name on both
|
|
51
|
+
#: ConsoleNamespace (host-side admission) and ConsoleTools
|
|
52
|
+
#: (worker-side recording).
|
|
53
|
+
CONSOLE_TOOL_VERBS = tuple(sorted(TIER_2_OPERATIONS))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def tier_for(operation):
|
|
57
|
+
"""Classify one operation into its console tier.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
operation: Operation name to classify (any value tolerated).
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
2 for project-state mutations routing through admission, 1
|
|
64
|
+
for reads, solver runs, unknown names, and non-text.
|
|
65
|
+
"""
|
|
66
|
+
if isinstance(operation, str) and operation in TIER_2_OPERATIONS:
|
|
67
|
+
return 2
|
|
68
|
+
return 1
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def is_tier2(operation):
|
|
72
|
+
"""True when an operation is a tier-2 admitted mutation.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
operation: Operation name to test (any value tolerated).
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
True for tier-2 verbs, False for everything else.
|
|
79
|
+
"""
|
|
80
|
+
return tier_for(operation) == 2
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def admission_envelope(operation, arguments):
|
|
84
|
+
"""Render one admission identity text for a tier-2 call.
|
|
85
|
+
|
|
86
|
+
The text carries the operation plus its arguments through the
|
|
87
|
+
same YAML dumper the Engine uses, so identical calls admit with
|
|
88
|
+
identical identity and resubmits replay instead of duplicating.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
operation: Tier-2 operation name for the envelope.
|
|
92
|
+
arguments: Operation arguments carried on the envelope.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
YAML command text identifying this exact call.
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
ExecutionError: invalid_command for a non-text operation,
|
|
99
|
+
non-mapping arguments, or values no YAML dumper spans.
|
|
100
|
+
"""
|
|
101
|
+
if not isinstance(operation, str) or not operation:
|
|
102
|
+
raise ExecutionError(
|
|
103
|
+
"invalid_command",
|
|
104
|
+
f"Envelope needs a text operation, got {operation!r}.",
|
|
105
|
+
)
|
|
106
|
+
if not isinstance(arguments, dict):
|
|
107
|
+
raise ExecutionError(
|
|
108
|
+
"invalid_command",
|
|
109
|
+
f"Envelope needs mapping arguments, got {arguments!r}.",
|
|
110
|
+
)
|
|
111
|
+
# Fresh dumper per call: a failed ruamel dump poisons the
|
|
112
|
+
# instance (it then emits empty text forever), which would
|
|
113
|
+
# collapse distinct calls onto one identity.
|
|
114
|
+
buf = io.StringIO()
|
|
115
|
+
try:
|
|
116
|
+
YAML(typ="safe").dump(
|
|
117
|
+
{"operation": operation, "arguments": arguments}, buf
|
|
118
|
+
)
|
|
119
|
+
except Exception as exc:
|
|
120
|
+
raise ExecutionError(
|
|
121
|
+
"invalid_command",
|
|
122
|
+
f"Envelope arguments do not serialize: {exc}.",
|
|
123
|
+
) from exc
|
|
124
|
+
return buf.getvalue()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def stamp_tier2_call(operation, arguments, expected_revision,
|
|
128
|
+
request_id=None):
|
|
129
|
+
"""Bind live admission identity onto one recorded tier-2 call.
|
|
130
|
+
|
|
131
|
+
Console replay stamps what the cell left open: a tier-2 call
|
|
132
|
+
without a caller binding gains the live head revision, and a
|
|
133
|
+
call without an envelope id gains a fresh one. Caller bindings
|
|
134
|
+
win verbatim — a cell that pinned its own revision replays at
|
|
135
|
+
that revision and fails loudly when it drifted. Tier-1 calls
|
|
136
|
+
pass through untouched.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
operation: Recorded operation name.
|
|
140
|
+
arguments: Recorded arguments mapping.
|
|
141
|
+
expected_revision: Live head revision to bind when the
|
|
142
|
+
caller bound none.
|
|
143
|
+
request_id: Envelope id to keep, or None for a fresh one
|
|
144
|
+
on tier-2 calls.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
(arguments, request_id) pair: a new arguments mapping with
|
|
148
|
+
the binding filled when it was missing, plus the kept
|
|
149
|
+
or minted envelope id.
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
ExecutionError: invalid_command for non-mapping arguments.
|
|
153
|
+
"""
|
|
154
|
+
if not isinstance(arguments, dict):
|
|
155
|
+
raise ExecutionError(
|
|
156
|
+
"invalid_command",
|
|
157
|
+
f"Stamp needs mapping arguments, got {arguments!r}.",
|
|
158
|
+
)
|
|
159
|
+
if not is_tier2(operation):
|
|
160
|
+
return dict(arguments), request_id
|
|
161
|
+
stamped = dict(arguments)
|
|
162
|
+
if "expected_revision" not in stamped:
|
|
163
|
+
stamped["expected_revision"] = expected_revision
|
|
164
|
+
return stamped, request_id or uuid.uuid4().hex
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def tool_call(operation, arguments):
|
|
168
|
+
"""Build one canonical worker-side op-call record.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
operation: Operation name for the record.
|
|
172
|
+
arguments: Op arguments copied onto the record.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Op-call mapping with operation plus a copy of arguments —
|
|
176
|
+
the prelude JSONL shape, host replayable.
|
|
177
|
+
|
|
178
|
+
Raises:
|
|
179
|
+
ExecutionError: invalid_command for a non-text operation
|
|
180
|
+
or non-mapping arguments.
|
|
181
|
+
"""
|
|
182
|
+
if not isinstance(operation, str) or not operation:
|
|
183
|
+
raise ExecutionError(
|
|
184
|
+
"invalid_command",
|
|
185
|
+
f"Op call needs a text operation, got {operation!r}.",
|
|
186
|
+
)
|
|
187
|
+
if not isinstance(arguments, dict):
|
|
188
|
+
raise ExecutionError(
|
|
189
|
+
"invalid_command",
|
|
190
|
+
f"Op call needs mapping arguments, got {arguments!r}.",
|
|
191
|
+
)
|
|
192
|
+
return {"operation": operation, "arguments": dict(arguments)}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def collect_run_ids(op_results):
|
|
196
|
+
"""Lift child run ids off replayed op results.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
op_results: Per-op replay outcomes (ok plus result, or ok
|
|
200
|
+
False plus error); None reads as no results.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Run ids in replay order: one per ok result carrying a text
|
|
204
|
+
run_id, everything else skipped.
|
|
205
|
+
"""
|
|
206
|
+
run_ids = []
|
|
207
|
+
for item in op_results or []:
|
|
208
|
+
if not isinstance(item, dict) or not item.get("ok"):
|
|
209
|
+
continue
|
|
210
|
+
result = item.get("result")
|
|
211
|
+
if isinstance(result, dict) and isinstance(
|
|
212
|
+
result.get("run_id"), str
|
|
213
|
+
):
|
|
214
|
+
run_ids.append(result["run_id"])
|
|
215
|
+
return run_ids
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def build_effects_report(ops, op_results, ops_skipped=0, replayed=True):
|
|
219
|
+
"""Pack replayed ops as the shared effects shape.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
ops: Recorded op calls in replay order.
|
|
223
|
+
op_results: Per-op replay outcomes aligned with ops.
|
|
224
|
+
ops_skipped: Harvest lines dropped as malformed.
|
|
225
|
+
replayed: True once a dispatcher replayed the calls; an
|
|
226
|
+
unreplayed bundle is ok only when it holds no ops.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Effects mapping with ops, per-op results, the ok flag,
|
|
230
|
+
the skip count, child run ids, and the replayed flag.
|
|
231
|
+
"""
|
|
232
|
+
results = list(op_results or [])
|
|
233
|
+
calls = list(ops or [])
|
|
234
|
+
if replayed:
|
|
235
|
+
ops_ok = all(item.get("ok") for item in results)
|
|
236
|
+
else:
|
|
237
|
+
ops_ok = not calls
|
|
238
|
+
return {
|
|
239
|
+
"ops": calls,
|
|
240
|
+
"op_results": results,
|
|
241
|
+
"ops_ok": ops_ok,
|
|
242
|
+
"ops_skipped": ops_skipped,
|
|
243
|
+
"run_ids": collect_run_ids(results),
|
|
244
|
+
"replayed": bool(replayed),
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def report_completions(run_ids, fetch):
|
|
249
|
+
"""Report stored completions for run ids without executing.
|
|
250
|
+
|
|
251
|
+
A read-only batch read-back: every id resolves through fetch
|
|
252
|
+
(a stored-completion reader such as the job surface), unknown
|
|
253
|
+
ids land in refused with their code, and ids listed twice are
|
|
254
|
+
refused as duplicates — nothing runs, nothing advances, and a
|
|
255
|
+
second report over the same ids reads the same values.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
run_ids: Non-empty list of run ids to report.
|
|
259
|
+
fetch: Callable mapping one run id to its stored
|
|
260
|
+
completion; per-id failures land in refused.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
Report mapping with the asked run ids, their completions
|
|
264
|
+
in order, and refused entries (run_id, code, message).
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
ExecutionError: invalid_command for an empty or
|
|
268
|
+
non-list run_ids, a non-text id, or a non-callable
|
|
269
|
+
fetch.
|
|
270
|
+
"""
|
|
271
|
+
if not isinstance(run_ids, list) or not run_ids:
|
|
272
|
+
raise ExecutionError(
|
|
273
|
+
"invalid_command",
|
|
274
|
+
"report_completions needs a non-empty run_ids list.",
|
|
275
|
+
)
|
|
276
|
+
for run_id in run_ids:
|
|
277
|
+
if not isinstance(run_id, str) or not run_id:
|
|
278
|
+
raise ExecutionError(
|
|
279
|
+
"invalid_command",
|
|
280
|
+
f"Run id must be non-empty text, got {run_id!r}.",
|
|
281
|
+
)
|
|
282
|
+
if not callable(fetch):
|
|
283
|
+
raise ExecutionError(
|
|
284
|
+
"invalid_command", "report_completions needs a fetch reader."
|
|
285
|
+
)
|
|
286
|
+
completions = []
|
|
287
|
+
refused = []
|
|
288
|
+
seen = set()
|
|
289
|
+
for run_id in run_ids:
|
|
290
|
+
if run_id in seen:
|
|
291
|
+
refused.append({
|
|
292
|
+
"run_id": run_id,
|
|
293
|
+
"code": "duplicate_in_batch",
|
|
294
|
+
"message": f"Run listed twice in one report: {run_id}.",
|
|
295
|
+
})
|
|
296
|
+
continue
|
|
297
|
+
seen.add(run_id)
|
|
298
|
+
try:
|
|
299
|
+
completions.append(fetch(run_id))
|
|
300
|
+
except Exception as exc: # per-id truth: record, never raise
|
|
301
|
+
refused.append({
|
|
302
|
+
"run_id": run_id,
|
|
303
|
+
"code": getattr(exc, "code", None) or "internal_error",
|
|
304
|
+
"message": str(exc),
|
|
305
|
+
})
|
|
306
|
+
return {"run_ids": list(run_ids), "completions": completions,
|
|
307
|
+
"refused": refused}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def entity_doc_path(entity):
|
|
311
|
+
"""Derive the one doc path storing an entity.
|
|
312
|
+
|
|
313
|
+
Shared ENGINE-ECS addressing: this wrapper names the same
|
|
314
|
+
function the store and the wired verbs use, so console paths
|
|
315
|
+
cannot drift onto a second projection.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
entity: Entity id to project.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Canonical entities path for the id.
|
|
322
|
+
|
|
323
|
+
Raises:
|
|
324
|
+
EcsError: invalid_entity for a malformed id (propagated
|
|
325
|
+
unchanged from the shared substrate).
|
|
326
|
+
"""
|
|
327
|
+
return ecs.entity_doc_path(entity)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def parse_address(address):
|
|
331
|
+
"""Split one canonical entity.component address.
|
|
332
|
+
|
|
333
|
+
Shared ENGINE-ECS addressing, same function as the store.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
address: Address text with exactly one dot.
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
(entity, component) pair, both validated.
|
|
340
|
+
|
|
341
|
+
Raises:
|
|
342
|
+
EcsError: invalid_address for a malformed address
|
|
343
|
+
(propagated unchanged from the shared substrate).
|
|
344
|
+
"""
|
|
345
|
+
return ecs.parse_address(address)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def format_address(entity, component):
|
|
349
|
+
"""Render one canonical entity.component address.
|
|
350
|
+
|
|
351
|
+
Shared ENGINE-ECS addressing, same function as the store.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
entity: Entity id part.
|
|
355
|
+
component: Component name part.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
Canonical address text.
|
|
359
|
+
|
|
360
|
+
Raises:
|
|
361
|
+
EcsError: invalid_entity or invalid_component for
|
|
362
|
+
malformed parts (propagated unchanged).
|
|
363
|
+
"""
|
|
364
|
+
return ecs.format_address(entity, component)
|