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.
Files changed (241) hide show
  1. rocket_engine/__init__.py +8 -0
  2. rocket_engine/__main__.py +12 -0
  3. rocket_engine/adapters/README.md +54 -0
  4. rocket_engine/adapters/__init__.py +7 -0
  5. rocket_engine/adapters/api.py +39 -0
  6. rocket_engine/adapters/base.py +46 -0
  7. rocket_engine/adapters/cace/__init__.py +163 -0
  8. rocket_engine/adapters/circulax/README.md +10 -0
  9. rocket_engine/adapters/circulax/__init__.py +112 -0
  10. rocket_engine/adapters/circulax/_driver.py +190 -0
  11. rocket_engine/adapters/circulax/adapter.py +538 -0
  12. rocket_engine/adapters/circulax/results.py +291 -0
  13. rocket_engine/adapters/cli/README.md +34 -0
  14. rocket_engine/adapters/cli/__init__.py +305 -0
  15. rocket_engine/adapters/connectivity/__init__.py +196 -0
  16. rocket_engine/adapters/connectivity/results.py +214 -0
  17. rocket_engine/adapters/cosim/README.md +9 -0
  18. rocket_engine/adapters/cosim/__init__.py +1390 -0
  19. rocket_engine/adapters/cosim/results.py +214 -0
  20. rocket_engine/adapters/devsim/__init__.py +171 -0
  21. rocket_engine/adapters/digital_flow/README.md +9 -0
  22. rocket_engine/adapters/digital_flow/__init__.py +1121 -0
  23. rocket_engine/adapters/digital_flow/results.py +227 -0
  24. rocket_engine/adapters/digital_flow/state.py +462 -0
  25. rocket_engine/adapters/drc/README.klayout.md +7 -0
  26. rocket_engine/adapters/drc/README.md +7 -0
  27. rocket_engine/adapters/drc/__init__.py +1 -0
  28. rocket_engine/adapters/drc/klayout.py +952 -0
  29. rocket_engine/adapters/drc/magic.py +287 -0
  30. rocket_engine/adapters/drc/results.py +184 -0
  31. rocket_engine/adapters/drc/results_kl.py +188 -0
  32. rocket_engine/adapters/elmer/__init__.py +163 -0
  33. rocket_engine/adapters/envelope.py +120 -0
  34. rocket_engine/adapters/equivalence/__init__.py +156 -0
  35. rocket_engine/adapters/errors.py +181 -0
  36. rocket_engine/adapters/extract_magic/README.md +15 -0
  37. rocket_engine/adapters/extract_magic/__init__.py +425 -0
  38. rocket_engine/adapters/extract_magic/results.py +209 -0
  39. rocket_engine/adapters/formal_sby/README.md +7 -0
  40. rocket_engine/adapters/formal_sby/__init__.py +773 -0
  41. rocket_engine/adapters/formal_sby/formal_edge.py +195 -0
  42. rocket_engine/adapters/formal_sby/results.py +185 -0
  43. rocket_engine/adapters/gdsfactory/__init__.py +194 -0
  44. rocket_engine/adapters/gdsfactory/_driver.py +459 -0
  45. rocket_engine/adapters/gdsfactory/adapter.py +609 -0
  46. rocket_engine/adapters/gdsfactory/results.py +181 -0
  47. rocket_engine/adapters/hdl_sim/README.md +7 -0
  48. rocket_engine/adapters/hdl_sim/__init__.py +369 -0
  49. rocket_engine/adapters/hdl_sim/ghdl.py +155 -0
  50. rocket_engine/adapters/hdl_sim/results.py +178 -0
  51. rocket_engine/adapters/hdl_sim/verilator.py +167 -0
  52. rocket_engine/adapters/http/README.md +15 -0
  53. rocket_engine/adapters/http/__init__.py +458 -0
  54. rocket_engine/adapters/http/events.py +63 -0
  55. rocket_engine/adapters/ipc/README.md +9 -0
  56. rocket_engine/adapters/ipc/__init__.py +111 -0
  57. rocket_engine/adapters/lvs_netgen/README.md +20 -0
  58. rocket_engine/adapters/lvs_netgen/__init__.py +889 -0
  59. rocket_engine/adapters/lvs_netgen/results.py +168 -0
  60. rocket_engine/adapters/mcp/README.md +19 -0
  61. rocket_engine/adapters/mcp/__init__.py +85 -0
  62. rocket_engine/adapters/mcp/api-schema.json +6107 -0
  63. rocket_engine/adapters/mcp/pull.py +246 -0
  64. rocket_engine/adapters/mcp/server.py +794 -0
  65. rocket_engine/adapters/meep/__init__.py +167 -0
  66. rocket_engine/adapters/meow/README.md +7 -0
  67. rocket_engine/adapters/meow/__init__.py +190 -0
  68. rocket_engine/adapters/meow/_driver.py +227 -0
  69. rocket_engine/adapters/meow/_envelope.py +108 -0
  70. rocket_engine/adapters/meow/adapter.py +491 -0
  71. rocket_engine/adapters/meow/results.py +218 -0
  72. rocket_engine/adapters/mutation/__init__.py +192 -0
  73. rocket_engine/adapters/ngspice/README.md +28 -0
  74. rocket_engine/adapters/ngspice/__init__.py +627 -0
  75. rocket_engine/adapters/ngspice/results.py +215 -0
  76. rocket_engine/adapters/postlayout/README.md +28 -0
  77. rocket_engine/adapters/postlayout/__init__.py +17 -0
  78. rocket_engine/adapters/postlayout/adapter.py +1062 -0
  79. rocket_engine/adapters/postlayout/results.py +330 -0
  80. rocket_engine/adapters/postlayout/translate.py +71 -0
  81. rocket_engine/adapters/profile.py +220 -0
  82. rocket_engine/adapters/sax/README.md +23 -0
  83. rocket_engine/adapters/sax/__init__.py +516 -0
  84. rocket_engine/adapters/sax/_driver.py +148 -0
  85. rocket_engine/adapters/sax/results.py +291 -0
  86. rocket_engine/adapters/stdio_console.py +1151 -0
  87. rocket_engine/adapters/syntax/README.md +5 -0
  88. rocket_engine/adapters/syntax/__init__.py +366 -0
  89. rocket_engine/adapters/syntax/results.py +181 -0
  90. rocket_engine/adapters/synth_yosys/README.md +7 -0
  91. rocket_engine/adapters/synth_yosys/__init__.py +655 -0
  92. rocket_engine/adapters/synth_yosys/amaranth.py +120 -0
  93. rocket_engine/adapters/synth_yosys/ghdl.py +128 -0
  94. rocket_engine/adapters/synth_yosys/results.py +173 -0
  95. rocket_engine/adapters/timing_sta/README.md +9 -0
  96. rocket_engine/adapters/timing_sta/__init__.py +726 -0
  97. rocket_engine/adapters/view_sync/__init__.py +185 -0
  98. rocket_engine/adapters/view_sync/results.py +189 -0
  99. rocket_engine/adapters/vlsir/__init__.py +142 -0
  100. rocket_engine/adapters/xschem/__init__.py +440 -0
  101. rocket_engine/adapters/xschem/deck.py +266 -0
  102. rocket_engine/clients/__init__.py +5 -0
  103. rocket_engine/clients/runtime.py +255 -0
  104. rocket_engine/composition.py +2279 -0
  105. rocket_engine/execution/README.md +30 -0
  106. rocket_engine/execution/__init__.py +150 -0
  107. rocket_engine/execution/apig/__init__.py +1 -0
  108. rocket_engine/execution/apig/pool.py +463 -0
  109. rocket_engine/execution/apig/submit.py +124 -0
  110. rocket_engine/execution/block_runs_scope.py +479 -0
  111. rocket_engine/execution/coalesce.py +414 -0
  112. rocket_engine/execution/console/__init__.py +1 -0
  113. rocket_engine/execution/console/apply_session.py +318 -0
  114. rocket_engine/execution/console/lifecycle.py +265 -0
  115. rocket_engine/execution/dispatch.py +205 -0
  116. rocket_engine/execution/errors.py +31 -0
  117. rocket_engine/execution/ports.py +797 -0
  118. rocket_engine/execution/pyexec/__init__.py +1 -0
  119. rocket_engine/execution/pyexec/apply_context.py +547 -0
  120. rocket_engine/execution/pyexec/approvals.py +173 -0
  121. rocket_engine/execution/pyexec/runner.py +404 -0
  122. rocket_engine/execution/pyexec/support.py +464 -0
  123. rocket_engine/execution/python_exec.py +897 -0
  124. rocket_engine/execution/queue.py +85 -0
  125. rocket_engine/execution/replay_safe.py +601 -0
  126. rocket_engine/execution/routing/__init__.py +1 -0
  127. rocket_engine/execution/routing/calls.py +364 -0
  128. rocket_engine/execution/routing/namespace.py +785 -0
  129. rocket_engine/execution/routing/ports.py +102 -0
  130. rocket_engine/execution/routing/tools.py +346 -0
  131. rocket_engine/execution/runner.py +311 -0
  132. rocket_engine/execution/runtime.py +1149 -0
  133. rocket_engine/execution/service.py +279 -0
  134. rocket_engine/execution/worker.py +464 -0
  135. rocket_engine/interfaces/README.md +26 -0
  136. rocket_engine/interfaces/__init__.py +58 -0
  137. rocket_engine/interfaces/apig_assets.py +407 -0
  138. rocket_engine/interfaces/celllink.py +461 -0
  139. rocket_engine/interfaces/documents.py +92 -0
  140. rocket_engine/interfaces/envelopes.py +131 -0
  141. rocket_engine/interfaces/errors.py +16 -0
  142. rocket_engine/interfaces/layout.py +410 -0
  143. rocket_engine/interfaces/layout_schema.yaml +278 -0
  144. rocket_engine/interfaces/paths.py +223 -0
  145. rocket_engine/interfaces/pdks.py +550 -0
  146. rocket_engine/interfaces/ports.py +72 -0
  147. rocket_engine/interfaces/references.py +115 -0
  148. rocket_engine/interfaces/refs.py +85 -0
  149. rocket_engine/interfaces/runparams.py +304 -0
  150. rocket_engine/interfaces/setup.py +552 -0
  151. rocket_engine/interfaces/setup_catalogue.yaml +243 -0
  152. rocket_engine/interfaces/setup_probes.py +66 -0
  153. rocket_engine/interfaces/vocabulary.py +58 -0
  154. rocket_engine/interfaces/yaml_dump.py +31 -0
  155. rocket_engine/library/README.md +22 -0
  156. rocket_engine/library/__init__.py +13 -0
  157. rocket_engine/library/apig_catalog.py +371 -0
  158. rocket_engine/library/catalog.py +185 -0
  159. rocket_engine/library/errors.py +16 -0
  160. rocket_engine/mutate/__init__.py +776 -0
  161. rocket_engine/mutate/operators.py +700 -0
  162. rocket_engine/ops/__init__.py +1 -0
  163. rocket_engine/ops/deferred.py +279 -0
  164. rocket_engine/ops/editors.py +404 -0
  165. rocket_engine/ops/evidence.py +194 -0
  166. rocket_engine/ops/gates.py +262 -0
  167. rocket_engine/ops/ports.py +76 -0
  168. rocket_engine/ops/queries.py +417 -0
  169. rocket_engine/ops/runs.py +553 -0
  170. rocket_engine/ops/submit.py +614 -0
  171. rocket_engine/project/README.md +27 -0
  172. rocket_engine/project/__init__.py +6 -0
  173. rocket_engine/project/canvas/__init__.py +55 -0
  174. rocket_engine/project/canvas/compile.py +109 -0
  175. rocket_engine/project/canvas/integrate.py +48 -0
  176. rocket_engine/project/canvas/schema.py +241 -0
  177. rocket_engine/project/canvas/templates.py +46 -0
  178. rocket_engine/project/canvas/validate.py +603 -0
  179. rocket_engine/project/edit/__init__.py +5 -0
  180. rocket_engine/project/edit/cas.py +87 -0
  181. rocket_engine/project/edit/transactions.py +282 -0
  182. rocket_engine/project/errors.py +16 -0
  183. rocket_engine/project/frontend13.py +685 -0
  184. rocket_engine/project/geometry/__init__.py +23 -0
  185. rocket_engine/project/geometry/ops.py +451 -0
  186. rocket_engine/project/geometry/snap.py +103 -0
  187. rocket_engine/project/ip/__init__.py +1 -0
  188. rocket_engine/project/ip/blocks.py +195 -0
  189. rocket_engine/project/ip/entry.schema.json +78 -0
  190. rocket_engine/project/ip/lifecycle.py +402 -0
  191. rocket_engine/project/ip/verbs.py +123 -0
  192. rocket_engine/project/layers/__init__.py +6 -0
  193. rocket_engine/project/layers/bindings.py +115 -0
  194. rocket_engine/project/layers/catalog.py +228 -0
  195. rocket_engine/project/layers/presets.py +43 -0
  196. rocket_engine/project/ledger/__init__.py +1 -0
  197. rocket_engine/project/ledger/docs.py +167 -0
  198. rocket_engine/project/ledger/entities.py +176 -0
  199. rocket_engine/project/ledger/events.py +29 -0
  200. rocket_engine/project/ledger/runs.py +257 -0
  201. rocket_engine/project/ledger/shared.py +174 -0
  202. rocket_engine/project/ledger/snapshots.py +385 -0
  203. rocket_engine/project/ledger/wires.py +552 -0
  204. rocket_engine/project/process/__init__.py +14 -0
  205. rocket_engine/project/process/model.py +193 -0
  206. rocket_engine/project/process/recipes.py +121 -0
  207. rocket_engine/project/schematic/__init__.py +1 -0
  208. rocket_engine/project/schematic/hierarchy.py +312 -0
  209. rocket_engine/project/schematic/instances.py +393 -0
  210. rocket_engine/project/schematic/sheets.py +198 -0
  211. rocket_engine/project/service.py +2941 -0
  212. rocket_engine/project/symbols/__init__.py +1 -0
  213. rocket_engine/project/symbols/cells.py +324 -0
  214. rocket_engine/project/symbols/linkage.py +356 -0
  215. rocket_engine/project/symbols/symbols.py +352 -0
  216. rocket_engine/project/templates/__init__.py +303 -0
  217. rocket_engine/project/templates/errors.py +25 -0
  218. rocket_engine/project/testbench/__init__.py +49 -0
  219. rocket_engine/project/testbench/blocks.py +619 -0
  220. rocket_engine/project/testbench/templates.py +134 -0
  221. rocket_engine/stores/README.md +12 -0
  222. rocket_engine/stores/__init__.py +6 -0
  223. rocket_engine/stores/ecs.py +1508 -0
  224. rocket_engine/stores/layers.py +1023 -0
  225. rocket_engine/stores/settings.py +1188 -0
  226. rocket_engine/stores/wireplace.py +1324 -0
  227. rocket_engine/workflows/README.md +18 -0
  228. rocket_engine/workflows/__init__.py +53 -0
  229. rocket_engine/workflows/capability_plan.py +102 -0
  230. rocket_engine/workflows/completion.py +228 -0
  231. rocket_engine/workflows/connectgraph.py +734 -0
  232. rocket_engine/workflows/connectgraph_emit.py +336 -0
  233. rocket_engine/workflows/gates.py +144 -0
  234. rocket_engine/workflows/photonic_wire.py +76 -0
  235. rocket_engine/workflows/stages.py +324 -0
  236. rocket_engine/workflows/viewsync.py +399 -0
  237. rocket_engine-0.0.2b1.dist-info/METADATA +200 -0
  238. rocket_engine-0.0.2b1.dist-info/RECORD +241 -0
  239. rocket_engine-0.0.2b1.dist-info/WHEEL +4 -0
  240. rocket_engine-0.0.2b1.dist-info/entry_points.txt +2 -0
  241. rocket_engine-0.0.2b1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,214 @@
