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,18 @@
|
|
|
1
|
+
# workflows — process inventories and completion gates
|
|
2
|
+
|
|
3
|
+
`workflows/` holds the digital, analog, photonic, and mixed-domain verification stages as data. It plans checks and reports whether the requested flow has enough available operations and passing evidence. It never launches a solver.
|
|
4
|
+
|
|
5
|
+
## Current behavior
|
|
6
|
+
|
|
7
|
+
- `stages.py` contains the D/A/P/M inventories and their stage-to-operation mappings.
|
|
8
|
+
- `capability_plan.py` marks stages ready or blocked based on available operations.
|
|
9
|
+
- `completion.py` combines the plan with the latest check records. Missing operations, checks that have not run, and non-PASS verdicts remain blockers; only a blocker-free flow can report fully verified.
|
|
10
|
+
- The stage `when` expressions are descriptive today. The planner currently treats planned stages as required instead of evaluating those expressions to narrow applicability.
|
|
11
|
+
|
|
12
|
+
The same plan and completion reports are served by `plan_checks` and `get_design_completion`, so clients can show the engine's reasons and blockers directly.
|
|
13
|
+
|
|
14
|
+
## Boundaries and routing
|
|
15
|
+
|
|
16
|
+
This module owns stage order, applicability metadata, and completion rules. `composition.Engine` supplies registered operations and check results. Solver inputs and evidence belong to [`adapters/`](../adapters/README.md) and [`execution/`](../execution/README.md); command and result shapes belong to [`interfaces/`](../interfaces/README.md).
|
|
17
|
+
|
|
18
|
+
For the product process source, see the [PRD verification process](../../../PRD/tools-research/verification-process.md) and [workflow catalog](../../../PRD/tools-research/verification-workflows.yaml). For current engine gaps, see the [sprint board](../../docs/sprint-board.md).
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""D/A/P/M step order and check plans as data. Never calls solvers directly."""
|
|
2
|
+
|
|
3
|
+
from .capability_plan import plan_from_capabilities
|
|
4
|
+
from .completion import design_completion_report, plan_checks_report
|
|
5
|
+
from .connectgraph import (
|
|
6
|
+
RULE_DANGLING_NET,
|
|
7
|
+
RULE_ORPHAN_LABEL,
|
|
8
|
+
RULE_SHORT,
|
|
9
|
+
RULE_UNCONNECTED_PIN,
|
|
10
|
+
Connectivity,
|
|
11
|
+
ConnectGraphError,
|
|
12
|
+
Net,
|
|
13
|
+
NetlistStructs,
|
|
14
|
+
ResolvedInstance,
|
|
15
|
+
erc_findings,
|
|
16
|
+
prepare_netlist_structs,
|
|
17
|
+
)
|
|
18
|
+
from .connectgraph_emit import (
|
|
19
|
+
LANGUAGES,
|
|
20
|
+
emit_netlists,
|
|
21
|
+
emit_spice,
|
|
22
|
+
emit_verilog,
|
|
23
|
+
emit_vhdl,
|
|
24
|
+
resolve_format,
|
|
25
|
+
to_raw_ir,
|
|
26
|
+
)
|
|
27
|
+
from .stages import STAGES, applicable_stages
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"STAGES",
|
|
31
|
+
"applicable_stages",
|
|
32
|
+
"plan_from_capabilities",
|
|
33
|
+
"design_completion_report",
|
|
34
|
+
"plan_checks_report",
|
|
35
|
+
"Connectivity",
|
|
36
|
+
"ConnectGraphError",
|
|
37
|
+
"Net",
|
|
38
|
+
"NetlistStructs",
|
|
39
|
+
"ResolvedInstance",
|
|
40
|
+
"erc_findings",
|
|
41
|
+
"prepare_netlist_structs",
|
|
42
|
+
"RULE_SHORT",
|
|
43
|
+
"RULE_UNCONNECTED_PIN",
|
|
44
|
+
"RULE_DANGLING_NET",
|
|
45
|
+
"RULE_ORPHAN_LABEL",
|
|
46
|
+
"LANGUAGES",
|
|
47
|
+
"emit_netlists",
|
|
48
|
+
"emit_spice",
|
|
49
|
+
"emit_verilog",
|
|
50
|
+
"emit_vhdl",
|
|
51
|
+
"resolve_format",
|
|
52
|
+
"to_raw_ir",
|
|
53
|
+
]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Capability-aware stage planning: readiness from tool truth, not wiring.
|
|
2
|
+
|
|
3
|
+
`applicable_stages` plans against a caller-supplied backend set,
|
|
4
|
+
which reads ready whenever an operation is merely wired — M11
|
|
5
|
+
(`run_timing`) planned ready while `sta` was absent. This module
|
|
6
|
+
plans against a `report_capabilities` operations mapping instead:
|
|
7
|
+
a stage is ready only when every tool entrypoint it needs reports
|
|
8
|
+
ready, and a blocked stage carries which entrypoints block it plus
|
|
9
|
+
their reason, missing items, and remedy.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from .stages import _SCRIPTED, STAGES, covering_decks
|
|
13
|
+
|
|
14
|
+
_FALLBACK_REMEDY = "Provision the missing tooling (see docs/provision-plan.md)."
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _stage_decks(stage, operations, solvers):
|
|
18
|
+
"""Covering deck cites for one stage's tool entrypoints.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
stage: Stage inventory entry with entrypoints.
|
|
22
|
+
operations: Per-operation readiness mapping.
|
|
23
|
+
solvers: Operation -> deck-tool cites; None means the
|
|
24
|
+
curated DECKS table.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Deck cites across the stage's tool entrypoints.
|
|
28
|
+
"""
|
|
29
|
+
cites = []
|
|
30
|
+
for entrypoint in stage["entrypoints"]:
|
|
31
|
+
cites.extend(covering_decks(entrypoint, solvers, operations))
|
|
32
|
+
return cites
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def plan_from_capabilities(flow, operations, solvers=None):
|
|
36
|
+
"""Plan a flow against a capabilities report's operations mapping.
|
|
37
|
+
|
|
38
|
+
Scripted entrypoints need no backend. A stage whose tool
|
|
39
|
+
entrypoints all read ready in the report is ready; otherwise it
|
|
40
|
+
stays required-but-blocked (never silently dropped) and names
|
|
41
|
+
the blocking entrypoints with their report reason, missing
|
|
42
|
+
items, and remedy. Entrypoints with no report row block loudly
|
|
43
|
+
with a no-report reason instead of a tool-blind ready. Every
|
|
44
|
+
stage also cites its covering decks (WORKFLOW-COVERAGE, ADR-007)
|
|
45
|
+
so blockers resolve to a deck, a probe-gated deck, or a named
|
|
46
|
+
gap — the completion report reads the same cites per blocker.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
flow: Flow inventory to plan (digital/analog/photonic/mixed).
|
|
50
|
+
operations: Per-operation readiness mapping as reported by
|
|
51
|
+
`report_capabilities` (operation -> readiness plus
|
|
52
|
+
reason/missing/remedy detail).
|
|
53
|
+
solvers: Operation -> deck-tool cites (tool plus needs).
|
|
54
|
+
Defaults to the curated DECKS table.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Stage list with per-stage readiness (ready/blocked) plus
|
|
58
|
+
deck cites; blocked stages also carry blocked_by,
|
|
59
|
+
reason, missing, and remedy keys.
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
ValueError: Unknown flow name.
|
|
63
|
+
"""
|
|
64
|
+
try:
|
|
65
|
+
stages = STAGES[flow]
|
|
66
|
+
except KeyError:
|
|
67
|
+
raise ValueError(f"Unknown flow: {flow}.") from None
|
|
68
|
+
planned = []
|
|
69
|
+
for stage in stages:
|
|
70
|
+
needed = [e for e in stage["entrypoints"] if e not in _SCRIPTED]
|
|
71
|
+
decks = _stage_decks(stage, operations, solvers)
|
|
72
|
+
blocking = [
|
|
73
|
+
e for e in needed
|
|
74
|
+
if operations.get(e, {}).get("readiness") != "ready"
|
|
75
|
+
]
|
|
76
|
+
if not blocking:
|
|
77
|
+
planned.append({**stage, "readiness": "ready", "decks": decks})
|
|
78
|
+
continue
|
|
79
|
+
reasons, missing, remedies = [], [], []
|
|
80
|
+
for entry in blocking:
|
|
81
|
+
row = operations.get(entry, {})
|
|
82
|
+
if entry not in operations:
|
|
83
|
+
reasons.append(
|
|
84
|
+
f"{entry}: no capability report on this machine."
|
|
85
|
+
)
|
|
86
|
+
missing.append(entry)
|
|
87
|
+
continue
|
|
88
|
+
reasons.append(f"{entry}: {row.get('reason', 'not ready.')}")
|
|
89
|
+
missing.extend(row.get("missing") or [])
|
|
90
|
+
remedy = row.get("remedy")
|
|
91
|
+
if remedy and remedy not in remedies:
|
|
92
|
+
remedies.append(remedy)
|
|
93
|
+
planned.append({
|
|
94
|
+
**stage,
|
|
95
|
+
"readiness": "blocked",
|
|
96
|
+
"blocked_by": blocking,
|
|
97
|
+
"reason": "; ".join(reasons),
|
|
98
|
+
"missing": sorted(set(missing)),
|
|
99
|
+
"remedy": " ".join(remedies) if remedies else _FALLBACK_REMEDY,
|
|
100
|
+
"decks": decks,
|
|
101
|
+
})
|
|
102
|
+
return planned
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""Design-completion gate: stage plans plus fully-verified claims (I27).
|
|
2
|
+
|
|
3
|
+
`plan_checks_report` wires the stage inventory to caller backends so
|
|
4
|
+
required-but-blocked stages surface instead of vanishing; every
|
|
5
|
+
planned stage stays required and reports ready or blocked with its
|
|
6
|
+
missing operations. `design_completion_report` layers the latest
|
|
7
|
+
check verdicts over that plan: any blocked, unverified, or failing
|
|
8
|
+
stage becomes a named blocker (mixed M14 cites run_thermal, and the
|
|
9
|
+
vocab-only run_thermal operation appears as its own blocker), the
|
|
10
|
+
report refuses the fully-verified claim while any stand, and only
|
|
11
|
+
an all-satisfied plan claims with per-operation evidence run ids.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .gates import gate_plan_for_target
|
|
15
|
+
from .stages import applicable_stages
|
|
16
|
+
|
|
17
|
+
# Scripted entrypoints need no backend (mirrors stages._SCRIPTED).
|
|
18
|
+
_SCRIPTED = frozenset({"project scripting", "get_capabilities", "ip_instantiate"})
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _tool_ops(stage):
|
|
22
|
+
"""Tool entrypoints one stage needs (scripted entries excluded)."""
|
|
23
|
+
return [e for e in stage["entrypoints"] if e not in _SCRIPTED]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _missing_ops(stage, available):
|
|
27
|
+
"""Tool entrypoints one stage needs but no backend serves."""
|
|
28
|
+
return [e for e in _tool_ops(stage) if e not in available]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _check_status(record):
|
|
32
|
+
"""Verdict status for one check record (None when never ran)."""
|
|
33
|
+
if record is None:
|
|
34
|
+
return None
|
|
35
|
+
if not isinstance(record, dict):
|
|
36
|
+
return "unknown"
|
|
37
|
+
status = record.get("status")
|
|
38
|
+
if status is None:
|
|
39
|
+
verdict = record.get("verdict")
|
|
40
|
+
if isinstance(verdict, dict):
|
|
41
|
+
status = verdict.get("status")
|
|
42
|
+
return status if status is not None else "unknown"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _run_id(record):
|
|
46
|
+
"""String run id for one check record (None when absent)."""
|
|
47
|
+
if isinstance(record, dict) and isinstance(record.get("run_id"), str):
|
|
48
|
+
return record["run_id"]
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def plan_checks_report(flow, available_backends, target=None, canvas=None):
|
|
53
|
+
"""Plan one flow against installed backends with named blockers.
|
|
54
|
+
|
|
55
|
+
Thin report over `applicable_stages`: every planned stage keeps
|
|
56
|
+
its required flag and gains its readiness plus the exact missing
|
|
57
|
+
operations, so a caller can name required-but-blocked stages
|
|
58
|
+
(mixed M14 cites run_thermal) instead of silently dropping them.
|
|
59
|
+
With a target (plus an optional canvas) the plan is additionally
|
|
60
|
+
gated per `gates.gate_plan_for_target`, joining deck tools,
|
|
61
|
+
canvas settings, and metric budgets to every stage.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
flow: Flow inventory to plan (digital/analog/photonic/mixed).
|
|
65
|
+
available_backends: Installed backend entrypoint names.
|
|
66
|
+
target: v1 target the plan serves (kind required); None
|
|
67
|
+
skips gating and returns the backend-only plan.
|
|
68
|
+
canvas: Canvas mapping with targets/tools; None means an
|
|
69
|
+
empty canvas (a canvas without a target refuses).
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Mapping with the flow, per-stage plans (each carrying
|
|
73
|
+
readiness plus missing_operations), blocked_stages and
|
|
74
|
+
ready_stages id lists in stage order, the sorted
|
|
75
|
+
unique missing_operations across blocked stages, and —
|
|
76
|
+
when gated — the target/canvas join.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
ValueError: Unknown flow name, a canvas without a target,
|
|
80
|
+
or a bad target/canvas shape.
|
|
81
|
+
"""
|
|
82
|
+
available = set() if available_backends is None else set(available_backends)
|
|
83
|
+
planned = applicable_stages(flow, available)
|
|
84
|
+
stages = []
|
|
85
|
+
for stage in planned:
|
|
86
|
+
stages.append({**stage, "missing_operations": _missing_ops(stage, available)})
|
|
87
|
+
blocked = [s["id"] for s in stages if s["readiness"] == "blocked"]
|
|
88
|
+
ready = [s["id"] for s in stages if s["readiness"] == "ready"]
|
|
89
|
+
missing = sorted({op for stage in stages for op in stage["missing_operations"]})
|
|
90
|
+
plan = {
|
|
91
|
+
"flow": flow,
|
|
92
|
+
"stages": stages,
|
|
93
|
+
"blocked_stages": blocked,
|
|
94
|
+
"ready_stages": ready,
|
|
95
|
+
"missing_operations": missing,
|
|
96
|
+
}
|
|
97
|
+
if target is None and canvas is None:
|
|
98
|
+
return plan
|
|
99
|
+
if target is None:
|
|
100
|
+
raise ValueError("plan_checks canvas needs a target.")
|
|
101
|
+
return gate_plan_for_target(plan, target, canvas)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def design_completion_report(flow, available_backends, checks, current_revision=None):
|
|
105
|
+
"""Judge one flow's completion: blockers stand or evidence claims.
|
|
106
|
+
|
|
107
|
+
Combines the stage plan with the latest check verdicts. A stage
|
|
108
|
+
whose backends are missing blocks as blocked_stage; a ready tool
|
|
109
|
+
stage whose operation never ran blocks as unverified_stage; a
|
|
110
|
+
ready stage whose latest verdict is not PASS blocks as
|
|
111
|
+
failing_check with its run id. Missing operations additionally
|
|
112
|
+
appear as missing_operation blockers so vocab-only names such as
|
|
113
|
+
run_thermal never vanish silently. Scripted-only stages need no
|
|
114
|
+
solver evidence and never block. While any blocker stands the
|
|
115
|
+
report refuses the claim (fully_verified False, claim None);
|
|
116
|
+
only a blocker-free plan claims fully verified with evidence.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
flow: Flow inventory to judge (digital/analog/photonic/mixed).
|
|
120
|
+
available_backends: Installed backend entrypoint names.
|
|
121
|
+
checks: Mapping of operation to its latest check record
|
|
122
|
+
(the checks value from Engine.check_results: each with
|
|
123
|
+
status plus run_id); absent operations read never_run.
|
|
124
|
+
current_revision: Project revision to echo; None when unknown.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Mapping with the flow, fully_verified flag, claim (fully
|
|
128
|
+
verified) or refusal text, blockers in stage order with
|
|
129
|
+
missing-operation entries after, sorted unique
|
|
130
|
+
missing_operations, evidence mapping each PASS operation
|
|
131
|
+
to its run id, per-stage plans carrying stage_status plus
|
|
132
|
+
run_ids, and the echoed current_revision.
|
|
133
|
+
|
|
134
|
+
Raises:
|
|
135
|
+
ValueError: Unknown flow name.
|
|
136
|
+
"""
|
|
137
|
+
available = set() if available_backends is None else set(available_backends)
|
|
138
|
+
seen = dict(checks) if checks is not None else {}
|
|
139
|
+
plan = plan_checks_report(flow, available)
|
|
140
|
+
blockers = []
|
|
141
|
+
stages_out = []
|
|
142
|
+
for stage in plan["stages"]:
|
|
143
|
+
tool_ops = _tool_ops(stage)
|
|
144
|
+
missing = stage["missing_operations"]
|
|
145
|
+
if missing:
|
|
146
|
+
blockers.append(
|
|
147
|
+
{
|
|
148
|
+
"kind": "blocked_stage",
|
|
149
|
+
"stage": stage["id"],
|
|
150
|
+
"step": stage["step"],
|
|
151
|
+
"missing_operations": list(missing),
|
|
152
|
+
"required": stage["required"],
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
stages_out.append({**stage, "stage_status": "blocked", "run_ids": {}})
|
|
156
|
+
continue
|
|
157
|
+
if not tool_ops:
|
|
158
|
+
stages_out.append({**stage, "stage_status": "verified", "run_ids": {}})
|
|
159
|
+
continue
|
|
160
|
+
run_ids = {}
|
|
161
|
+
failing = []
|
|
162
|
+
unverified = []
|
|
163
|
+
for op in tool_ops:
|
|
164
|
+
record = seen.get(op)
|
|
165
|
+
if op not in seen:
|
|
166
|
+
unverified.append(
|
|
167
|
+
{
|
|
168
|
+
"kind": "unverified_stage",
|
|
169
|
+
"stage": stage["id"],
|
|
170
|
+
"step": stage["step"],
|
|
171
|
+
"operation": op,
|
|
172
|
+
"status": "never_run",
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
continue
|
|
176
|
+
status = _check_status(record)
|
|
177
|
+
rid = _run_id(record)
|
|
178
|
+
if rid is not None:
|
|
179
|
+
run_ids[op] = rid
|
|
180
|
+
if status == "PASS":
|
|
181
|
+
continue
|
|
182
|
+
failing.append(
|
|
183
|
+
{
|
|
184
|
+
"kind": "failing_check",
|
|
185
|
+
"stage": stage["id"],
|
|
186
|
+
"step": stage["step"],
|
|
187
|
+
"operation": op,
|
|
188
|
+
"status": status,
|
|
189
|
+
"run_id": rid,
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
blockers.extend(failing)
|
|
193
|
+
blockers.extend(unverified)
|
|
194
|
+
if failing:
|
|
195
|
+
stage_status = "failing"
|
|
196
|
+
elif unverified:
|
|
197
|
+
stage_status = "unverified"
|
|
198
|
+
else:
|
|
199
|
+
stage_status = "verified"
|
|
200
|
+
stages_out.append({**stage, "stage_status": stage_status, "run_ids": run_ids})
|
|
201
|
+
for op in plan["missing_operations"]:
|
|
202
|
+
stages_needing = sorted(
|
|
203
|
+
s["id"] for s in plan["stages"] if op in s["missing_operations"]
|
|
204
|
+
)
|
|
205
|
+
blockers.append(
|
|
206
|
+
{"kind": "missing_operation", "operation": op, "stages": stages_needing}
|
|
207
|
+
)
|
|
208
|
+
evidence = {}
|
|
209
|
+
for op in sorted(available):
|
|
210
|
+
record = seen.get(op)
|
|
211
|
+
if _check_status(record) == "PASS":
|
|
212
|
+
rid = _run_id(record)
|
|
213
|
+
if rid is not None:
|
|
214
|
+
evidence[op] = rid
|
|
215
|
+
fully_verified = not blockers
|
|
216
|
+
return {
|
|
217
|
+
"flow": flow,
|
|
218
|
+
"fully_verified": fully_verified,
|
|
219
|
+
"claim": "fully verified" if fully_verified else None,
|
|
220
|
+
"refusal": None
|
|
221
|
+
if fully_verified
|
|
222
|
+
else f"{len(blockers)} blocker(s) stand; not fully verified.",
|
|
223
|
+
"blockers": blockers,
|
|
224
|
+
"missing_operations": plan["missing_operations"],
|
|
225
|
+
"evidence": evidence,
|
|
226
|
+
"stages": stages_out,
|
|
227
|
+
"current_revision": current_revision,
|
|
228
|
+
}
|