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,399 @@
1
+ """Intended-vs-extracted view comparison (VIEW-SYNC, photonic P14).
2
+
3
+ `compare_views` reduces two schematics through the shared
4
+ CONNECT-GRAPH extraction (`prepare_netlist_structs`), correlates
5
+ pins through CellLink identity (never a second naming scheme),
6
+ and reports missing/wrong/extra ports, missing/unexpected
7
+ connections, and unmapped objects with per-finding identity
8
+ references. Every net name flows from the cited view's shared
9
+ `Connectivity.net_name` authority.
10
+ """
11
+
12
+ import json
13
+
14
+ from ..interfaces.celllink import REFERENCE, ContractError, resolve_link
15
+ from .connectgraph import ConnectGraphError, prepare_netlist_structs
16
+
17
+ RULE_MISSING_PORT = "view_sync.missing_port"
18
+ RULE_EXTRA_PORT = "view_sync.extra_port"
19
+ RULE_WRONG_PORT = "view_sync.wrong_port"
20
+ RULE_MISSING_CONNECTION = "view_sync.missing_connection"
21
+ RULE_UNEXPECTED_CONNECTION = "view_sync.unexpected_connection"
22
+ RULE_UNMAPPED = "view_sync.unmapped"
23
+
24
+
25
+ class ViewSyncError(ValueError):
26
+ """Bad view-sync input: malformed view or bad identity mapping."""
27
+
28
+
29
+ def _identity_maps(links, variant):
30
+ """Per-instance symbol-to-cell maps plus their inverses."""
31
+ if links is None:
32
+ links = []
33
+ if not isinstance(links, list):
34
+ raise ViewSyncError(f"links must be a list, got {links!r}.")
35
+ base_variant = variant in (None, REFERENCE)
36
+ if not base_variant:
37
+ if not isinstance(variant, str) or not variant:
38
+ raise ViewSyncError(
39
+ f"variant must be a non-empty string, got {variant!r}."
40
+ )
41
+ if not links:
42
+ raise ViewSyncError(f"Unknown variant {variant!r}: no links define it.")
43
+ forward = {}
44
+ for index, entry in enumerate(links):
45
+ if not isinstance(entry, dict):
46
+ raise ViewSyncError(f"links[{index}] must be a mapping, got {entry!r}.")
47
+ block_id = entry.get("id")
48
+ if not isinstance(block_id, str) or not block_id:
49
+ raise ViewSyncError(f"links[{index}] needs a non-empty string id.")
50
+ if block_id in forward:
51
+ raise ViewSyncError(f"Duplicate link id: {block_id!r}.")
52
+ block = {"id": block_id}
53
+ if "CellLink" in entry:
54
+ block["CellLink"] = entry["CellLink"]
55
+ try:
56
+ resolved = resolve_link(block, variant=variant)
57
+ except ContractError as exc:
58
+ raise ViewSyncError(f"link {block_id!r}: {exc}") from exc
59
+ mapping = {item["symPin"]: item["cellPin"] for item in resolved["pinMap"]}
60
+ targets = sorted(mapping.values())
61
+ if len(set(targets)) != len(targets):
62
+ raise ViewSyncError(
63
+ f"link {block_id!r}: pinMap collision: two symbol pins "
64
+ f"resolve to one cell pin ({', '.join(targets)})."
65
+ )
66
+ forward[block_id] = mapping
67
+ reverse = {
68
+ name: {cell: sym for sym, cell in mapping.items()}
69
+ for name, mapping in forward.items()
70
+ }
71
+ return forward, reverse
72
+
73
+
74
+ def _extract_side(schematic, side):
75
+ """Extract one view, naming the side on failure."""
76
+ try:
77
+ return prepare_netlist_structs(schematic)
78
+ except ConnectGraphError as exc:
79
+ raise ViewSyncError(f"{side} schematic: {exc}") from exc
80
+
81
+
82
+ def _net_id_by_name(connectivity, name, side):
83
+ """Net id for a port name (ports always name an extracted net)."""
84
+ for net in connectivity.nets:
85
+ if net.name == name:
86
+ return net.id
87
+ raise ViewSyncError(f"{side} port {name!r} names no extracted net.")
88
+
89
+
90
+ def _port_findings(intended_structs, extracted_structs):
91
+ """Missing/wrong/extra port findings with authority net names."""
92
+ findings = []
93
+ iconn = intended_structs.connectivity
94
+ econn = extracted_structs.connectivity
95
+ intended_ports = {p["name"]: p["direction"] for p in intended_structs.ports}
96
+ extracted_ports = {p["name"]: p["direction"] for p in extracted_structs.ports}
97
+ for name in sorted(set(intended_ports) - set(extracted_ports)):
98
+ net_id = _net_id_by_name(iconn, name, "intended")
99
+ findings.append(
100
+ {
101
+ "rule": RULE_MISSING_PORT,
102
+ "severity": "error",
103
+ "message": (
104
+ f"port {name} is missing in extracted "
105
+ f"(intended direction {intended_ports[name]})"
106
+ ),
107
+ "view": "intended",
108
+ "port": name,
109
+ "expected_direction": intended_ports[name],
110
+ "net": iconn.net_name(net_id),
111
+ "net_id": net_id,
112
+ }
113
+ )
114
+ for name in sorted(set(extracted_ports) - set(intended_ports)):
115
+ net_id = _net_id_by_name(econn, name, "extracted")
116
+ findings.append(
117
+ {
118
+ "rule": RULE_EXTRA_PORT,
119
+ "severity": "error",
120
+ "message": (
121
+ f"port {name} is unexpected in extracted "
122
+ f"(direction {extracted_ports[name]})"
123
+ ),
124
+ "view": "extracted",
125
+ "port": name,
126
+ "actual_direction": extracted_ports[name],
127
+ "net": econn.net_name(net_id),
128
+ "net_id": net_id,
129
+ }
130
+ )
131
+ for name in sorted(set(intended_ports) & set(extracted_ports)):
132
+ if intended_ports[name] == extracted_ports[name]:
133
+ continue
134
+ intended_id = _net_id_by_name(iconn, name, "intended")
135
+ extracted_id = _net_id_by_name(econn, name, "extracted")
136
+ findings.append(
137
+ {
138
+ "rule": RULE_WRONG_PORT,
139
+ "severity": "error",
140
+ "message": (
141
+ f"port {name} direction {extracted_ports[name]}, "
142
+ f"expected {intended_ports[name]}"
143
+ ),
144
+ "view": "extracted",
145
+ "port": name,
146
+ "expected_direction": intended_ports[name],
147
+ "actual_direction": extracted_ports[name],
148
+ "net": econn.net_name(extracted_id),
149
+ "net_id": extracted_id,
150
+ "intended_net_id": intended_id,
151
+ "extracted_net_id": extracted_id,
152
+ }
153
+ )
154
+ return findings
155
+
156
+
157
+ def _correlate(intended_structs, extracted_structs, forward, reverse):
158
+ """Correlate pins through CellLink identity (mapped + unmapped)."""
159
+ intended_by_inst = {i.name: i for i in intended_structs.instances}
160
+ extracted_by_inst = {i.name: i for i in extracted_structs.instances}
161
+ findings = []
162
+ for name in sorted(set(intended_by_inst) - set(extracted_by_inst)):
163
+ pins = sorted(p for p, _ in intended_by_inst[name].pins)
164
+ findings.append(
165
+ {
166
+ "rule": RULE_UNMAPPED,
167
+ "severity": "error",
168
+ "message": (
169
+ f"instance {name} has no extracted counterpart "
170
+ f"({len(pins)} pins)"
171
+ ),
172
+ "view": "intended",
173
+ "kind": "instance",
174
+ "instance": name,
175
+ "side": "intended",
176
+ "pins": pins,
177
+ }
178
+ )
179
+ for name in sorted(set(extracted_by_inst) - set(intended_by_inst)):
180
+ pins = sorted(p for p, _ in extracted_by_inst[name].pins)
181
+ findings.append(
182
+ {
183
+ "rule": RULE_UNMAPPED,
184
+ "severity": "error",
185
+ "message": (
186
+ f"instance {name} has no intended counterpart "
187
+ f"({len(pins)} pins)"
188
+ ),
189
+ "view": "extracted",
190
+ "kind": "instance",
191
+ "instance": name,
192
+ "side": "extracted",
193
+ "pins": pins,
194
+ }
195
+ )
196
+ mapped = []
197
+ for name in sorted(set(intended_by_inst) & set(extracted_by_inst)):
198
+ pin_map = forward.get(name, {})
199
+ back_map = reverse.get(name, {})
200
+ intended_pins = {p: n for p, n in intended_by_inst[name].pins}
201
+ extracted_pins = {p: n for p, n in extracted_by_inst[name].pins}
202
+ matched = set()
203
+ for sym in sorted(intended_pins):
204
+ cell = pin_map.get(sym, sym)
205
+ if cell in extracted_pins:
206
+ matched.add(cell)
207
+ mapped.append(
208
+ (name, sym, cell, intended_pins[sym], extracted_pins[cell])
209
+ )
210
+ continue
211
+ conn = intended_structs.connectivity
212
+ net_id = intended_pins[sym]
213
+ findings.append(
214
+ {
215
+ "rule": RULE_UNMAPPED,
216
+ "severity": "error",
217
+ "message": (
218
+ f"pin {name}.{sym} has no extracted counterpart "
219
+ f"(cell pin {cell})"
220
+ ),
221
+ "view": "intended",
222
+ "kind": "pin",
223
+ "instance": name,
224
+ "pin": sym,
225
+ "cell_pin": cell,
226
+ "side": "intended",
227
+ "net": conn.net_name(net_id),
228
+ "net_id": net_id,
229
+ }
230
+ )
231
+ for cell in sorted(set(extracted_pins) - matched):
232
+ conn = extracted_structs.connectivity
233
+ net_id = extracted_pins[cell]
234
+ findings.append(
235
+ {
236
+ "rule": RULE_UNMAPPED,
237
+ "severity": "error",
238
+ "message": (
239
+ f"pin {name}.{cell} has no intended counterpart "
240
+ f"(symbol pin {back_map.get(cell, cell)})"
241
+ ),
242
+ "view": "extracted",
243
+ "kind": "pin",
244
+ "instance": name,
245
+ "pin": cell,
246
+ "sym_pin": back_map.get(cell, cell),
247
+ "side": "extracted",
248
+ "net": conn.net_name(net_id),
249
+ "net_id": net_id,
250
+ }
251
+ )
252
+ return mapped, findings
253
+
254
+
255
+ def _connection_findings(intended_structs, extracted_structs, mapped):
256
+ """Split (missing) and joined (unexpected) net findings."""
257
+ findings = []
258
+ iconn = intended_structs.connectivity
259
+ econn = extracted_structs.connectivity
260
+ by_intended = {}
261
+ for inst, sym, cell, intended_id, extracted_id in mapped:
262
+ by_intended.setdefault(intended_id, []).append(
263
+ (inst, sym, cell, extracted_id)
264
+ )
265
+ for intended_id in sorted(by_intended):
266
+ members = by_intended[intended_id]
267
+ landed = sorted({extracted_id for (_, _, _, extracted_id) in members})
268
+ if len(landed) > 1:
269
+ split = [{"net": econn.net_name(x), "net_id": x} for x in landed]
270
+ pin_list = sorted(f"{i}.{s}" for (i, s, _, _) in members)
271
+ findings.append(
272
+ {
273
+ "rule": RULE_MISSING_CONNECTION,
274
+ "severity": "error",
275
+ "message": (
276
+ f"net {iconn.net_name(intended_id)} splits across "
277
+ f"{', '.join(s['net'] for s in split)} in extracted: "
278
+ + ", ".join(pin_list)
279
+ ),
280
+ "view": "intended",
281
+ "net": iconn.net_name(intended_id),
282
+ "net_id": intended_id,
283
+ "split_across": split,
284
+ "members": [
285
+ {"instance": i, "pin": s, "cell_pin": c}
286
+ for (i, s, c, _) in sorted(members)
287
+ ],
288
+ }
289
+ )
290
+ by_extracted = {}
291
+ for inst, sym, cell, intended_id, extracted_id in mapped:
292
+ by_extracted.setdefault(extracted_id, []).append(
293
+ (inst, sym, cell, intended_id)
294
+ )
295
+ for extracted_id in sorted(by_extracted):
296
+ members = by_extracted[extracted_id]
297
+ sources = sorted({intended_id for (_, _, _, intended_id) in members})
298
+ if len(sources) > 1:
299
+ merged = [{"net": iconn.net_name(i), "net_id": i} for i in sources]
300
+ pin_list = sorted(f"{i}.{c}" for (i, _, c, _) in members)
301
+ findings.append(
302
+ {
303
+ "rule": RULE_UNEXPECTED_CONNECTION,
304
+ "severity": "error",
305
+ "message": (
306
+ f"net {econn.net_name(extracted_id)} joins "
307
+ f"{', '.join(m['net'] for m in merged)} in extracted: "
308
+ + ", ".join(pin_list)
309
+ ),
310
+ "view": "extracted",
311
+ "net": econn.net_name(extracted_id),
312
+ "net_id": extracted_id,
313
+ "merged_from": merged,
314
+ "members": [
315
+ {"instance": i, "pin": c, "sym_pin": s}
316
+ for (i, s, c, _) in sorted(members)
317
+ ],
318
+ }
319
+ )
320
+ return findings
321
+
322
+
323
+ def _coverage(intended_structs, extracted_structs, mapped, count):
324
+ """Coverage mapping with the explicit sync statement."""
325
+ pinless = sum(1 for n in intended_structs.connectivity.nets if not n.pins)
326
+ pinless += sum(1 for n in extracted_structs.connectivity.nets if not n.pins)
327
+ intended_nets = len(intended_structs.connectivity.nets)
328
+ extracted_nets = len(extracted_structs.connectivity.nets)
329
+ sizes = (
330
+ f"{intended_nets} vs {extracted_nets} nets, {len(mapped)} mapped pins"
331
+ )
332
+ if count == 0:
333
+ statement = (
334
+ "view_sync: intended and extracted are in sync "
335
+ f"(0 findings, {sizes})"
336
+ )
337
+ else:
338
+ noun = "finding" if count == 1 else "findings"
339
+ statement = (
340
+ f"view_sync: {count} {noun}; intended vs extracted out of sync "
341
+ f"({sizes})"
342
+ )
343
+ return {
344
+ "compared_views": ["intended", "extracted"],
345
+ "intended_nets": intended_nets,
346
+ "extracted_nets": extracted_nets,
347
+ "mapped_pins": len(mapped),
348
+ "pinless_nets_skipped": pinless,
349
+ "statement": statement,
350
+ }
351
+
352
+
353
+ def compare_views(intended, extracted, links=None, variant=None):
354
+ """Diff intended vs extracted schematics over shared connectivity.
355
+
356
+ Both views reduce through CONNECT-GRAPH extraction, pins
357
+ correlate through CellLink identity, and ports, connections,
358
+ and unmapped objects diff with per-finding identity
359
+ references; every net name resolves through the cited view's
360
+ `Connectivity.net_name` authority.
361
+
362
+ Args:
363
+ intended: Intended-view schematic record (symbol-pin space;
364
+ see workflows.connectgraph for the shape).
365
+ extracted: Extracted-view schematic record (cell-pin space).
366
+ links: CellLink block links ([{id, CellLink?}]) mapping
367
+ intended symbol pins to extracted cell pins; None or []
368
+ correlates by identity.
369
+ variant: Variant selector applied to every link; None and
370
+ REFERENCE resolve each stored base link.
371
+
372
+ Returns:
373
+ Mapping with findings (sorted by rule, deterministic),
374
+ coverage (compared views, net counts, mapped pins,
375
+ pinless skips, statement), and a text report.
376
+
377
+ Raises:
378
+ ViewSyncError: Malformed schematic (naming its side),
379
+ malformed links, an unknown variant, or a pinMap
380
+ collision.
381
+
382
+ Caution: Optical view comparison, never transistor LVS —
383
+ findings judge connectivity sync only, not device
384
+ equivalence.
385
+ """
386
+ forward, reverse = _identity_maps(links, variant)
387
+ intended_structs = _extract_side(intended, "intended")
388
+ extracted_structs = _extract_side(extracted, "extracted")
389
+ mapped, unmapped = _correlate(
390
+ intended_structs, extracted_structs, forward, reverse
391
+ )
392
+ findings = _port_findings(intended_structs, extracted_structs)
393
+ findings.extend(unmapped)
394
+ findings.extend(_connection_findings(intended_structs, extracted_structs, mapped))
395
+ findings.sort(key=lambda f: (f["rule"], json.dumps(f, sort_keys=True)))
396
+ coverage = _coverage(intended_structs, extracted_structs, mapped, len(findings))
397
+ lines = [coverage["statement"]]
398
+ lines.extend(f"- [{f['rule']}] {f['message']}" for f in findings)
399
+ return {"findings": findings, "coverage": coverage, "report": "\n".join(lines)}
@@ -0,0 +1,200 @@
1
+ Metadata-Version: 2.5
2
+ Name: rocket-engine
3
+ Version: 0.0.2b1
4
+ Summary: Shared tooling engine used by the RocketEDA IDE (manual actions and MCP invoke the same operations).
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
14
+ Requires-Python: >=3.12
15
+ Requires-Dist: amaranth>=0.5.10
16
+ Requires-Dist: anyio>=4.0
17
+ Requires-Dist: cace==2.13.0
18
+ Requires-Dist: circulax
19
+ Requires-Dist: cocotb>=1.9
20
+ Requires-Dist: devsim==2.11.2
21
+ Requires-Dist: fastapi>=0.115
22
+ Requires-Dist: gdsfactory<10,>=9.51
23
+ Requires-Dist: gplugins<3,>=2.1
24
+ Requires-Dist: httpx>=0.27
25
+ Requires-Dist: jsonschema>=4.0
26
+ Requires-Dist: matplotlib>=3.8
27
+ Requires-Dist: mcp<3,>=1.0
28
+ Requires-Dist: meow-sim>=0.15
29
+ Requires-Dist: pydantic>=2.0
30
+ Requires-Dist: pyslang>=12.1.0
31
+ Requires-Dist: pyspice>=1.5
32
+ Requires-Dist: pywellen>=0.25.7
33
+ Requires-Dist: pyyaml>=6
34
+ Requires-Dist: ruamel-yaml>=0.18
35
+ Requires-Dist: sax>=0.18
36
+ Requires-Dist: scikit-rf>=1.0
37
+ Requires-Dist: uvicorn>=0.30
38
+ Requires-Dist: vlsirtools>=7.0.0
39
+ Description-Content-Type: text/markdown
40
+
41
+ <p align="center">
42
+ <img src=".github/assets/rocketide-logo.svg" width="72" height="72" alt="RocketIDE logo">
43
+ </p>
44
+
45
+ <h1 align="center">rocket-engine</h1>
46
+
47
+ <p align="center"><sub>Part of <a href="https://github.com/Team-RocketEDA/RocketIDE"><b>RocketIDE</b></a> · the engine</sub></p>
48
+
49
+ `rocket-engine` is RocketEDA's headless Python engine for chip-design projects. It owns the shared operation surface, project revisions and events, tool dispatch, capability reporting, and verification evidence used by manual clients and the agent harness.
50
+
51
+ The product serves digital, analog, photonic, and mixed-domain work. The engine coordinates existing EDA tools through adapters; it does not implement an agent loop or physics solvers. Product direction lives in the sibling [PRD](../PRD/README.md). The agent harness is in [rocket_fuel](../rocket_fuel/README.md), the current workbench is in [UIUX](../UIUX/README.md), and [RocketIDE](../RocketIDE/README.md) is the planned packaging layer.
52
+
53
+ ## Requirements
54
+
55
+ <!-- REQUIREMENTS:START -->
56
+ pip ships the engine, not the tools. Native binaries, PDK trees,
57
+ and cloud keys arrive via provision recipes, your own PATH, or
58
+ explicit opt-in. The engine resolves provisioned roots first, then
59
+ ambient PATH, then per-job `tool_dir`; `report_capabilities` tells
60
+ you exactly what resolved and the remedy for what did not.
61
+
62
+ ### Native tools (provision or PATH)
63
+
64
+ | Capability | Provides | How to get it |
65
+ |---|---|---|
66
+ | Digital bundle (oss-cad-suite) | `iverilog`, `vvp`, `verilator`, `slang`, `yosys`, `ghdl`, `sby` | scripts/provision_toolchain.sh: pinned tarball 20261025 + asserts (PROV phase 1). |
67
+ | LibreLane (RTL-to-GDS flow) | `librelane` | scripts/provision_toolchain.sh (PROV phase 1; upstream AppImage/Nix install docs). |
68
+ | OpenSTA (static timing) | `sta` | scripts/provision_toolchain.sh (PROV phase 1; upstream OpenSTA README source build). |
69
+ | ngspice (SPICE) | `ngspice` | docs/provision-plan.md: apt pin or source build (B10). |
70
+ | Netgen (LVS) | `netgen` | docs/tickets/NGSPICE-LIVE.md: opencircuitdesign source build (B10). |
71
+ | Magic (DRC + extraction) | `magic` | docs/provision-plan.md: source build with --prefix into the app-owned tools dir (B10). |
72
+ | KLayout (batch DRC) | `klayout` | docs/provision-plan.md: ambient install kept and version-asserted (B10). |
73
+ | Xyce (parallel SPICE) | `Xyce` | scripts/provision_toolchain.sh (PROV phase 2; Xyce building guide recipe). |
74
+ | Xschem (schematic) | `xschem` | scripts/provision_toolchain.sh (PROV phase 2; upstream xschem source build). |
75
+ | Bubblewrap (isolation) | `bwrap` | docs/probe-bwrap-isolation.md (B10). |
76
+ | cvc (SMT solvers) | `cvc4`, `cvc5` | scripts/provision_toolchain.sh: pinned tarball 20261025 ships cvc4/cvc5 (PROV phase 1). |
77
+ | OpenROAD | `openroad` | scripts/provision_toolchain.sh (PROV phase 1; LibreLane closure ships openroad). |
78
+ | openEMS (EC-FDTD) | `openEMS` | scripts/provision_toolchain.sh (PROV-DEFERRED; docs.openEMS.de recipe). |
79
+ | Elmer (thermal/FEM) | `ElmerSolver` | scripts/provision_toolchain.sh (PROV-DEFERRED; CSC PPA apt route). |
80
+ | Palace (full-wave FEM) | `palace` | docs/provision-sources.md §12 (unsourced — no recipe yet). |
81
+
82
+ ### Python libraries (ride the wheel)
83
+
84
+ | Capability | Provides | How to get it |
85
+ |---|---|---|
86
+ | CACE (characterization) | `cace` | scripts/provision_toolchain.sh (PROV phase 2; pip into the engine venv). |
87
+ | SAX (photonic sim) | `sax` | pyproject.toml [project] dependencies: plain `uv sync` installs everything (core library). |
88
+ | Circulax (time-domain circuit sim) | `circulax` | pyproject.toml [project] dependencies: plain `uv sync` installs everything (core library). |
89
+ | Meow (EME mode/field solver) | `meow` | pyproject.toml [project] dependencies: plain `uv sync` installs everything (core library). |
90
+ | gdsfactory (layout views) | `gdsfactory` | pyproject.toml [project] dependencies: plain `uv sync` installs everything (core library). |
91
+ | pymeep (FDTD) | `meep` | scripts/provision_toolchain.sh (PROV-DEFERRED; conda-forge pymeep env). |
92
+ | DEVSIM (TCAD) | `devsim` | scripts/provision_toolchain.sh (PROV-DEFERRED; pip into the engine venv). |
93
+
94
+ ### PDKs (registered trees, never in the wheel)
95
+
96
+ | Capability | Provides | How to get it |
97
+ |---|---|---|
98
+ | PDK sky130A | `sky130A` + 4 decks | scripts/install.sh --pdk-only (PDK_SOURCE/PDK_ID/PDK_REVISION; see docs/demo-runbook.md). |
99
+ | PDK ihp (IHP SG13G2 BiCMOS + RF) | `ihp` + 1 decks | docs/pdk/ihp/recipe.md (PDK-IHP lane). |
100
+
101
+ ### Cloud (opt-in only, never default)
102
+
103
+ | Capability | Provides | How to get it |
104
+ |---|---|---|
105
+ | Tidy3D web (cloud) | BYOC: tidy3d web | CLOUD-AUTH (Backlog): OS keyring preferred, encrypted file fallback. |
106
+ | GDSFactory+ (cloud) | BYOC: gdsfactory+ | CLOUD-AUTH (Backlog): OS keyring preferred, encrypted file fallback. |
107
+ <!-- REQUIREMENTS:END -->
108
+
109
+ ## Current shape
110
+
111
+ - `src/` is the package root and installs as `rocket_engine`.
112
+ - `composition.py` is the composition root. It binds project and execution services, operation/query handlers, and solver adapters.
113
+ - Transports use the same operation vocabulary. The live CLI and MCP server are implemented. HTTP and IPC currently provide JSON envelope handlers; listening servers, SSE delivery, and length-prefixed IPC framing are not implemented here.
114
+ - Project mutations are revision-gated and actor-attributed. A durable project ledger is available when an engine root is configured; an engine without one keeps project state in memory.
115
+ - Engine `submit` runs normal solver operations inline and returns their completion. `run_job` remains the explicit deferred/batch pump and idempotent completion fetch.
116
+ - Tool registration describes what the engine can route. Machine-specific availability and PDK/deck readiness come from `get_capabilities`; registration alone does not mean a flow is qualified or installed.
117
+
118
+ ## Architecture
119
+
120
+ ```text
121
+ UI / CLI / Rocket Fuel
122
+ │
123
+ adapters/{http,ipc,mcp,cli}
124
+ │ commands and queries
125
+ composition.Engine
126
+ ├── project/ revisions, documents, components, events
127
+ ├── execution/ dispatch, isolation, run state, verdicts
128
+ ├── library/ PDK and cell catalogs
129
+ └── workflows/ D/A/P/M check plans and completion gates
130
+ │
131
+ adapters/<solver> ──> native EDA tools and Python libraries
132
+ │
133
+ normalized findings, measurements, artifacts
134
+ ```
135
+
136
+ `interfaces/` defines the shared vocabulary, data shapes, and ports. Transport adapters translate client requests into engine calls. Solver adapters preflight project inputs, invoke tools, and normalize their output. The engine evaluates findings and publishes project events; transports do not own verification rules.
137
+
138
+ | Module | Responsibility |
139
+ |---|---|
140
+ | [`src/interfaces/`](src/interfaces/README.md) | Operation/query vocabulary, contracts, ports, path and design-data types |
141
+ | [`src/project/`](src/project/README.md) | Revision-gated documents, ECS components, snapshots, and event ledger |
142
+ | [`src/execution/`](src/execution/README.md) | Run lifecycle, bounded dispatch, isolation, Python execution approvals, and verdicts |
143
+ | [`src/library/`](src/library/README.md) | PDK registration/readiness and reusable cell catalogs |
144
+ | [`src/workflows/`](src/workflows/README.md) | Digital, analog, photonic, and mixed-domain stage plans and completion checks |
145
+ | [`src/adapters/`](src/adapters/README.md) | CLI, MCP, HTTP/IPC envelope handlers, and solver integrations |
146
+
147
+ ## Registered solver operations
148
+
149
+ | Operations | Adapter(s) |
150
+ |---|---|
151
+ | `run_drc` | Magic (default), KLayout |
152
+ | `run_hdl_test`, `run_syntax`, `run_formal`, `run_synth`, `run_timing` | Icarus, Slang, SBY, Yosys, OpenSTA |
153
+ | `run_spice`, `run_post_layout`, `run_cosim` | ngspice; co-simulation also uses Icarus |
154
+ | `run_optical`, `run_em` | SAX/Circulax, MEOW |
155
+ | `run_extraction`, `run_lvs` | Magic, Netgen |
156
+ | `run_connectivity`, `run_erc`, `run_view_sync` | connectgraph |
157
+ | `generate_views` | GDSFactory |
158
+ | `run_digital_flow` | LibreLane |
159
+
160
+ This is a routing map, not a support guarantee. Consult `get_capabilities` for installed tools, profiles, PDKs, and decks. The LibreLane adapter is registered and has hermetic coverage; its live RTL-to-GDS qualification is currently blocked on the pinned LibreLane distribution and a compatible PDK root. See the [DIGITAL-FLOW report](docs/work/DIGITAL-FLOW/report.md) and the [sprint board](docs/sprint-board.md) for current work status.
161
+
162
+ ## API contract
163
+
164
+ **Next implementation contract:** the [v1 contract bundle](contracts/README.md)
165
+ freezes six methods (`describe`, `query`, `edit`, `run`, `script`, `watch`),
166
+ typed editors/components/testbenches, tool tasks and `canvas.toml`.
167
+ It includes generated client types/help and validated examples. Provider and
168
+ consumer migration is pending; the current running API below is v0.
169
+ [ADR-014](docs/adr/014-contract-first-editor-and-tool-api.md) records the
170
+ supersession and deployment gates. Check the design contract with
171
+ `.venv/bin/python scripts/check_v1_contract.py`.
172
+
173
+
174
+ The operation and query vocabulary is in [`src/interfaces/vocabulary.py`](src/interfaces/vocabulary.py). Handler docstrings are the source for the generated [`docs/engine-api.md`](docs/engine-api.md), [`docs/api-schema.json`](docs/api-schema.json), and [`docs/api-help.json`](docs/api-help.json). Do not hand-edit those generated files; regenerate them with `scripts/api_spec.py --write`.
175
+
176
+ Every accepted mutation checks `expected_revision`, advances the project revision, and records its actor. A stale revision returns `revision_conflict`; callers re-read and retry. Run verdicts are engine-owned. Exit status and tool process output alone never establish PASS.
177
+
178
+ The current MCP bridge derives descriptions from handler docstrings. Its wire input schemas are still generic for most tools; only `python_execute` currently has a specific schema. See [MCP-SCHEMA](docs/tickets/MCP-SCHEMA.md).
179
+
180
+ ## Setup and common commands
181
+
182
+ Use the repository installer as the only supported Python environment setup. It creates the pinned Python 3.12 environment, installs the base and development dependencies, installs a sealed engine copy, registers the configured PDK, and probes selected host tools.
183
+
184
+ ```sh
185
+ scripts/install.sh --install
186
+ .venv/bin/python -m rocket_engine --help
187
+ scripts/install.sh --check-only
188
+ ```
189
+
190
+ Native tool provisioning is documented in [`docs/provision-plan.md`](docs/provision-plan.md) and managed by `scripts/provision_toolchain.sh`. `get_capabilities` reports what is usable on the current machine. After editing `src/`, rerun `scripts/install.sh --install` so the sealed package matches the source tree.
191
+
192
+ For operation docstring and generated-contract conventions, read [`AGENTS.md`](AGENTS.md). It also documents the test and fixture workflow. The [scenario guide](scenarios/README.md) describes live-tool prerequisites and the scenario CLI.
193
+
194
+ ## Where to look next
195
+
196
+ - Project requirements and decisions: [`../PRD/README.md`](../PRD/README.md)
197
+ - Current engine work and open tickets: [`docs/sprint-board.md`](docs/sprint-board.md), [`docs/tickets/`](docs/tickets/)
198
+ - Fuel integration contract: [`docs/fuel-contract.md`](docs/fuel-contract.md)
199
+ - Generated engine API: [`docs/engine-api.md`](docs/engine-api.md)
200
+ - Storage ownership: [`docs/storage-policy.md`](docs/storage-policy.md) and [`docs/adr/`](docs/adr/README.md)