tigrbl-kernel 0.1.0__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.
tigrbl_kernel/atoms.py ADDED
@@ -0,0 +1,237 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib
4
+ import inspect
5
+ import logging
6
+ import pkgutil
7
+ from types import SimpleNamespace
8
+ from typing import (
9
+ Any,
10
+ Callable,
11
+ Dict,
12
+ Iterable,
13
+ List,
14
+ Mapping,
15
+ Optional,
16
+ Sequence,
17
+ cast,
18
+ )
19
+
20
+ from tigrbl_typing.phases import HOOK_PHASES as HOOK_PHASES
21
+
22
+ from tigrbl_atoms import StepFn
23
+ from . import events as _ev, ordering as _ordering
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ _AtomRun = Callable[[Optional[object], Any], Any]
28
+ _DiscoveredAtom = tuple[str, _AtomRun]
29
+
30
+
31
+ def _discover_atoms() -> list[_DiscoveredAtom]:
32
+ out: list[_DiscoveredAtom] = []
33
+ try:
34
+ import tigrbl_atoms.atoms as atoms_pkg # type: ignore
35
+ except Exception:
36
+ return out
37
+
38
+ for info in pkgutil.walk_packages(atoms_pkg.__path__, atoms_pkg.__name__ + "."): # type: ignore[attr-defined]
39
+ if info.ispkg:
40
+ continue
41
+ try:
42
+ mod = importlib.import_module(info.name)
43
+ instance = getattr(mod, "INSTANCE", None)
44
+ if instance is not None and callable(instance):
45
+ anchor = getattr(instance, "anchor", None) or getattr(
46
+ mod, "ANCHOR", None
47
+ )
48
+ if isinstance(anchor, str):
49
+ out.append((anchor, cast(_AtomRun, instance)))
50
+ continue
51
+ anchor = getattr(mod, "ANCHOR", None)
52
+ run = getattr(mod, "run", None)
53
+ if isinstance(anchor, str) and callable(run):
54
+ out.append((anchor, cast(_AtomRun, run)))
55
+ except Exception:
56
+ continue
57
+ logger.debug("kernel: discovered %d atoms", len(out))
58
+ return out
59
+
60
+
61
+ def _infer_domain_subject(run: _AtomRun) -> tuple[Optional[str], Optional[str]]:
62
+ mod = getattr(run, "__module__", "") or ""
63
+ parts = mod.split(".")
64
+ try:
65
+ i = parts.index("atoms")
66
+ return (
67
+ parts[i + 1] if i + 1 < len(parts) else None,
68
+ parts[i + 2] if i + 2 < len(parts) else None,
69
+ )
70
+ except ValueError:
71
+ return None, None
72
+
73
+
74
+ def _make_label(anchor: str, run: _AtomRun) -> Optional[str]:
75
+ domain, subject = _infer_domain_subject(run)
76
+ return f"atom:{domain}:{subject}@{anchor}" if (domain and subject) else None
77
+
78
+
79
+ def _wrap_atom(run: _AtomRun, *, anchor: str) -> StepFn:
80
+ use_two_args = True
81
+ try:
82
+ params = tuple(inspect.signature(run).parameters.values())
83
+ positional = [
84
+ p
85
+ for p in params
86
+ if p.kind
87
+ in (
88
+ inspect.Parameter.POSITIONAL_ONLY,
89
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
90
+ )
91
+ ]
92
+ use_two_args = len(positional) != 1
93
+ except (TypeError, ValueError):
94
+ use_two_args = True
95
+
96
+ async def _step(ctx: Any) -> Any:
97
+ rv = run(None, ctx) if use_two_args else run(ctx) # type: ignore[misc]
98
+ if inspect.isawaitable(rv):
99
+ return await cast(Any, rv)
100
+ return rv
101
+
102
+ label = getattr(run, "__tigrbl_label", None)
103
+ if not isinstance(label, str):
104
+ label = _make_label(anchor, run)
105
+ if label:
106
+ setattr(_step, "__tigrbl_label", label)
107
+ return _step
108
+
109
+
110
+ def _hook_phase_chains(model: type, alias: str) -> Dict[str, List[StepFn]]:
111
+ hooks_root = getattr(model, "hooks", None) or SimpleNamespace()
112
+ alias_ns = getattr(hooks_root, alias, None)
113
+ out: Dict[str, List[StepFn]] = {ph: [] for ph in HOOK_PHASES}
114
+ if alias_ns is None:
115
+ return out
116
+ for phase in HOOK_PHASES:
117
+ out[phase] = list(getattr(alias_ns, phase, []) or [])
118
+ return out
119
+
120
+
121
+ def _is_persistent(chains: Mapping[str, Sequence[StepFn]]) -> bool:
122
+ for fn in chains.get("START_TX", ()) or ():
123
+ if getattr(fn, "__name__", "") == "start_tx":
124
+ return True
125
+ for fn in chains.get("PRE_TX_BEGIN", ()) or ():
126
+ if getattr(fn, "__name__", "") == "mark_skip_persist":
127
+ return False
128
+ return False
129
+
130
+
131
+ def _label_dep_atom(*, kind: str, index: int, anchor: str) -> str:
132
+ return f"hook:dep:{kind}:{index}@{anchor}"
133
+
134
+
135
+ def _make_dep_atom_step(run_fn: _AtomRun, dep: Any, *, label: str) -> StepFn:
136
+ async def _step(ctx: Any) -> Any:
137
+ rv = run_fn(dep, ctx)
138
+ if hasattr(rv, "__await__"):
139
+ return await cast(Any, rv)
140
+ return rv
141
+
142
+ setattr(_step, "__tigrbl_label", label)
143
+ return _step
144
+
145
+
146
+ def _inject_pre_tx_dep_atoms(chains: Dict[str, List[StepFn]], sp: Any | None) -> None:
147
+ if sp is None:
148
+ return
149
+ try:
150
+ from tigrbl_atoms.atoms.dep.security import INSTANCE as sec_run # type: ignore
151
+ from tigrbl_atoms.atoms.dep.extra import INSTANCE as dep_run # type: ignore
152
+ except Exception:
153
+ try:
154
+ from tigrbl_atoms.atoms.dep.security import run as sec_run # type: ignore
155
+ from tigrbl_atoms.atoms.dep.extra import run as dep_run # type: ignore
156
+ except Exception:
157
+ return
158
+
159
+ pre_tx = chains.setdefault("PRE_TX_BEGIN", [])
160
+ for idx, dep in enumerate(getattr(sp, "secdeps", ()) or ()):
161
+ pre_tx.append(
162
+ _make_dep_atom_step(
163
+ sec_run,
164
+ dep,
165
+ label=_label_dep_atom(
166
+ kind="security", index=idx, anchor=_ev.DEP_SECURITY
167
+ ),
168
+ )
169
+ )
170
+ for idx, dep in enumerate(getattr(sp, "deps", ()) or ()):
171
+ pre_tx.append(
172
+ _make_dep_atom_step(
173
+ dep_run,
174
+ dep,
175
+ label=_label_dep_atom(kind="extra", index=idx, anchor=_ev.DEP_EXTRA),
176
+ )
177
+ )
178
+
179
+
180
+ def _inject_atoms(
181
+ chains: Dict[str, List[StepFn]],
182
+ atoms: Iterable[_DiscoveredAtom],
183
+ *,
184
+ persistent: bool,
185
+ target: str | None = None,
186
+ ) -> None:
187
+ order = {name: i for i, name in enumerate(_ev.all_events_ordered())}
188
+
189
+ def _sort_key(item: _DiscoveredAtom) -> tuple[int, int]:
190
+ anchor, run = item
191
+ anchor_idx = order.get(anchor, 10_000)
192
+ domain, subject = _infer_domain_subject(run)
193
+ token = f"{domain}:{subject}" if domain and subject else ""
194
+ pref = _ordering._PREF.get(anchor, ())
195
+ token_idx = pref.index(token) if token in pref else 10_000
196
+ return anchor_idx, token_idx
197
+
198
+ for anchor, run in sorted(atoms, key=_sort_key):
199
+ if _ev.is_valid_event(anchor):
200
+ info = _ev.get_anchor_info(anchor)
201
+ phase = info.phase
202
+ persist_tied = info.persist_tied
203
+ elif anchor == "INGRESS_ROUTE":
204
+ # Back-compat phase alias retained for route-stage atom injection.
205
+ phase = "INGRESS_ROUTE"
206
+ persist_tied = False
207
+ elif anchor in _ev.PHASES:
208
+ phase = anchor
209
+ persist_tied = False
210
+ elif anchor == "INGRESS_ROUTE":
211
+ # Compatibility alias retained for tests and legacy direct callers.
212
+ # Canonical runtime ingress routing phase is INGRESS_DISPATCH.
213
+ phase = anchor
214
+ persist_tied = False
215
+ else:
216
+ continue
217
+
218
+ domain, _subject = _infer_domain_subject(run)
219
+ if not persistent and persist_tied:
220
+ if not (
221
+ domain == "sys"
222
+ and isinstance(_subject, str)
223
+ and _subject.startswith("handler_")
224
+ ):
225
+ continue
226
+ if (
227
+ domain == "sys"
228
+ and isinstance(_subject, str)
229
+ and _subject.startswith("handler_")
230
+ ):
231
+ handler_target = _subject.removeprefix("handler_")
232
+ if handler_target != "persistence" and target and handler_target != target:
233
+ continue
234
+ if domain == "dep":
235
+ continue
236
+
237
+ chains.setdefault(phase, []).append(_wrap_atom(run, anchor=anchor))
tigrbl_kernel/cache.py ADDED
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ import threading
4
+ import weakref
5
+ from typing import Any, Dict, Generic, Mapping, Optional, Sequence, TypeVar
6
+
7
+ from tigrbl_core._spec.column_spec import mro_collect_columns
8
+
9
+ K = TypeVar("K")
10
+ V = TypeVar("V")
11
+
12
+
13
+ class _WeakMaybeDict(Generic[K, V]):
14
+ """Dictionary that uses weak references when possible.
15
+
16
+ Falls back to strong references when ``key`` cannot be weakly referenced.
17
+ """
18
+
19
+ def __init__(self) -> None:
20
+ self._weak: "weakref.WeakKeyDictionary[Any, V]" = weakref.WeakKeyDictionary()
21
+ self._strong: Dict[int, tuple[Any, V]] = {}
22
+
23
+ def _use_weak(self, key: Any) -> bool:
24
+ try:
25
+ weakref.ref(key)
26
+ return True
27
+ except TypeError:
28
+ return False
29
+
30
+ def __setitem__(self, key: K, value: V) -> None:
31
+ if self._use_weak(key):
32
+ self._weak[key] = value
33
+ else:
34
+ self._strong[id(key)] = (key, value)
35
+
36
+ def __getitem__(self, key: K) -> V:
37
+ if self._use_weak(key):
38
+ return self._weak[key]
39
+ return self._strong[id(key)][1]
40
+
41
+ def get(self, key: K, default: Optional[V] = None) -> Optional[V]:
42
+ if self._use_weak(key):
43
+ return self._weak.get(key, default)
44
+ return self._strong.get(id(key), (None, default))[1]
45
+
46
+ def setdefault(self, key: K, default: V) -> V:
47
+ if self._use_weak(key):
48
+ return self._weak.setdefault(key, default)
49
+ return self._strong.setdefault(id(key), (key, default))[1]
50
+
51
+ def pop(self, key: K, default: Optional[V] = None) -> Optional[V]:
52
+ if self._use_weak(key):
53
+ return self._weak.pop(key, default)
54
+ return self._strong.pop(id(key), (None, default))[1]
55
+
56
+
57
+ class _SpecsOnceCache:
58
+ """Thread-safe, compute-once cache of per-model column specs."""
59
+
60
+ def __init__(self) -> None:
61
+ self._d: Dict[type, Mapping[str, Any]] = {}
62
+ self._lock = threading.Lock()
63
+
64
+ def get(self, model: type) -> Mapping[str, Any]:
65
+ try:
66
+ return self._d[model]
67
+ except KeyError:
68
+ pass
69
+ with self._lock:
70
+ rv = self._d.get(model)
71
+ if rv is None:
72
+ rv = mro_collect_columns(model)
73
+ self._d[model] = rv
74
+ return rv
75
+
76
+ def prime(self, models: Sequence[type]) -> None:
77
+ for model in models:
78
+ self.get(model)
79
+
80
+ def invalidate(self, model: Optional[type] = None) -> None:
81
+ with self._lock:
82
+ if model is None:
83
+ self._d.clear()
84
+ else:
85
+ self._d.pop(model, None)
tigrbl_kernel/core.py ADDED
@@ -0,0 +1,186 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import threading
5
+ from types import SimpleNamespace
6
+ from typing import Any, ClassVar, Mapping, Optional, Sequence
7
+
8
+
9
+ from . import events as _ev
10
+ from ._build import (
11
+ _build_route_matrix,
12
+ _pack_kernel_plan,
13
+ _segment_label,
14
+ _build,
15
+ _build_egress,
16
+ _build_ingress,
17
+ _build_op,
18
+ _compile_bootstrap_plan,
19
+ _plan_labels,
20
+ )
21
+ from ._compile import _compile_opview_from_specs, _compile_plan
22
+ from .atoms import _DiscoveredAtom, _discover_atoms
23
+ from .cache import _SpecsOnceCache, _WeakMaybeDict
24
+ from .models import KernelPlan, OpView
25
+ from .opview_compiler import compile_opview_from_specs
26
+ from .types import DEFAULT_PHASE_ORDER as _DEFAULT_PHASE_ORDER
27
+ from .utils import (
28
+ _opspecs,
29
+ _table_iter,
30
+ )
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ DEFAULT_PHASE_ORDER = tuple(getattr(_ev, "PHASES", ())) or _DEFAULT_PHASE_ORDER
36
+
37
+
38
+ class Kernel:
39
+ _instance: ClassVar["Kernel | None"] = None
40
+
41
+ def __new__(cls, *args: Any, **kwargs: Any) -> "Kernel":
42
+ if cls._instance is None:
43
+ cls._instance = super().__new__(cls)
44
+ return cls._instance
45
+
46
+ def __init__(self, atoms: Optional[Sequence[_DiscoveredAtom]] = None):
47
+ if atoms is None and getattr(self, "_singleton_initialized", False):
48
+ self._reset(atoms)
49
+ return
50
+ self._reset(atoms)
51
+ if atoms is None:
52
+ self._singleton_initialized = True
53
+
54
+ def _reset(self, atoms: Optional[Sequence[_DiscoveredAtom]] = None) -> None:
55
+ self._atoms_cache = list(atoms) if atoms else None
56
+ self._specs_cache = _SpecsOnceCache()
57
+ self._opviews = _WeakMaybeDict()
58
+ self._phase_chains = _WeakMaybeDict()
59
+ self._phase_chains_by_id: dict[int, dict[str, tuple[Any, Any]]] = {}
60
+ self._kernel_plans = _WeakMaybeDict()
61
+ self._kernelz_payload = _WeakMaybeDict()
62
+ self._primed = _WeakMaybeDict()
63
+ self._lock = threading.Lock()
64
+
65
+ def _atoms(self) -> list[_DiscoveredAtom]:
66
+ if self._atoms_cache is None:
67
+ self._atoms_cache = _discover_atoms()
68
+ return self._atoms_cache
69
+
70
+ def get_specs(self, model: type) -> Mapping[str, Any]:
71
+ return self._specs_cache.get(model)
72
+
73
+ def plan_labels(self, model: type, alias: str) -> list[str]:
74
+ return self._plan_labels(model, alias)
75
+
76
+ def prime_specs(self, models: Sequence[type]) -> None:
77
+ self._specs_cache.prime(models)
78
+
79
+ def invalidate_specs(self, model: Optional[type] = None) -> None:
80
+ self._specs_cache.invalidate(model)
81
+
82
+ def ensure_primed(self, app: Any) -> None:
83
+ if self._primed.get(app):
84
+ return
85
+ with self._lock:
86
+ if self._primed.get(app):
87
+ return
88
+ self.prime_specs(_table_iter(app))
89
+ self._kernel_plans.pop(app, None)
90
+ self._kernelz_payload.pop(app, None)
91
+ self._opviews.pop(app, None)
92
+ self._phase_chains.pop(app, None)
93
+ self._phase_chains_by_id.clear()
94
+ self._primed[app] = True
95
+
96
+ def get_opview(self, app: Any, model: type, alias: str) -> OpView:
97
+ ov_map = self._opviews.get(app)
98
+ if isinstance(ov_map, dict):
99
+ opview = ov_map.get((model, alias))
100
+ if opview is not None:
101
+ return opview
102
+
103
+ self.ensure_primed(app)
104
+
105
+ ov_map = self._opviews.setdefault(app, {})
106
+ opview = ov_map.get((model, alias))
107
+ if opview is not None:
108
+ return opview
109
+
110
+ try:
111
+ specs = self._specs_cache.get(model)
112
+ found = False
113
+ for sp in _opspecs(model):
114
+ ov_map.setdefault(
115
+ (model, sp.alias), compile_opview_from_specs(specs, sp)
116
+ )
117
+ if sp.alias == alias:
118
+ found = True
119
+
120
+ if not found:
121
+ temp_sp = SimpleNamespace(alias=alias)
122
+ ov_map[(model, alias)] = compile_opview_from_specs(specs, temp_sp)
123
+
124
+ return ov_map[(model, alias)]
125
+ except Exception as exc:
126
+ raise RuntimeError(
127
+ f"opview_missing: app={app!r} model={getattr(model, '__name__', model)!r} alias={alias!r}"
128
+ ) from exc
129
+
130
+ def kernel_plan(self, app: Any) -> KernelPlan:
131
+ self.ensure_primed(app)
132
+ plan = self._kernel_plans.get(app)
133
+ if isinstance(plan, KernelPlan):
134
+ return plan
135
+
136
+ compiled = self.compile_plan(app)
137
+ self._kernel_plans[app] = compiled
138
+
139
+ payload: dict[str, dict[str, list[str]]] = {}
140
+ for model in _table_iter(app):
141
+ model_name = getattr(model, "__name__", str(model))
142
+ payload[model_name] = {}
143
+ for sp in _opspecs(model):
144
+ payload[model_name][sp.alias] = self._plan_labels(model, sp.alias)
145
+ self._kernelz_payload[app] = payload
146
+
147
+ return compiled
148
+
149
+ def kernelz_payload(self, app: Any) -> dict[str, dict[str, list[str]]]:
150
+ self.kernel_plan(app)
151
+ payload = self._kernelz_payload.get(app)
152
+ if isinstance(payload, dict):
153
+ return payload
154
+ return {}
155
+
156
+ def invalidate_kernelz_payload(self, app: Optional[Any] = None) -> None:
157
+ with self._lock:
158
+ if app is None:
159
+ self._kernel_plans = _WeakMaybeDict()
160
+ self._kernelz_payload = _WeakMaybeDict()
161
+ self._opviews = _WeakMaybeDict()
162
+ self._phase_chains = _WeakMaybeDict()
163
+ self._phase_chains_by_id = {}
164
+ self._primed = _WeakMaybeDict()
165
+ else:
166
+ self._kernel_plans.pop(app, None)
167
+ self._kernelz_payload.pop(app, None)
168
+ self._opviews.pop(app, None)
169
+ self._phase_chains.pop(app, None)
170
+ self._phase_chains_by_id.clear()
171
+ self._primed.pop(app, None)
172
+
173
+
174
+ Kernel._build_op = _build_op
175
+ Kernel._build = _build
176
+ Kernel._build_ingress = _build_ingress
177
+ Kernel._build_egress = _build_egress
178
+ Kernel._plan_labels = _plan_labels
179
+ Kernel._compile_bootstrap_plan = _compile_bootstrap_plan
180
+ Kernel._segment_label = _segment_label
181
+ Kernel._build_route_matrix = _build_route_matrix
182
+ Kernel._pack_kernel_plan = _pack_kernel_plan
183
+
184
+ Kernel.compile_plan = _compile_plan
185
+ Kernel.compile_bootstrap_plan = _compile_bootstrap_plan
186
+ Kernel._compile_opview_from_specs = _compile_opview_from_specs
@@ -0,0 +1,6 @@
1
+ """Compatibility wrapper for canonical runtime event anchors.
2
+
3
+ Canonical event anchors and ordering now live in ``tigrbl_atoms.events``.
4
+ """
5
+
6
+ from tigrbl_atoms.events import * # noqa: F403
@@ -0,0 +1,165 @@
1
+ from __future__ import annotations
2
+
3
+ import inspect
4
+ import logging
5
+ from typing import Any, Iterable, Mapping, Optional, Sequence
6
+
7
+ try:
8
+ from tigrbl_kernel import trace as _trace # type: ignore
9
+ except Exception: # pragma: no cover
10
+ _trace = None # type: ignore
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def _normalize_payload(payload: Any) -> Any:
16
+ if isinstance(payload, (str, int, float, bool)) or payload is None:
17
+ return payload
18
+ if isinstance(payload, dict):
19
+ return {str(k): _normalize_payload(v) for k, v in payload.items()}
20
+ if isinstance(payload, (list, tuple, set)):
21
+ return [_normalize_payload(v) for v in payload]
22
+
23
+ model_dump = getattr(payload, "model_dump", None)
24
+ if callable(model_dump):
25
+ try:
26
+ return _normalize_payload(model_dump())
27
+ except Exception:
28
+ pass
29
+
30
+ obj_dict = getattr(payload, "__dict__", None)
31
+ if isinstance(obj_dict, dict):
32
+ data = {
33
+ k: v
34
+ for k, v in obj_dict.items()
35
+ if not k.startswith("_") and not callable(v)
36
+ }
37
+ if data:
38
+ return _normalize_payload(data)
39
+
40
+ return str(payload)
41
+
42
+
43
+ async def _maybe_await(v: Any) -> Any:
44
+ if inspect.isawaitable(v):
45
+ return await v # type: ignore[func-returns-value]
46
+ return v
47
+
48
+
49
+ def _trace_ready(ctx: Any) -> bool:
50
+ if _trace is None:
51
+ return False
52
+ temp = getattr(ctx, "temp", None)
53
+ return isinstance(temp, dict) and "__trace__" in temp
54
+
55
+
56
+ async def _run_chain(ctx: Any, chain: Optional[Iterable[Any]], *, phase: str) -> None:
57
+ temp = getattr(ctx, "temp", None)
58
+ if isinstance(temp, dict) and temp.get("rpc_short_circuit"):
59
+ if phase not in {"EGRESS_SHAPE", "EGRESS_FINALIZE", "POST_RESPONSE"}:
60
+ return
61
+
62
+ if not chain:
63
+ return
64
+
65
+ isawaitable = inspect.isawaitable
66
+ trace_active = _trace_ready(ctx)
67
+
68
+ for idx, step in enumerate(chain):
69
+ label = getattr(step, "__tigrbl_label", None)
70
+ if not isinstance(label, str) or not label:
71
+ label = f"phase:{phase}:step:{idx}"
72
+
73
+ seq = _trace.start(ctx, label) if trace_active else None
74
+ before_post_response = None
75
+ if phase == "POST_RESPONSE":
76
+ response = getattr(ctx, "response", None)
77
+ before_value = getattr(response, "result", None)
78
+ if before_value is None:
79
+ before_value = ctx.get("result")
80
+ before_post_response = _normalize_payload(before_value)
81
+
82
+ try:
83
+ rv = step(ctx)
84
+ if isawaitable(rv):
85
+ rv = await rv # type: ignore[func-returns-value]
86
+ if rv is not None and rv is not ctx:
87
+ ctx.result = rv
88
+ if trace_active:
89
+ _trace.end(ctx, seq, status=_trace.OK)
90
+
91
+ if (
92
+ phase == "POST_RESPONSE"
93
+ and getattr(step, "__tigrbl_label", None) is None
94
+ ):
95
+ temp_ns = getattr(ctx, "temp", None)
96
+ if not isinstance(temp_ns, dict):
97
+ continue
98
+
99
+ egress = temp_ns.get("egress")
100
+ if not isinstance(egress, dict):
101
+ continue
102
+
103
+ response = getattr(ctx, "response", None)
104
+ result = getattr(response, "result", None)
105
+ if result is None:
106
+ result = ctx.get("result")
107
+ else:
108
+ ctx.result = result
109
+
110
+ if result is None:
111
+ continue
112
+ if hasattr(result, "status_code") and hasattr(result, "body"):
113
+ continue
114
+ if isinstance(result, dict) and any(
115
+ key in result for key in ("status_code", "headers", "body")
116
+ ):
117
+ continue
118
+
119
+ safe_result = _normalize_payload(result)
120
+ if safe_result == before_post_response:
121
+ continue
122
+
123
+ egress["wire_payload"] = safe_result
124
+ enveloped = egress.get("enveloped")
125
+ if isinstance(enveloped, dict) and "result" in enveloped:
126
+ enveloped["result"] = safe_result
127
+ elif enveloped is not None and not isinstance(enveloped, dict):
128
+ egress["enveloped"] = safe_result
129
+
130
+ transport_response = egress.get("transport_response")
131
+ if isinstance(transport_response, dict):
132
+ transport_response["body"] = egress.get("enveloped", safe_result)
133
+ except Exception as exc:
134
+ temp = getattr(ctx, "temp", None)
135
+ route = temp.get("route") if isinstance(temp, dict) else None
136
+ rpc_env = route.get("rpc_envelope") if isinstance(route, dict) else None
137
+ if isinstance(rpc_env, Mapping):
138
+ ctx.status_code = 200
139
+ ctx.result = None
140
+ if isinstance(temp, dict):
141
+ temp["rpc_short_circuit"] = True
142
+ if not isinstance(temp.get("rpc_error"), dict):
143
+ builder = ctx.get("rpc_error_builder")
144
+ if callable(builder):
145
+ try:
146
+ temp["rpc_error"] = builder(exc)
147
+ except Exception:
148
+ temp["rpc_error"] = {"message": str(exc)}
149
+ else:
150
+ temp["rpc_error"] = {"message": str(exc)}
151
+ if trace_active:
152
+ _trace.attach_error(ctx, seq, exc)
153
+ _trace.end(ctx, seq, status=_trace.ERROR)
154
+ return
155
+ if trace_active:
156
+ _trace.attach_error(ctx, seq, exc)
157
+ _trace.end(ctx, seq, status=_trace.ERROR)
158
+ raise
159
+
160
+
161
+ def _g(phases: Optional[Mapping[str, Sequence[Any]]], key: str) -> Sequence[Any]:
162
+ return () if not phases else phases.get(key, ())
163
+
164
+
165
+ __all__ = ["_maybe_await", "_run_chain", "_g"]
@@ -0,0 +1,10 @@
1
+ """Kernel-owned hook type definitions.
2
+
3
+ The kernel compiles plans and phase chains, but does not execute them.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from tigrbl_atoms import HookPhase, HookPhases, StepFn
9
+
10
+ __all__ = ["HookPhase", "HookPhases", "StepFn"]