dizzy.engine.ports¶
dizzy.engine.ports
¶
The ports an engine shell consumes — the seam that de-apps the shells.
A scheduling shell (dizzy.engine.st, dizzy.engine.mp) decides who
holds the command
queue, who runs the workers, and where telemetry lands. It must decide those
things without knowing a single command name, event name, or environment
field. Everything app-specific therefore arrives through one object:
HostApp
.graph the FeatGraph — the declared topology, resolved
.build_runtime() build this process's Engine (the app's wiring)
.routes() command -> (pool, message options) [optional]
.otel tracing/metrics/propagation provider [optional]
.origin_for() correlation to carry on a dispatch [optional]
.on_command_done() the app's post-command hook [optional]
.span_attrs() origin -> tracing attributes [optional]
The shell finds the HostApp through $DIZZY_HOST_APP (module:attr), so a
worker process boots from environment alone — no app import in the shell's
source. Everything but graph and build_runtime has a null default, so
a minimal app supplies two things.
CommandQueue
¶
Bases: Protocol
Where a policy's dispatch goes. The engine holds one of these.
Source code in dizzy/src/dizzy/engine/ports.py
39 40 41 42 43 44 45 | |
TelemetryBus
¶
Bases: Protocol
Host-level observation — never events, never load-bearing.
Source code in dizzy/src/dizzy/engine/ports.py
48 49 50 51 52 | |
NullOtel
¶
Satisfies the tracing surface a shell uses, doing nothing.
Source code in dizzy/src/dizzy/engine/ports.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | |
ShellServices
dataclass
¶
The shell's side of the contract, passed to build_runtime.
The app builds its Engine around these: dispatches go to command_queue, observations to publish. Telemetry sinks are the app's to construct — a sink that must cross the process boundary is just one that closes over publish, which keeps the shell ignorant of the app's payload shapes.
Source code in dizzy/src/dizzy/engine/ports.py
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | |
observer = _noop_observer
class-attribute
instance-attribute
¶
The SHELL's event observer, which the app MUST call from whatever observer it passes to its engine builder.
The engine takes exactly one observer, so an app that installs its own
without chaining this one silently unplugs the shell: mp collects the
events a command emitted here, and on_command_done receives that list.
Dropping it degrades every result to "no events emitted" rather than
failing, which is why it is stated as a requirement and not a nicety.
Use :func:chain_observers if you have nothing app-specific to add.
Runtime
dataclass
¶
One process's live engine, as the app built it.
Source code in dizzy/src/dizzy/engine/ports.py
159 160 161 162 163 164 165 166 167 168 169 170 | |
session = None
class-attribute
instance-attribute
¶
The read-model session, when there is one — the shell rolls it back after a failed command so a partial fold can't leak into the next.
refresh = lambda: None
class-attribute
instance-attribute
¶
Re-hydrate mutable environment before each command (secrets can change
under a long-lived worker). Derive the field list from
graph.environment rather than listing it.
HostApp
dataclass
¶
Everything a scheduling shell needs to run an app it knows nothing about.
Source code in dizzy/src/dizzy/engine/ports.py
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | |
routes = dict
class-attribute
instance-attribute
¶
command name -> (pool, broker message options). Unlisted commands go to the default pool. Where the route table COMES from — a manifest, a config file, a constant — is the app's business, not a shell's.
origin_for = _no_origin
class-attribute
instance-attribute
¶
(current_event, command_being_dispatched) -> correlation string, or None for the default. Lets an app thread its own causality (e.g. a tool call's identity) through a dispatch without the shell knowing those names.
on_command_done = _no_hook
class-attribute
instance-attribute
¶
(origin, status, detail, emitted) after a command finishes — the app's place to close out whatever origin referred to.
Returning TRUTHY on a failure means "handled": the app turned the failure into a fact, so the shell must not also let the broker retry the side effect. A falsy return re-raises, keeping at-least-once delivery.
span_attrs = _no_attrs
class-attribute
instance-attribute
¶
origin -> extra tracing attributes. Whatever an app encodes in an origin string is the app's to decode, but a shell that simply dropped it would make traces unsearchable by the app's own identifiers — so the decoding gets a door rather than being deleted.
resolve(spec=None)
staticmethod
¶
Load the app manifest named by spec or $DIZZY_HOST_APP.
Spec form is module:attr; attr may be a HostApp or a
zero-argument callable returning one (the usual choice — it defers the
app's imports to worker-boot time).
Source code in dizzy/src/dizzy/engine/ports.py
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | |
chain_observers(*observers)
¶
Compose observers into the one the engine accepts, in order.
Source code in dizzy/src/dizzy/engine/ports.py
122 123 124 125 126 127 128 129 | |
null_app(build_runtime, feat_path=None)
¶
The minimal HostApp: a feat file and a way to build the engine.
Source code in dizzy/src/dizzy/engine/ports.py
270 271 272 273 274 | |