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,246 @@
|
|
|
1
|
+
"""MCP pull path over the cursor event log (ADR-017 D7).
|
|
2
|
+
|
|
3
|
+
The MCP port is pull-by-default: the client polls the existing
|
|
4
|
+
cursor log from a stale cursor and converges, never waiting on a
|
|
5
|
+
server push. Push stays a per-port opt-in: subscribing without
|
|
6
|
+
the explicit flag is refused, never silently armed.
|
|
7
|
+
|
|
8
|
+
Position dedupe reuses the bus-owned PositionGuard (the one
|
|
9
|
+
shared helper every port applies through): the pull path reads
|
|
10
|
+
the shared cursor log through the wired get_events_since query
|
|
11
|
+
every transport serves, so there is no second event shape and
|
|
12
|
+
no duplicated seam — receiving one page twice re-renders the
|
|
13
|
+
same state.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from ...execution.ports import PositionGuard
|
|
17
|
+
from .. import api
|
|
18
|
+
from ..errors import AdapterError
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def poll_events(engine, project_id, cursor, require_contiguous_from=None,
|
|
22
|
+
request_id=None):
|
|
23
|
+
"""Poll one page of ledger events after a cursor.
|
|
24
|
+
|
|
25
|
+
The poll rides the wired get_events_since query — the same
|
|
26
|
+
cursor log every transport shares — so a stale cursor
|
|
27
|
+
converges with no diff reconstruction and no snapshot
|
|
28
|
+
pinning.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
engine: Engine the MCP port reads through.
|
|
32
|
+
project_id: Project the cursor belongs to.
|
|
33
|
+
cursor: Only events with a higher seq are returned; 0
|
|
34
|
+
replays the retained log.
|
|
35
|
+
require_contiguous_from: Assert the reader holds
|
|
36
|
+
contiguous history from this seq; an unmet demand
|
|
37
|
+
fails with resync_required instead of gap-hiding.
|
|
38
|
+
request_id: Envelope id; minted when omitted.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Page mapping with the events after the cursor, oldest
|
|
42
|
+
first, plus the live cursor.
|
|
43
|
+
"""
|
|
44
|
+
arguments = {"cursor": cursor}
|
|
45
|
+
if require_contiguous_from is not None:
|
|
46
|
+
arguments["require_contiguous_from"] = require_contiguous_from
|
|
47
|
+
return api.submit(engine, project_id, "get_events_since",
|
|
48
|
+
arguments, request_id=request_id)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class McpPullClient:
|
|
52
|
+
"""Pull-by-default MCP cursor over one project's event log.
|
|
53
|
+
|
|
54
|
+
The client holds its cursor and reuses the bus-owned
|
|
55
|
+
PositionGuard for position-check-then-apply, so
|
|
56
|
+
same-position redelivery applies once through the one
|
|
57
|
+
shared helper every port uses — never a per-client
|
|
58
|
+
reinvention. Bind the port's bus guard (guard_for) and
|
|
59
|
+
port name and the pull path shares one dedupe record
|
|
60
|
+
with the push path. Polling advances the cursor; a
|
|
61
|
+
failed contiguity demand resyncs from the snapshot plus
|
|
62
|
+
the full retained log and resets the position, never
|
|
63
|
+
skipping over a trimmed gap.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
engine: Engine the MCP port reads through.
|
|
67
|
+
project_id: Project the cursor belongs to.
|
|
68
|
+
cursor: Last consumed ledger position; 0 replays the
|
|
69
|
+
retained log.
|
|
70
|
+
guard: PositionGuard to check positions against; the
|
|
71
|
+
port's bound bus guard when the MCP port is
|
|
72
|
+
bus-attached, a client-owned guard otherwise.
|
|
73
|
+
port: Port name positions apply under; the attached
|
|
74
|
+
port name for a bus-bound guard, the project id
|
|
75
|
+
otherwise.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(self, engine, project_id, cursor=0, guard=None,
|
|
79
|
+
port=None):
|
|
80
|
+
self._engine = engine
|
|
81
|
+
self._project_id = project_id
|
|
82
|
+
self._cursor = cursor
|
|
83
|
+
self._applied = cursor
|
|
84
|
+
self._guard = guard if guard is not None else PositionGuard()
|
|
85
|
+
self._owns_guard = guard is None
|
|
86
|
+
self._port = port if port is not None else project_id
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def cursor(self):
|
|
90
|
+
"""Last consumed ledger position.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Cursor the next poll reads after.
|
|
94
|
+
"""
|
|
95
|
+
return self._cursor
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def applied_position(self):
|
|
99
|
+
"""Highest ledger position this client handed over.
|
|
100
|
+
|
|
101
|
+
The guard stays the dedupe authority (it also records
|
|
102
|
+
positions the push path applied); this is the client's
|
|
103
|
+
own high-water mark for cursor bookkeeping.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Seq of the last applied event, or the starting
|
|
107
|
+
cursor when nothing applied yet.
|
|
108
|
+
"""
|
|
109
|
+
return self._applied
|
|
110
|
+
|
|
111
|
+
def poll(self, require_contiguous=False, request_id=None):
|
|
112
|
+
"""Poll the next page after the stored cursor.
|
|
113
|
+
|
|
114
|
+
A stale cursor converges: the page carries every
|
|
115
|
+
retained event after it, and the stored cursor advances
|
|
116
|
+
to the live head. With require_contiguous, the poll
|
|
117
|
+
asserts the reader holds contiguous history from
|
|
118
|
+
cursor + 1; a fresh cursor (0) skips the demand because
|
|
119
|
+
an empty log cannot be non-contiguous, and an unmet
|
|
120
|
+
demand resyncs instead of gap-hiding.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
require_contiguous: Assert contiguous history from
|
|
124
|
+
cursor + 1 and resync when the demand cannot
|
|
125
|
+
be met (a trimmed gap).
|
|
126
|
+
request_id: Envelope id; minted when omitted.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Page mapping with events, the live cursor, and
|
|
130
|
+
whether a resync served it.
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
ProjectError: invalid_command for a malformed
|
|
134
|
+
cursor. An unmet contiguity demand never escapes
|
|
135
|
+
— it resyncs instead.
|
|
136
|
+
"""
|
|
137
|
+
demand = self._cursor + 1 if require_contiguous and self._cursor else None
|
|
138
|
+
try:
|
|
139
|
+
page = poll_events(self._engine, self._project_id,
|
|
140
|
+
self._cursor,
|
|
141
|
+
require_contiguous_from=demand,
|
|
142
|
+
request_id=request_id)
|
|
143
|
+
except Exception as exc:
|
|
144
|
+
if getattr(exc, "code", None) != "resync_required":
|
|
145
|
+
raise
|
|
146
|
+
return self.resync(request_id=request_id)
|
|
147
|
+
self._cursor = page["cursor"]
|
|
148
|
+
return {"events": page["events"], "cursor": page["cursor"],
|
|
149
|
+
"resynced": False}
|
|
150
|
+
|
|
151
|
+
def apply(self, events, handler):
|
|
152
|
+
"""Apply one page idempotently: position check, then apply.
|
|
153
|
+
|
|
154
|
+
The check runs through the bus-owned PositionGuard, so
|
|
155
|
+
a position the push path already applied (or this page
|
|
156
|
+
before) applies once per port. Events are offered in
|
|
157
|
+
seq order; events without an integer seq carry no
|
|
158
|
+
ledger position, so the guard cannot admit them and
|
|
159
|
+
they are skipped. A raising handler leaves its
|
|
160
|
+
position unrecorded, so redelivery retries it.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
events: Page of ledger events, oldest first.
|
|
164
|
+
handler: Called once per newly positioned event.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Count of events handed to the handler.
|
|
168
|
+
"""
|
|
169
|
+
ordered = sorted(
|
|
170
|
+
(e for e in events if isinstance(e.get("seq"), int)
|
|
171
|
+
and not isinstance(e.get("seq"), bool)),
|
|
172
|
+
key=lambda e: e["seq"],
|
|
173
|
+
)
|
|
174
|
+
applied = 0
|
|
175
|
+
for event in ordered:
|
|
176
|
+
done, _ = self._guard.apply_once(
|
|
177
|
+
self._port, event["seq"], handler, event)
|
|
178
|
+
if not done:
|
|
179
|
+
continue
|
|
180
|
+
if event["seq"] > self._applied:
|
|
181
|
+
self._applied = event["seq"]
|
|
182
|
+
applied += 1
|
|
183
|
+
return applied
|
|
184
|
+
|
|
185
|
+
def resync(self, request_id=None):
|
|
186
|
+
"""Resync from the snapshot plus the full retained log.
|
|
187
|
+
|
|
188
|
+
Drops the stale position, re-reads the live head, and
|
|
189
|
+
replays the retained log from 0 so the caller
|
|
190
|
+
re-renders current state. The applied position resets
|
|
191
|
+
so the replayed page applies in full through apply;
|
|
192
|
+
running the onboarding ritual twice stays safe. A
|
|
193
|
+
client-owned guard is replaced with a fresh one; a
|
|
194
|
+
bus-bound guard is left alone — bus resync rebinds
|
|
195
|
+
through the bus (a new onboarding, per ADR-017), so
|
|
196
|
+
the shared dedupe record is never wiped here.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
request_id: Envelope id; minted when omitted.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
Page mapping with the full retained events, the
|
|
203
|
+
live cursor, and resynced True.
|
|
204
|
+
"""
|
|
205
|
+
self._cursor = 0
|
|
206
|
+
self._applied = 0
|
|
207
|
+
if self._owns_guard:
|
|
208
|
+
self._guard = PositionGuard()
|
|
209
|
+
page = poll_events(self._engine, self._project_id, 0,
|
|
210
|
+
request_id=request_id)
|
|
211
|
+
self._cursor = page["cursor"]
|
|
212
|
+
return {"events": page["events"], "cursor": page["cursor"],
|
|
213
|
+
"resynced": True}
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def subscribe_push(runtime, send, enable_push=False):
|
|
217
|
+
"""Push lifecycle events to one subscriber, opt-in only.
|
|
218
|
+
|
|
219
|
+
Pull is the default; this is the per-port push escape hatch
|
|
220
|
+
(ADR-017 D7). Without the explicit flag the call is
|
|
221
|
+
refused and no listener is registered — the AI wakes on
|
|
222
|
+
its own polls, never on UI churn.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
runtime: EngineRuntime emitting lifecycle events.
|
|
226
|
+
send: Called synchronously with each built
|
|
227
|
+
notification mapping.
|
|
228
|
+
enable_push: Explicit opt-in; push stays off unless
|
|
229
|
+
this is True.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Unsubscribe callable removing the listener.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
AdapterError: unsupported_operation when push was not
|
|
236
|
+
explicitly opted into.
|
|
237
|
+
"""
|
|
238
|
+
if not enable_push:
|
|
239
|
+
raise AdapterError(
|
|
240
|
+
"unsupported_operation",
|
|
241
|
+
"MCP push is opt-in only (ADR-017 D7): pass "
|
|
242
|
+
"enable_push=True, or keep polling the cursor log.",
|
|
243
|
+
)
|
|
244
|
+
from .server import subscribe_runtime
|
|
245
|
+
|
|
246
|
+
return subscribe_runtime(runtime, send)
|