1
+ """Cosim v1 normalizer: v0 joint parse output to a ResultBundle.
2
+
3
+ Maps the ``run_cosim`` joint parse shape (``measurements[]``
4
+ with the SNDR gate plus ones-density bounds, and violations for
5
+ bitless analog halves or failing digital benches) onto a typed
6
+ measurement table, bound views, measurements, and findings. Pure
7
+ function of the parsed output: no I/O, no tool calls,
8
+ deterministic ids derived from the run id. PASS measurements keep
9
+ value, target, margin, and status.
10
+ """
11
+
12
+ TASK = "run_cosim"
13
+
14
+ _DIAG_CAP = 240
15
+
16
+ _SEVERITY = {"error": "error", "warning": "warning"}
17
+
18
+
19
+ def _cap(text):
20
+ """Cap one diagnostic string at the bundle prose limit.
21
+
22
+ Args:
23
+ text: Raw diagnostic text, possibly unbounded tool prose.
24
+
25
+ Returns:
26
+ The text unchanged when short, else truncated with an
27
+ ellipsis marker.
28
+ """
29
+ text = text if isinstance(text, str) else str(text)
30
+ if len(text) <= _DIAG_CAP:
31
+ return text
32
+ return text[: _DIAG_CAP - 3] + "..."
33
+
34
+
35
+ def _quantity(value, unit):
36
+ """Build one v1 Quantity, mapping unitless to dimensionless.
37
+
38
+ Args:
39
+ value: Numeric value.
40
+ unit: Unit string, possibly empty for unitless measures.
41
+
42
+ Returns:
43
+ Quantity mapping with an explicit unit.
44
+ """
45
+ return {"value": float(value), "unit": unit if unit else "1"}
46
+
47
+
48
+ def _limit(item):
49
+ """Pick the binding target bound for one measurement.
50
+
51
+ Args:
52
+ item: v0 measurement with a ``target`` min/max mapping.
53
+
54
+ Returns:
55
+ The bound closest to the measured value, or None when the
56
+ target is empty.
57
+ """
58
+ target = item.get("target") or {}
59
+ scored = []
60
+ if target.get("min") is not None:
61
+ scored.append((float(item["value"]) - float(target["min"]),
62
+ float(target["min"])))
63
+ if target.get("max") is not None:
64
+ scored.append((float(target["max"]) - float(item["value"]),
65
+ float(target["max"])))
66
+ if not scored:
67
+ return None
68
+ return min(scored)[1]
69
+
70
+
71
+ def _provenance(project_id, run_id, tools, provenance):
72
+ """Build ResultProvenance, defaulting to a placeholder closure.
73
+
74
+ Args:
75
+ project_id: Project the run belongs to.
76
+ run_id: Run the bundle describes.
77
+ tools: Tool ingredient mappings (id, version, digest?).
78
+ provenance: Full provenance mapping when the caller has
79
+ one; a deterministic placeholder otherwise.
80
+
81
+ Returns:
82
+ Provenance mapping valid against the v1 schema.
83
+ """
84
+ if provenance is not None:
85
+ return provenance
86
+ ref = {"scope": "project", "id": project_id, "revision": "r1"}
87
+ return {
88
+ "snapshot": dict(ref),
89
+ "input_lock": dict(ref),
90
+ "closure_hash": "0" * 64,
91
+ "tools": [
92
+ {
93
+ "id": item["id"],
94
+ "version": item.get("version", ""),
95
+ "digest": item.get("digest", "0" * 64),
96
+ }
97
+ for item in tools
98
+ ],
99
+ "parents": [],
100
+ }
101
+
102
+
103
+ def normalize(parsed, *, run_id, project_id="project", target=None,
104
+ tools=(), provenance=None):
105
+ """Normalize one cosim joint parse output to a v1 ResultBundle.
106
+
107
+ Joint measurement rows become a table dataset plus a bound
108
+ table view; violations (bitless halves, failed benches)
109
+ become findings with capped messages.
110
+
111
+ Args:
112
+ parsed: v0 parse mapping with ``measurements[]`` and
113
+ ``violations[]``.
114
+ run_id: Run the bundle describes (anchors all ids).
115
+ project_id: Project the run belongs to.
116
+ target: v1 target mapping; project kind by default.
117
+ tools: Tool ingredient mappings for provenance.
118
+ provenance: Full provenance mapping when the caller has
119
+ one; a deterministic placeholder otherwise.
120
+
121
+ Returns:
122
+ Schema-valid ResultBundle mapping.
123
+ """
124
+ measurements_in = parsed.get("measurements") or []
125
+ violations = parsed.get("violations") or []
126
+ table_id = f"{run_id}:dataset:measurements"
127
+ datasets = [
128
+ {
129
+ "id": table_id,
130
+ "kind": "table",
131
+ "row_count": len(measurements_in),
132
+ "columns": [
133
+ {
134
+ "id": f"{table_id}:name",
135
+ "name": "name",
136
+ "dtype": "utf8",
137
+ "unit": "1",
138
+ "data": [item["name"] for item in measurements_in],
139
+ },
140
+ {
141
+ "id": f"{table_id}:value",
142
+ "name": "value",
143
+ "dtype": "float64",
144
+ "unit": "1",
145
+ "data": [float(item["value"]) for item in measurements_in],
146
+ },
147
+ {
148
+ "id": f"{table_id}:margin",
149
+ "name": "margin",
150
+ "dtype": "float64",
151
+ "unit": "1",
152
+ "data": [float(item["margin"]) for item in measurements_in],
153
+ },
154
+ {
155
+ "id": f"{table_id}:status",
156
+ "name": "status",
157
+ "dtype": "utf8",
158
+ "unit": "1",
159
+ "data": [item["status"] for item in measurements_in],
160
+ },
161
+ ],
162
+ "conditions": [],
163
+ }
164
+ ]
165
+ views = [
166
+ {
167
+ "id": f"{run_id}:view:measurements",
168
+ "kind": "table",
169
+ "dataset_id": table_id,
170
+ "name": "joint measurements",
171
+ }
172
+ ]
173
+ measurements = []
174
+ for item in measurements_in:
175
+ entry = {
176
+ "name": item["name"],
177
+ "value": _quantity(item["value"], item.get("unit", "")),
178
+ "margin": _quantity(item["margin"], item.get("unit", "")),
179
+ "status": "PASS" if item["status"] == "pass" else "FAIL",
180
+ }
181
+ bound = _limit(item)
182
+ if bound is not None:
183
+ entry["limit"] = _quantity(bound, item.get("unit", ""))
184
+ measurements.append(entry)
185
+ findings = [
186
+ {
187
+ "id": f"{run_id}:finding:{index}",
188
+ "severity": _SEVERITY.get(v.get("severity"), "info"),
189
+ "code": v.get("rule", "sim_fail"),
190
+ "message": _cap(v.get("message", "")),
191
+ }
192
+ for index, v in enumerate(violations)
193
+ ]
194
+ converged = not any(v.get("rule") == "sim_fail" for v in violations)
195
+ return {
196
+ "schema": "rocketeda/results/v1",
197
+ "ref": {"scope": "project", "id": run_id, "revision": "r1"},
198
+ "run_id": run_id,
199
+ "task": TASK,
200
+ "target": dict(target)
201
+ if target is not None
202
+ else {"project_id": project_id, "kind": "project"},
203
+ "state": "complete",
204
+ "freshness": "current",
205
+ "convergence": "converged" if converged else "not_converged",
206
+ "provenance": _provenance(project_id, run_id, tools, provenance),
207
+ "datasets": datasets,
208
+ "views": views,
209
+ "measurements": measurements,
210
+ "findings": findings,
211
+ "artifacts": [],
212
+ "logs": [],
213
+ "gaps": [],
214
+ }
@@ -0,0 +1,171 @@
1
+ """Devsim TCAD adapter: run_tcad behind the ToolAdapter port."""
2
+
3
+ import json
4
+ import shutil
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+ from ...execution.errors import ExecutionError
9
+ from ...interfaces import ToolAdapter
10
+ from ..errors import AdapterError
11
+
12
+ OPERATION = "run_tcad"
13
+ _TOOL = "devsim"
14
+ _DUMP = "devsim_dump.json"
15
+ _TIMEOUT_S = 300
16
+
17
+
18
+ class DevsimAdapter(ToolAdapter):
19
+ """run_tcad via devsim: driver dump parsed to measurements.
20
+
21
+ Serves the run_tcad operation with tool `devsim`. The driver
22
+ script calls get_contact_current/get_*_model_values plus
23
+ solve(info=True) and dumps JSON; the adapter parses the dump
24
+ file, never stdout scraping.
25
+
26
+ Job keys:
27
+ script (required): Driver python script path.
28
+ workdir: Run directory (default ".").
29
+ timeout_s: Budget in seconds (default 300).
30
+ python: Driver python binary (default sys python).
31
+
32
+ Args:
33
+ runner: Optional isolated runner; direct subprocess when None.
34
+ """
35
+
36
+ def __init__(self, runner=None):
37
+ self._runner = runner
38
+
39
+ def capabilities(self, target):
40
+ """Report the served operation and tool.
41
+
42
+ Args:
43
+ target: Target the capabilities are reported for.
44
+
45
+ Returns:
46
+ Capability mapping with operations and tool.
47
+ """
48
+ return {"operations": [OPERATION], "tool": _TOOL,
49
+ "dump": _DUMP}
50
+
51
+ def preflight(self, job):
52
+ """Check operation, script, and devsim importability.
53
+
54
+ Args:
55
+ job: Solver job with operation run_tcad plus script.
56
+
57
+ Returns:
58
+ Checked mapping with script, timeout, and python.
59
+
60
+ Raises:
61
+ AdapterError: unsupported_operation, invalid_reference
62
+ for a missing script, missing_dependency with
63
+ BLOCKED-needs-host when devsim is not importable.
64
+ """
65
+ if job.get("operation") != OPERATION:
66
+ raise AdapterError(
67
+ "unsupported_operation",
68
+ f"Devsim handles {OPERATION}, got {job.get('operation')}.",
69
+ )
70
+ script = job.get("script")
71
+ if not script or not Path(script).is_file():
72
+ raise AdapterError(
73
+ "invalid_reference", f"Driver script not found: {script}.")
74
+ try:
75
+ __import__(_TOOL)
76
+ except ImportError as exc:
77
+ raise AdapterError(
78
+ "missing_dependency",
79
+ "BLOCKED-needs-host: devsim not importable "
80
+ "(need devsim==2.11.2 in the engine venv).",
81
+ ) from exc
82
+ timeout = job.get("timeout_s", _TIMEOUT_S)
83
+ if (not isinstance(timeout, (int, float))
84
+ or isinstance(timeout, bool) or not timeout > 0):
85
+ raise AdapterError("invalid_command", f"Bad timeout: {timeout!r}.")
86
+ checked = {"script": str(script), "timeout_s": timeout,
87
+ "python": job.get("python") or "python3"}
88
+ if self._runner is not None:
89
+ try:
90
+ self._runner.preflight()
91
+ except ExecutionError as exc:
92
+ raise AdapterError(exc.code, str(exc)) from exc
93
+ return checked
94
+
95
+ def execute(self, job):
96
+ """Run the driver script under a timeout.
97
+
98
+ Args:
99
+ job: Solver job with operation run_tcad plus script.
100
+
101
+ Returns:
102
+ Native output with exit_code, stdout/stderr, dump, file.
103
+ """
104
+ checked = self.preflight(job)
105
+ workdir = job.get("workdir", ".")
106
+ if not Path(workdir).is_dir():
107
+ raise AdapterError(
108
+ "invalid_reference", f"Workdir not found: {workdir}.")
109
+ proc = self._run([checked["python"], checked["script"]],
110
+ workdir, checked["timeout_s"])
111
+ dump_path = Path(workdir) / _DUMP
112
+ dump = None
113
+ if dump_path.is_file():
114
+ try:
115
+ dump = json.loads(dump_path.read_text())
116
+ except ValueError:
117
+ dump = None
118
+ return {"exit_code": proc.returncode, "stdout": proc.stdout,
119
+ "stderr": proc.stderr, "dump": dump,
120
+ "dump_file": _DUMP}
121
+
122
+ def parse(self, native_output):
123
+ """Parse the driver JSON dump to verdict plus measurements.
124
+
125
+ Args:
126
+ native_output: Native output with the dump mapping.
127
+
128
+ Returns:
129
+ {total, violations[], measurements[], source} with the
130
+ dump file as source.
131
+
132
+ Raises:
133
+ AdapterError: runner_unavailable when no dump is present.
134
+ """
135
+ dump = native_output.get("dump")
136
+ if not isinstance(dump, dict):
137
+ raise AdapterError(
138
+ "runner_unavailable", "Devsim run left no dump JSON.")
139
+ solve = dump.get("solve") or {}
140
+ violations = []
141
+ if solve.get("converged") is False or not dump.get("currents"):
142
+ violations.append({"rule": "tcad_converge",
143
+ "severity": "error",
144
+ "message": "Devsim solve did not converge."})
145
+ measurements = []
146
+ for name, value in (dump.get("currents") or {}).items():
147
+ try:
148
+ measurements.append({"name": f"current.{name}",
149
+ "value": float(value), "unit": "A"})
150
+ except (TypeError, ValueError):
151
+ continue
152
+ pots = dump.get("potentials") or []
153
+ if pots:
154
+ measurements.append({"name": "potential.count",
155
+ "value": float(len(pots)), "unit": "count"})
156
+ return {"total": len(violations), "violations": violations,
157
+ "measurements": measurements, "source": "dump",
158
+ "dump_file": native_output.get("dump_file", _DUMP)}
159
+
160
+ def _run(self, argv, workdir, timeout_s):
161
+ if self._runner is not None:
162
+ try:
163
+ return self._runner.run(argv, workdir, timeout_s)
164
+ except ExecutionError as exc:
165
+ raise AdapterError(exc.code, str(exc)) from exc
166
+ try:
167
+ return subprocess.run(argv, capture_output=True, text=True,
168
+ timeout=timeout_s, cwd=workdir)
169
+ except subprocess.TimeoutExpired as exc:
170
+ raise AdapterError(
171
+ "runner_unavailable", "Devsim run timed out.") from exc
@@ -0,0 +1,9 @@
1
+ # LibreLane digital-flow adapter
2
+
3
+ LibrelaneFlowAdapter serves run_digital_flow with the librelane deck tool. It stages project RTL and flow configuration, runs the Classic flow under a timeout, and parses stage output into findings, measurements, and artifact references for the D11–D27 gates.
4
+
5
+ The adapter requires the pinned LibreLane 3.0.17 distribution and a compatible PDK root. Tool resolution uses PATH or the job tool_dir; version mismatch refuses. When supplied, BwrapRunner confines the flow with tool and PDK roots read-only and the work directory writable.
6
+
7
+ Hermetic qualification covers synthetic run trees, parse outcomes, timeouts, and failure gates. The live SERV RTL-to-GDS proof is currently blocked because this environment lacks the pinned distribution and PDK root. Adapter registration is not a claim that the full flow has passed live qualification.
8
+
9
+ See the [DIGITAL-FLOW report](../../../docs/work/DIGITAL-FLOW/report.md) and [provision plan](../../../docs/provision-plan.md).