tigrbl-kernel 0.4.1.dev3__py3-none-any.whl → 0.4.2.dev3__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/_build.py CHANGED
@@ -597,6 +597,11 @@ def _program_has_exact_http_like_no_input_binding(
597
597
 
598
598
 
599
599
  def _step_has_route_binding(step: StepFn) -> bool:
600
+ for candidate in (step, getattr(step, "__tigrbl_direct_run", None)):
601
+ endpoint = getattr(candidate, "__tigrbl_websocket_endpoint__", None)
602
+ path = getattr(candidate, "__tigrbl_websocket_path__", None)
603
+ if callable(endpoint) and isinstance(path, str) and path:
604
+ return True
600
605
  closure = getattr(step, "__closure__", None)
601
606
  if not closure:
602
607
  return False
@@ -0,0 +1,186 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from tigrbl_core._spec.binding_spec import normalize_exchange
7
+
8
+
9
+ CONTRACT_CHANNELS: tuple[str, ...] = ("receive", "send")
10
+ CONTRACT_SCOPE_TYPES: tuple[str, ...] = ("http", "websocket", "webtransport")
11
+ CONTRACT_DIRECTIONS: tuple[str, ...] = (
12
+ "client_to_server",
13
+ "server_to_client",
14
+ "app_to_server",
15
+ "server_to_app",
16
+ "system",
17
+ )
18
+ CONTRACT_FAMILIES: tuple[str, ...] = (
19
+ "request",
20
+ "session",
21
+ "message",
22
+ "stream",
23
+ "datagram",
24
+ )
25
+
26
+ CONTRACT_BINDING_ALIASES: dict[str, tuple[str, ...]] = {
27
+ "rest": ("http.rest", "https.rest"),
28
+ "jsonrpc": ("http.jsonrpc", "https.jsonrpc"),
29
+ "http.stream": ("http.stream", "https.stream"),
30
+ "sse": ("http.sse", "https.sse"),
31
+ "websocket": ("ws", "wss"),
32
+ "webtransport": ("webtransport",),
33
+ }
34
+
35
+ CONTRACT_EXCHANGE_ALIASES: dict[str, str] = {
36
+ "unary": "request_response",
37
+ "duplex": "bidirectional_stream",
38
+ "client_stream": "client_stream",
39
+ "server_stream": "server_stream",
40
+ "fire_and_forget": "fire_and_forget",
41
+ }
42
+
43
+ CANONICAL_CONTRACT_EVENTS: tuple[str, ...] = (
44
+ "http.request",
45
+ "http.disconnect",
46
+ "http.response.start",
47
+ "http.response.body",
48
+ "http.response.pathsend",
49
+ "websocket.connect",
50
+ "websocket.receive",
51
+ "websocket.disconnect",
52
+ "websocket.accept",
53
+ "websocket.send",
54
+ "websocket.close",
55
+ "webtransport.connect",
56
+ "webtransport.accept",
57
+ "webtransport.stream.receive",
58
+ "webtransport.stream.send",
59
+ "webtransport.stream.close",
60
+ "webtransport.stream.reset",
61
+ "webtransport.stream.stop_sending",
62
+ "webtransport.datagram.receive",
63
+ "webtransport.datagram.send",
64
+ "webtransport.disconnect",
65
+ "webtransport.close",
66
+ "transport.emit.complete",
67
+ "transport.emit.failed",
68
+ )
69
+
70
+ _EVENT_SCOPE_PREFIXES: dict[str, str] = {
71
+ "http.": "http",
72
+ "websocket.": "websocket",
73
+ "webtransport.": "webtransport",
74
+ "transport.emit.": "webtransport",
75
+ }
76
+
77
+
78
+ @dataclass(frozen=True, slots=True)
79
+ class ContractClassificationProjection:
80
+ event: str
81
+ channel: str
82
+ scope_type: str
83
+ binding: str
84
+ local_binding_kinds: tuple[str, ...]
85
+ family: str
86
+ contract_exchange: str
87
+ local_exchange: str
88
+ direction: str
89
+ allowed_framings: tuple[str, ...]
90
+ required_payload_fields: tuple[str, ...]
91
+
92
+
93
+ def project_contract_classification(row: dict[str, Any]) -> ContractClassificationProjection:
94
+ if "subsurface" in row:
95
+ raise ValueError("contract classifications must not use subsurface")
96
+
97
+ event = _required_str(row, "event")
98
+ channel = _required_str(row, "channel")
99
+ scope_type = _required_str(row, "scope_type")
100
+ binding = _required_str(row, "binding")
101
+ family = _required_str(row, "family")
102
+ exchange = _required_str(row, "exchange")
103
+ direction = _required_str(row, "direction")
104
+
105
+ if event not in CANONICAL_CONTRACT_EVENTS:
106
+ raise ValueError(f"unsupported contract event {event!r}")
107
+ if channel not in CONTRACT_CHANNELS:
108
+ raise ValueError(f"unsupported contract channel {channel!r}")
109
+ if scope_type not in CONTRACT_SCOPE_TYPES:
110
+ raise ValueError(f"unsupported contract scope_type {scope_type!r}")
111
+ if not _event_matches_scope(event=event, scope_type=scope_type):
112
+ raise ValueError(f"contract event {event!r} does not match scope_type {scope_type!r}")
113
+ if family not in CONTRACT_FAMILIES:
114
+ raise ValueError(f"unsupported contract family {family!r}")
115
+ if direction not in CONTRACT_DIRECTIONS:
116
+ raise ValueError(f"unsupported contract direction {direction!r}")
117
+ if binding not in CONTRACT_BINDING_ALIASES:
118
+ raise ValueError(f"unsupported contract binding {binding!r}")
119
+ if scope_type == "webtransport" and family == "message":
120
+ raise ValueError("WebTransport message is not a native transport family")
121
+
122
+ try:
123
+ local_exchange = normalize_exchange(CONTRACT_EXCHANGE_ALIASES[exchange])
124
+ except KeyError as exc:
125
+ raise ValueError(f"unsupported contract exchange {exchange!r}") from exc
126
+
127
+ return ContractClassificationProjection(
128
+ event=event,
129
+ channel=channel,
130
+ scope_type=scope_type,
131
+ binding=binding,
132
+ local_binding_kinds=CONTRACT_BINDING_ALIASES[binding],
133
+ family=family,
134
+ contract_exchange=exchange,
135
+ local_exchange=local_exchange,
136
+ direction=direction,
137
+ allowed_framings=_string_tuple(row.get("allowed_framings", ())),
138
+ required_payload_fields=_string_tuple(row.get("required_payload_fields", ())),
139
+ )
140
+
141
+
142
+ def is_supported_contract_classification(row: dict[str, Any]) -> bool:
143
+ try:
144
+ project_contract_classification(row)
145
+ except ValueError:
146
+ return False
147
+ return True
148
+
149
+
150
+ def _required_str(row: dict[str, Any], key: str) -> str:
151
+ value = row.get(key)
152
+ if not isinstance(value, str) or not value:
153
+ raise ValueError(f"contract classification requires string {key!r}")
154
+ return value
155
+
156
+
157
+ def _string_tuple(value: Any) -> tuple[str, ...]:
158
+ if value is None:
159
+ return ()
160
+ if not isinstance(value, (list, tuple)):
161
+ raise ValueError("contract classification list fields must be sequences")
162
+ result = tuple(str(item) for item in value)
163
+ if any(not item for item in result):
164
+ raise ValueError("contract classification list fields must not contain blanks")
165
+ return result
166
+
167
+
168
+ def _event_matches_scope(*, event: str, scope_type: str) -> bool:
169
+ for prefix, expected_scope_type in _EVENT_SCOPE_PREFIXES.items():
170
+ if event.startswith(prefix):
171
+ return scope_type == expected_scope_type
172
+ return False
173
+
174
+
175
+ __all__ = [
176
+ "CANONICAL_CONTRACT_EVENTS",
177
+ "CONTRACT_BINDING_ALIASES",
178
+ "CONTRACT_CHANNELS",
179
+ "CONTRACT_DIRECTIONS",
180
+ "CONTRACT_EXCHANGE_ALIASES",
181
+ "CONTRACT_FAMILIES",
182
+ "CONTRACT_SCOPE_TYPES",
183
+ "ContractClassificationProjection",
184
+ "is_supported_contract_classification",
185
+ "project_contract_classification",
186
+ ]
@@ -3,26 +3,43 @@ from __future__ import annotations
3
3
  from collections.abc import Mapping
4
4
  from typing import Any
5
5
 
6
+ from tigrbl_core._spec.binding_spec import (
7
+ validate_app_framing_for_binding,
8
+ validate_binding_profile_exchange,
9
+ validate_webtransport_inner_framing,
10
+ validate_webtransport_lane_exchange,
11
+ webtransport_lane_for_profile,
12
+ webtransport_runtime_family,
13
+ )
14
+
6
15
 
7
16
  def _unsupported(message: str) -> ValueError:
8
17
  return ValueError(f"binding protocol unsupported before runtime: {message}")
9
18
 
10
19
 
11
20
  def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dict[str, object]:
12
- kind = binding.get("kind")
21
+ kind = binding.get("kind") or binding.get("proto")
13
22
  if not kind:
14
23
  raise ValueError(
15
24
  "BindingSpec binding source is required; transport guessing is ambiguous"
16
25
  )
17
26
 
18
27
  kind = str(kind)
28
+ profile = binding.get("profile")
29
+ if kind in {"http", "https"} and profile:
30
+ kind = f"{kind}.{profile}"
31
+ elif kind == "websocket":
32
+ kind = str(binding.get("proto") or "ws")
19
33
  framing = binding.get("framing")
20
34
  rows: tuple[dict[str, str], ...]
21
35
 
22
- if kind == "http.rest":
23
- if framing not in (None, "json"):
24
- raise _unsupported("http.rest only supports json framing")
25
- family = "response"
36
+ if kind in {"http.rest", "https.rest"}:
37
+ validate_binding_profile_exchange(
38
+ binding_kind=kind,
39
+ exchange=str(binding.get("exchange") or "request_response"),
40
+ )
41
+ validate_app_framing_for_binding(binding_kind=kind, framing=str(framing or "json"))
42
+ family = "request"
26
43
  framing = "json"
27
44
  anchors = (
28
45
  "ingress.receive",
@@ -31,13 +48,18 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
31
48
  "transport.emit_complete",
32
49
  )
33
50
  rows = (
34
- {"family": "response", "subevent": "request.received"},
35
- {"family": "response", "subevent": "response.emit"},
51
+ {"family": "request", "subevent": "request.received"},
52
+ {"family": "request", "subevent": "response.emit"},
36
53
  )
37
- elif kind == "http.jsonrpc":
54
+ elif kind in {"http.jsonrpc", "https.jsonrpc"}:
38
55
  if not binding.get("rpc_method"):
39
56
  raise _unsupported("http.jsonrpc requires rpc_method")
40
- family = "response"
57
+ validate_binding_profile_exchange(
58
+ binding_kind=kind,
59
+ exchange=str(binding.get("exchange") or "request_response"),
60
+ )
61
+ validate_app_framing_for_binding(binding_kind=kind, framing=str(framing or "jsonrpc"))
62
+ family = "request"
41
63
  framing = "jsonrpc"
42
64
  anchors = (
43
65
  "framing.decode",
@@ -46,18 +68,28 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
46
68
  "framing.encode",
47
69
  )
48
70
  rows = (
49
- {"family": "response", "subevent": "request.received"},
50
- {"family": "response", "subevent": "response.emit"},
71
+ {"family": "request", "subevent": "request.received"},
72
+ {"family": "request", "subevent": "response.emit"},
51
73
  )
52
- elif kind == "http.stream":
74
+ elif kind in {"http.stream", "https.stream"}:
75
+ validate_binding_profile_exchange(
76
+ binding_kind=kind,
77
+ exchange=str(binding.get("exchange") or "server_stream"),
78
+ )
79
+ validate_app_framing_for_binding(binding_kind=kind, framing=str(framing or "stream"))
53
80
  family = "stream"
54
- framing = "stream"
81
+ framing = str(framing or "stream")
55
82
  anchors = ("handler.invoke", "transport.emit", "transport.emit_complete")
56
83
  rows = (
57
84
  {"family": "stream", "subevent": "stream.chunk"},
58
85
  {"family": "stream", "subevent": "stream.close"},
59
86
  )
60
- elif kind == "http.sse":
87
+ elif kind in {"http.sse", "https.sse"}:
88
+ validate_binding_profile_exchange(
89
+ binding_kind=kind,
90
+ exchange=str(binding.get("exchange") or "server_stream"),
91
+ )
92
+ validate_app_framing_for_binding(binding_kind=kind, framing=str(framing or "sse"))
61
93
  family = "stream"
62
94
  framing = "sse"
63
95
  anchors = (
@@ -67,15 +99,25 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
67
99
  "transport.emit_complete",
68
100
  )
69
101
  rows = (
70
- {"family": "event_stream", "subevent": "message.encoded"},
71
- {"family": "event_stream", "subevent": "message.emit"},
102
+ {"family": "stream", "subevent": "message.encoded"},
103
+ {"family": "stream", "subevent": "message.emit"},
72
104
  {"family": "stream", "subevent": "stream.close"},
73
105
  )
74
- elif kind in {"ws", "websocket"}:
106
+ elif kind in {"ws", "wss", "websocket"}:
75
107
  if binding.get("methods"):
76
108
  raise _unsupported("websocket bindings do not accept HTTP methods")
77
109
  family = "message"
78
110
  framing = str(framing or "text")
111
+ subprotocols = tuple(str(item).lower() for item in binding.get("subprotocols", ()))
112
+ validate_binding_profile_exchange(
113
+ binding_kind="wss" if kind == "wss" else "ws",
114
+ exchange=str(binding.get("exchange") or "bidirectional_stream"),
115
+ )
116
+ validate_app_framing_for_binding(
117
+ binding_kind="wss" if kind == "wss" else "ws",
118
+ framing=framing,
119
+ subprotocols=subprotocols,
120
+ )
79
121
  anchors = (
80
122
  "transport.accept",
81
123
  "framing.decode",
@@ -91,32 +133,120 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
91
133
  elif kind == "webtransport":
92
134
  if binding.get("exchange") == "request_response":
93
135
  raise _unsupported("webtransport request_response exchange")
94
- family = "session"
95
- framing = "webtransport"
96
- anchors = (
97
- "transport.accept",
98
- "dispatch.subevent.derive",
99
- "handler.invoke",
100
- "transport.close",
136
+ validate_app_framing_for_binding(binding_kind=kind, framing=str(framing or "webtransport"))
137
+ if framing and str(framing) != "webtransport":
138
+ raise _unsupported("webtransport outer framing must remain webtransport")
139
+ lane = webtransport_lane_for_profile(
140
+ binding.get("lane") or binding.get("profile") or "webtransport"
101
141
  )
102
- rows = (
103
- {"family": "session", "subevent": "session.open"},
104
- {"family": "session", "subevent": "session.close"},
142
+ validate_webtransport_lane_exchange(
143
+ lane=lane,
144
+ exchange=str(binding.get("exchange") or {
145
+ "session": "bidirectional_stream",
146
+ "bidi_stream": "bidirectional_stream",
147
+ "unidi_client_stream": "client_stream",
148
+ "unidi_server_stream": "server_stream",
149
+ "datagram": "bidirectional_stream",
150
+ }[lane]),
151
+ )
152
+ inner_framing = validate_webtransport_inner_framing(
153
+ lane=lane,
154
+ inner_framing=binding.get("inner_framing"),
105
155
  )
156
+ family = webtransport_runtime_family(lane)
157
+ framing = "webtransport"
158
+ if lane == "session":
159
+ anchors = (
160
+ "transport.accept",
161
+ "dispatch.subevent.derive",
162
+ "handler.invoke",
163
+ "transport.close",
164
+ )
165
+ rows = (
166
+ {"family": "session", "subevent": "session.open"},
167
+ {"family": "session", "subevent": "session.close"},
168
+ )
169
+ elif lane == "bidi_stream":
170
+ anchors = (
171
+ "transport.accept",
172
+ "transport.receive",
173
+ "framing.decode",
174
+ "dispatch.subevent.derive",
175
+ "handler.invoke",
176
+ "framing.encode",
177
+ "transport.emit",
178
+ "transport.close",
179
+ )
180
+ rows = (
181
+ {"family": "stream", "subevent": "stream.open"},
182
+ {"family": "stream", "subevent": "stream.chunk.received"},
183
+ {"family": "stream", "subevent": "stream.chunk.emit"},
184
+ {"family": "stream", "subevent": "stream.close"},
185
+ )
186
+ elif lane == "unidi_client_stream":
187
+ anchors = (
188
+ "transport.accept",
189
+ "transport.receive",
190
+ "framing.decode",
191
+ "dispatch.subevent.derive",
192
+ "handler.invoke",
193
+ "transport.close",
194
+ )
195
+ rows = (
196
+ {"family": "stream", "subevent": "stream.open"},
197
+ {"family": "stream", "subevent": "stream.chunk.received"},
198
+ {"family": "stream", "subevent": "stream.close"},
199
+ )
200
+ elif lane == "unidi_server_stream":
201
+ anchors = (
202
+ "transport.accept",
203
+ "handler.invoke",
204
+ "framing.encode",
205
+ "transport.emit",
206
+ "transport.close",
207
+ )
208
+ rows = (
209
+ {"family": "stream", "subevent": "stream.open"},
210
+ {"family": "stream", "subevent": "stream.chunk.emit"},
211
+ {"family": "stream", "subevent": "stream.emit_complete"},
212
+ {"family": "stream", "subevent": "stream.close"},
213
+ )
214
+ elif lane == "datagram":
215
+ anchors = (
216
+ "transport.accept",
217
+ "transport.receive",
218
+ "framing.decode",
219
+ "dispatch.subevent.derive",
220
+ "handler.invoke",
221
+ "framing.encode",
222
+ "transport.emit",
223
+ )
224
+ rows = (
225
+ {"family": "datagram", "subevent": "datagram.received"},
226
+ {"family": "datagram", "subevent": "datagram.emit"},
227
+ {"family": "datagram", "subevent": "datagram.emit_complete"},
228
+ )
229
+ else: # pragma: no cover - guarded by webtransport_lane_for_profile
230
+ raise _unsupported(f"webtransport lane {lane}")
106
231
  else:
107
232
  raise _unsupported(kind)
108
233
 
234
+ event_key_inputs = {
235
+ "family": family,
236
+ "binding": kind,
237
+ "framing": framing,
238
+ }
239
+ if kind == "webtransport":
240
+ event_key_inputs["lane"] = lane
241
+ event_key_inputs["inner_framing"] = inner_framing
242
+
109
243
  return {
110
244
  "op_id": op_id,
111
245
  "binding_kind": kind,
112
246
  "family": family,
113
247
  "framing": framing,
114
248
  "atom_anchors": anchors,
115
- "event_key_inputs": {
116
- "family": family,
117
- "binding": kind,
118
- "framing": framing,
119
- },
249
+ "event_key_inputs": event_key_inputs,
120
250
  "capability_requirements": {
121
251
  "required_mask": _required_mask(kind=kind, family=family, framing=str(framing)),
122
252
  },
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
 
4
4
  _FAMILIES = {
5
5
  "request": ("request.received", "request.body.received"),
6
- "response": ("response.emit", "response.emit_complete"),
7
6
  "session": ("session.open", "session.ready", "session.close"),
8
7
  "message": ("message.received", "message.decoded", "message.emit", "message.emit_complete"),
9
8
  "stream": ("stream.open", "stream.chunk.received", "stream.chunk.emit", "stream.close"),
@@ -11,19 +10,29 @@ _FAMILIES = {
11
10
  }
12
11
 
13
12
  _BINDING_FAMILY = {
14
- "http.rest": "response",
15
- "http.jsonrpc": "response",
13
+ "http.rest": "request",
14
+ "https.rest": "request",
15
+ "http.jsonrpc": "request",
16
+ "https.jsonrpc": "request",
16
17
  "http.stream": "stream",
18
+ "https.stream": "stream",
17
19
  "http.sse": "stream",
20
+ "https.sse": "stream",
18
21
  "ws": "message",
22
+ "wss": "message",
19
23
  "websocket": "message",
24
+ "webtransport": "session",
25
+ "webtransport.session": "session",
26
+ "webtransport.bidi_stream": "stream",
27
+ "webtransport.unidi_client_stream": "stream",
28
+ "webtransport.unidi_server_stream": "stream",
20
29
  "webtransport.datagram": "datagram",
21
30
  }
22
31
 
23
32
  _ALIASES = {
24
33
  "receive": {"message": "message.received", "request": "request.received"},
25
- "emit": {"response": "response.emit", "message": "message.emit", "datagram": "datagram.emit"},
26
- "complete": {"response": "response.emit_complete", "message": "message.emit_complete", "datagram": "datagram.emit_complete"},
34
+ "emit": {"message": "message.emit", "stream": "stream.chunk.emit", "datagram": "datagram.emit"},
35
+ "complete": {"message": "message.emit_complete", "stream": "stream.close", "datagram": "datagram.emit_complete"},
27
36
  }
28
37
 
29
38
 
@@ -1,6 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections.abc import Sequence
4
+ from typing import Any
5
+
6
+ from tigrbl_core._spec.binding_spec import validate_webtransport_inner_framing
4
7
 
5
8
 
6
9
  def _event(subevent: str, atom: str, family: str) -> dict[str, str]:
@@ -23,6 +26,26 @@ def compile_webtransport_events(surface: str) -> list[dict[str, str]]:
23
26
  _event("stream.emit_complete", "transport.emit", "stream"),
24
27
  _event("stream.close", "transport.close", "stream"),
25
28
  ]
29
+ if surface == "bidi_stream":
30
+ return [
31
+ _event("stream.open", "transport.accept", "stream"),
32
+ _event("stream.chunk.received", "transport.receive", "stream"),
33
+ _event("stream.chunk.emit", "transport.emit", "stream"),
34
+ _event("stream.close", "transport.close", "stream"),
35
+ ]
36
+ if surface == "unidi_client_stream":
37
+ return [
38
+ _event("stream.open", "transport.accept", "stream"),
39
+ _event("stream.chunk.received", "transport.receive", "stream"),
40
+ _event("stream.close", "transport.close", "stream"),
41
+ ]
42
+ if surface == "unidi_server_stream":
43
+ return [
44
+ _event("stream.open", "transport.accept", "stream"),
45
+ _event("stream.chunk.emit", "transport.emit", "stream"),
46
+ _event("stream.emit_complete", "transport.emit", "stream"),
47
+ _event("stream.close", "transport.close", "stream"),
48
+ ]
26
49
  if surface == "datagram":
27
50
  return [
28
51
  _event("datagram.received", "transport.receive", "datagram"),
@@ -31,10 +54,12 @@ def compile_webtransport_events(surface: str) -> list[dict[str, str]]:
31
54
  ]
32
55
  if surface == "app_frame":
33
56
  return [
34
- _event("app_frame.decode", "framing.decode", "message"),
35
- _event("app_frame.emit", "transport.emit", "message"),
36
- _event("app_frame.encode", "framing.encode", "message"),
57
+ _event("app_frame.decode", "framing.decode", "stream"),
58
+ _event("app_frame.emit", "transport.emit", "stream"),
59
+ _event("app_frame.encode", "framing.encode", "stream"),
37
60
  ]
61
+ if surface == "message":
62
+ raise ValueError("WebTransport does not expose message as a native surface")
38
63
  raise ValueError(f"unsupported WebTransport surface: {surface}")
39
64
 
40
65
 
@@ -48,4 +73,152 @@ def compile_webtransport_chain(*, include_stream: bool = True, include_datagram:
48
73
  return {"binding": "webtransport", "subevents": tuple(subevents)}
49
74
 
50
75
 
51
- __all__ = ["compile_webtransport_chain", "compile_webtransport_events"]
76
+ def compile_webtransport_native_lanes() -> dict[str, tuple[str, ...]]:
77
+ return {
78
+ "session": tuple(event["subevent"] for event in compile_webtransport_events("session")),
79
+ "bidi_stream": tuple(event["subevent"] for event in compile_webtransport_events("bidi_stream")),
80
+ "unidi_client_stream": tuple(
81
+ event["subevent"] for event in compile_webtransport_events("unidi_client_stream")
82
+ ),
83
+ "unidi_server_stream": tuple(
84
+ event["subevent"] for event in compile_webtransport_events("unidi_server_stream")
85
+ ),
86
+ "datagram": tuple(event["subevent"] for event in compile_webtransport_events("datagram")),
87
+ }
88
+
89
+
90
+ _STREAM_EVENTS = {
91
+ "webtransport.stream.receive",
92
+ "webtransport.stream.send",
93
+ "webtransport.stream.close",
94
+ "webtransport.stream.reset",
95
+ "webtransport.stream.stop_sending",
96
+ }
97
+ _DATAGRAM_EVENTS = {
98
+ "webtransport.datagram.receive",
99
+ "webtransport.datagram.send",
100
+ }
101
+ _SESSION_EVENTS = {
102
+ "webtransport.connect",
103
+ "webtransport.accept",
104
+ "webtransport.disconnect",
105
+ "webtransport.close",
106
+ }
107
+ _STREAM_DIRECTIONS = {
108
+ "bidi": "bidi_stream",
109
+ "client_to_server": "unidi_client_stream",
110
+ "server_to_client": "unidi_server_stream",
111
+ }
112
+
113
+
114
+ def validate_webtransport_event_payload(
115
+ *,
116
+ event: str,
117
+ channel: str,
118
+ payload: dict[str, Any],
119
+ ) -> dict[str, object]:
120
+ if not isinstance(payload, dict):
121
+ raise ValueError("WebTransport event payload must be a mapping")
122
+ if channel not in {"receive", "send"}:
123
+ raise ValueError("WebTransport event channel must be receive or send")
124
+ if event in _SESSION_EVENTS:
125
+ return _validate_session_payload(event=event, channel=channel, payload=payload)
126
+ if event in _STREAM_EVENTS:
127
+ return _validate_stream_payload(event=event, channel=channel, payload=payload)
128
+ if event in _DATAGRAM_EVENTS:
129
+ return _validate_datagram_payload(event=event, channel=channel, payload=payload)
130
+ if event.startswith("webtransport.message"):
131
+ raise ValueError("WebTransport message is not a native transport lane")
132
+ raise ValueError(f"unsupported WebTransport event {event!r}")
133
+
134
+
135
+ def _validate_session_payload(
136
+ *,
137
+ event: str,
138
+ channel: str,
139
+ payload: dict[str, Any],
140
+ ) -> dict[str, object]:
141
+ expected_channel = "receive" if event in {"webtransport.connect", "webtransport.disconnect"} else "send"
142
+ if channel != expected_channel:
143
+ raise ValueError(f"{event} is only valid on {expected_channel}")
144
+ _forbid(payload, "stream_id", "stream_direction", "datagram_id", "framing")
145
+ return {"family": "session", "lane": "session", "exchange": "request_response"}
146
+
147
+
148
+ def _validate_stream_payload(
149
+ *,
150
+ event: str,
151
+ channel: str,
152
+ payload: dict[str, Any],
153
+ ) -> dict[str, object]:
154
+ expected_channel = "receive" if event == "webtransport.stream.receive" else "send"
155
+ if channel != expected_channel:
156
+ raise ValueError(f"{event} is only valid on {expected_channel}")
157
+ _require(payload, "stream_id")
158
+ _forbid(payload, "datagram_id")
159
+ direction = payload.get("stream_direction")
160
+ if event in {
161
+ "webtransport.stream.receive",
162
+ "webtransport.stream.send",
163
+ }:
164
+ if not isinstance(direction, str) or direction not in _STREAM_DIRECTIONS:
165
+ raise ValueError("WebTransport stream payload requires valid stream_direction")
166
+ else:
167
+ direction = str(direction) if direction in _STREAM_DIRECTIONS else "bidi"
168
+ lane = _STREAM_DIRECTIONS[str(direction)]
169
+ if channel == "receive" and lane == "unidi_server_stream":
170
+ raise ValueError("server_to_client unidirectional streams cannot be receive events")
171
+ if channel == "send" and lane == "unidi_client_stream":
172
+ raise ValueError("client_to_server unidirectional streams cannot be send events")
173
+ validate_webtransport_inner_framing(
174
+ lane=lane,
175
+ inner_framing=payload.get("framing"),
176
+ )
177
+ return {
178
+ "family": "stream",
179
+ "lane": lane,
180
+ "exchange": {
181
+ "bidi_stream": "bidirectional_stream",
182
+ "unidi_client_stream": "client_stream",
183
+ "unidi_server_stream": "server_stream",
184
+ }[lane],
185
+ }
186
+
187
+
188
+ def _validate_datagram_payload(
189
+ *,
190
+ event: str,
191
+ channel: str,
192
+ payload: dict[str, Any],
193
+ ) -> dict[str, object]:
194
+ expected_channel = "receive" if event == "webtransport.datagram.receive" else "send"
195
+ if channel != expected_channel:
196
+ raise ValueError(f"{event} is only valid on {expected_channel}")
197
+ _require(payload, "datagram_id")
198
+ _forbid(payload, "stream_id", "stream_direction")
199
+ validate_webtransport_inner_framing(
200
+ lane="datagram",
201
+ inner_framing=payload.get("framing"),
202
+ )
203
+ return {"family": "datagram", "lane": "datagram", "exchange": "bidirectional_stream"}
204
+
205
+
206
+ def _require(payload: dict[str, Any], field: str) -> None:
207
+ value = payload.get(field)
208
+ if value is None or value == "":
209
+ raise ValueError(f"WebTransport payload requires {field}")
210
+
211
+
212
+ def _forbid(payload: dict[str, Any], *fields: str) -> None:
213
+ present = [field for field in fields if field in payload and payload[field] is not None]
214
+ if present:
215
+ joined = ", ".join(present)
216
+ raise ValueError(f"WebTransport payload field not valid for event: {joined}")
217
+
218
+
219
+ __all__ = [
220
+ "compile_webtransport_chain",
221
+ "compile_webtransport_events",
222
+ "compile_webtransport_native_lanes",
223
+ "validate_webtransport_event_payload",
224
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tigrbl-kernel
3
- Version: 0.4.1.dev3
3
+ Version: 0.4.2.dev3
4
4
  Summary: Kernel orchestration for composing Tigrbl runtime plans, bindings, operation dispatch, and optimized ASGI execution.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -234,112 +234,62 @@ Project-URL: Organization, https://github.com/tigrbl
234
234
  Project-URL: Repository, https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel
235
235
  Description-Content-Type: text/markdown
236
236
 
237
- ![Tigrbl Logo](https://raw.githubusercontent.com/swarmauri/swarmauri-sdk/master/assets/tigrbl_full_logo.png)
237
+ <div align="center">
238
+ <h1>tigrbl-kernel</h1>
239
+ <img src="https://raw.githubusercontent.com/swarmauri/swarmauri-sdk/master/assets/tigrbl_full_logo.png" alt="Tigrbl logo" width="140"/>
240
+ <p><strong>Kernel orchestration for composing Tigrbl runtime plans, bindings, operation dispatch, and optimized ASGI execution.</strong></p>
241
+ <a href="https://pypi.org/project/tigrbl-kernel/"><img src="https://img.shields.io/pypi/v/tigrbl-kernel?label=PyPI" alt="PyPI version for tigrbl-kernel"/></a>
242
+ <a href="https://pypi.org/project/tigrbl-kernel/"><img src="https://static.pepy.tech/badge/tigrbl-kernel" alt="Downloads for tigrbl-kernel"/></a>
243
+ <a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_kernel/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_kernel/README.md.svg?label=hits" alt="Repository hits for tigrbl-kernel README"/></a>
244
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
245
+ <a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%20to%203.15-3776ab" alt="Python requirement for tigrbl-kernel"/></a>
246
+ <a href="https://github.com/tigrbl/tigrbl/blob/master/docs/README.md"><img src="https://img.shields.io/badge/workspace-core-1f6feb" alt="Workspace group for tigrbl-kernel"/></a>
247
+ </div>
238
248
 
239
- <p align="center">
240
- <a href="https://pypi.org/project/tigrbl-kernel/">
241
- <img src="https://img.shields.io/pypi/dm/tigrbl-kernel" alt="PyPI downloads for tigrbl-kernel"/></a>
242
- <a href="https://hits.sh/github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel/">
243
- <img src="https://hits.sh/github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel.svg" alt="Repository views for tigrbl-kernel"/></a>
244
- <a href="https://pypi.org/project/tigrbl-kernel/">
245
- <img src="https://img.shields.io/pypi/pyversions/tigrbl-kernel" alt="Supported Python versions for tigrbl-kernel"/></a>
246
- <a href="https://pypi.org/project/tigrbl-kernel/">
247
- <img src="https://img.shields.io/pypi/l/tigrbl-kernel" alt="PyPI license metadata for tigrbl-kernel"/></a>
248
- <a href="https://pypi.org/project/tigrbl-kernel/">
249
- <img src="https://img.shields.io/pypi/v/tigrbl-kernel?label=tigrbl-kernel&color=green" alt="PyPI version for tigrbl-kernel"/></a>
250
- </p>
251
-
252
- ---
253
-
254
- <h1 align="center">Tigrbl kernel</h1>
255
-
256
- **Install and inspect `tigrbl-kernel`: [download `tigrbl-kernel` from PyPI](https://pypi.org/project/tigrbl-kernel/) or [open the package source](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel).**
257
-
258
- tigrbl-kernel is a kernel orchestration package for kernel orchestration for composing Tigrbl runtime plans, bindings, and operation dispatch.
259
-
260
- `tigrbl-kernel` is part of the Tigrbl package graph. It documents package-resident classes, concepts, extension points, and execution responsibilities while cross-linking to the facade, core specs, canonical mapping, runtime phases, concrete objects, operation packages, engine plugins, OpenAPI/OpenRPC documentation surfaces, and PyPI distributions that complete the system.
261
-
262
- ## Package ownership
263
-
264
- - `tigrbl-kernel` documents the concepts implemented in `pkgs/core/tigrbl_kernel` and links to the Tigrbl packages that provide neighboring authoring, canon, runtime, operation, and engine behavior.
265
- - Use this README as the package-local explanation for the objects that live here; use governed docs for release state, certification, and evidence.
249
+ ## Install
266
250
 
267
- ## Package ecosystem cross-links
251
+ ```bash
252
+ uv add tigrbl-kernel
253
+ ```
268
254
 
269
- Every Tigrbl Python package links to its sibling distributions on PyPI so package indexes, search engines, answer engines, dependency scanners, and human readers can move through the installable package graph without falling back to source-tree paths.
255
+ ```bash
256
+ pip install tigrbl-kernel
257
+ ```
270
258
 
271
- Core packages:
272
- - [`tigrbl`](https://pypi.org/project/tigrbl/) - Schema-first ASGI API framework for REST, JSON-RPC, OpenAPI, OpenRPC, SQLAlchemy models, typed validation, lifecycle hooks, and engine plugins.
273
- - [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/) - Runtime atom utilities for Tigrbl planning, dispatch, transport ingress, egress, and high-throughput ASGI execution pipelines.
274
- - [`tigrbl-base`](https://pypi.org/project/tigrbl-base/) - Abstract base interfaces for Tigrbl APIs, engines, providers, sessions, transports, and reusable runtime components.
275
- - [`tigrbl-canon`](https://pypi.org/project/tigrbl-canon/) - Canonical mapping, routing, symbol resolution, and naming utilities for Tigrbl framework packages and generated API surfaces.
276
- - [`tigrbl_client`](https://pypi.org/project/tigrbl_client/) - Typed Python client helpers for calling Tigrbl REST, JSON-RPC, OpenAPI, and generated schema-first API surfaces.
277
- - [`tigrbl-concrete`](https://pypi.org/project/tigrbl-concrete/) - Concrete Tigrbl implementations for reusable framework behavior, sessions, routes, responses, and base abstraction adapters.
278
- - [`tigrbl-core`](https://pypi.org/project/tigrbl-core/) - Core Tigrbl framework specifications, decorators, schemas, hooks, operations, and primitives for schema-first APIs.
279
- - [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/) (this package) - Kernel orchestration for composing Tigrbl runtime plans, bindings, operation dispatch, and optimized ASGI execution.
280
- - [`tigrbl-ops-olap`](https://pypi.org/project/tigrbl-ops-olap/) - Analytical OLAP operation boundaries for Tigrbl workloads, query-oriented APIs, and engine integrations.
281
- - [`tigrbl-ops-oltp`](https://pypi.org/project/tigrbl-ops-oltp/) - Transactional OLTP operation handlers for Tigrbl CRUD, bulk, REST, JSON-RPC, and database-backed workloads.
282
- - [`tigrbl-ops-realtime`](https://pypi.org/project/tigrbl-ops-realtime/) - Realtime, streaming, datagram, websocket, and event operation handlers for Tigrbl ASGI runtimes.
283
- - [`tigrbl-orm`](https://pypi.org/project/tigrbl-orm/) - SQLAlchemy ORM tables, mixins, columns, model helpers, and persistence primitives for Tigrbl applications.
284
- - [`tigrbl-runtime`](https://pypi.org/project/tigrbl-runtime/) - Runtime pipeline helpers and execution bridge surfaces for Tigrbl ASGI applications, transports, and operation dispatch.
285
- - [`tigrbl_spec`](https://pypi.org/project/tigrbl_spec/) - Shared Tigrbl interfaces, protocol definitions, compatibility targets, and specification artifacts for framework integration.
286
- - [`tigrbl_tests`](https://pypi.org/project/tigrbl_tests/) - Reusable Tigrbl pytest fixtures, conformance assertions, integration helpers, and package test utilities.
287
- - [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/) - Typing protocols, aliases, generics, and shared type helpers for Tigrbl framework packages and extensions.
259
+ ## What It Owns
288
260
 
289
- Engine packages:
290
- - [`tigrbl_engine_bigquery`](https://pypi.org/project/tigrbl_engine_bigquery/) - BigQuery engine plugin for Google BigQuery warehouse sessions, analytics workloads, and Tigrbl engine registration.
291
- - [`tigrbl_engine_clickhouse`](https://pypi.org/project/tigrbl_engine_clickhouse/) - ClickHouse engine plugin for analytical database sessions, warehouse workloads, and Tigrbl engine registration.
292
- - [`tigrbl_engine_csv`](https://pypi.org/project/tigrbl_engine_csv/) - CSV engine plugin for file-backed tables, pandas DataFrames, and lightweight Tigrbl data workflows.
293
- - [`tigrbl_engine_dataframe`](https://pypi.org/project/tigrbl_engine_dataframe/) - DataFrame engine plugin for transactional pandas sessions and in-process Tigrbl analytics workloads.
294
- - [`tigrbl_engine_duckdb`](https://pypi.org/project/tigrbl_engine_duckdb/) - DuckDB engine plugin for embedded analytical database sessions, OLAP workloads, and Tigrbl engine registration.
295
- - [`tigrbl_engine_inmemcache`](https://pypi.org/project/tigrbl_engine_inmemcache/) - In-memory cache engine plugin for process-local TTL, LRU, and fast Tigrbl cache workflows.
296
- - [`tigrbl_engine_inmemory`](https://pypi.org/project/tigrbl_engine_inmemory/) - In-memory database engine plugin for process-local transactional storage, copy-on-write snapshots, and Tigrbl testing.
297
- - [`tigrbl_engine_membloom`](https://pypi.org/project/tigrbl_engine_membloom/) - In-memory Bloom filter engine plugin for membership checks, rotating TTL windows, and Tigrbl API workflows.
298
- - [`tigrbl_engine_memdedupe`](https://pypi.org/project/tigrbl_engine_memdedupe/) - In-memory dedupe engine plugin for idempotency tracking, duplicate suppression, and Tigrbl workflow coordination.
299
- - [`tigrbl_engine_memkv`](https://pypi.org/project/tigrbl_engine_memkv/) - In-memory key-value engine plugin for process-local KV storage, cache workflows, and lightweight Tigrbl services.
300
- - [`tigrbl_engine_memlru`](https://pypi.org/project/tigrbl_engine_memlru/) - In-memory LRU engine plugin for least-recently-used cache behavior and process-local Tigrbl data workflows.
301
- - [`tigrbl_engine_mempubsub`](https://pypi.org/project/tigrbl_engine_mempubsub/) - In-memory pub/sub engine plugin for process-local publish-subscribe channels, events, and Tigrbl realtime workflows.
302
- - [`tigrbl_engine_memqueue`](https://pypi.org/project/tigrbl_engine_memqueue/) - In-memory queue engine plugin for process-local tasks, message workflows, and Tigrbl runtime coordination.
303
- - [`tigrbl_engine_memrate`](https://pypi.org/project/tigrbl_engine_memrate/) - In-memory rate-limit engine plugin for API quotas, counters, windows, and Tigrbl governance workflows.
304
- - [`tigrbl_engine_numpy`](https://pypi.org/project/tigrbl_engine_numpy/) - NumPy engine plugin for array-to-table helpers, analytical workflows, and Tigrbl data integration.
305
- - [`tigrbl_engine_pandas`](https://pypi.org/project/tigrbl_engine_pandas/) - Pandas engine plugin for transactional DataFrame sessions, tabular workflows, and Tigrbl data integration.
306
- - [`tigrbl_engine_pgsqli_wal`](https://pypi.org/project/tigrbl_engine_pgsqli_wal/) - PostgreSQL and SQLite WAL engine plugin for transactional Tigrbl workflows and database-backed engine registration.
307
- - [`tigrbl_engine_postgres`](https://pypi.org/project/tigrbl_engine_postgres/) - PostgreSQL engine plugin for SQLAlchemy sessions, async database workflows, and Tigrbl application persistence.
308
- - [`tigrbl_engine_pyspark`](https://pypi.org/project/tigrbl_engine_pyspark/) - PySpark engine plugin for distributed DataFrame integration, analytics workloads, and Tigrbl data workflows.
309
- - [`tigrbl_engine_redis`](https://pypi.org/project/tigrbl_engine_redis/) - Redis engine plugin for cache, data structures, and Tigrbl engine workflows backed by Redis.
310
- - [`tigrbl_engine_rediscachethrough`](https://pypi.org/project/tigrbl_engine_rediscachethrough/) - Redis cache-through engine plugin for Redis, PostgreSQL, and Tigrbl data-access acceleration workflows.
311
- - [`tigrbl_engine_snowflake`](https://pypi.org/project/tigrbl_engine_snowflake/) - Snowflake engine plugin for warehouse sessions, analytical workloads, and Tigrbl engine registration.
312
- - [`tigrbl_engine_sqlite`](https://pypi.org/project/tigrbl_engine_sqlite/) - SQLite engine plugin for SQLAlchemy sessions, local transactional storage, and Tigrbl application persistence.
313
- - [`tigrbl_engine_xlsx`](https://pypi.org/project/tigrbl_engine_xlsx/) - XLSX engine plugin for Excel workbook-backed tables, worksheet data access, and Tigrbl tabular workflows.
261
+ `tigrbl-kernel` owns the kernel boundary inside the split Python workspace. Key implementation roots include `tigrbl_kernel` with `_build, _compile, atoms, cache, callbacks, core`.
314
262
 
315
- Application packages:
316
- - [`tigrbl_acme_ca`](https://pypi.org/project/tigrbl_acme_ca/) - ACME v2 certificate authority app for Tigrbl tables, certificate automation, TLS workflows, and API surfaces.
317
- - [`tigrbl_spiffe`](https://pypi.org/project/tigrbl_spiffe/) - SPIFFE and SPIRE identity app for Tigrbl with workload identity tables, UDS transport, and HTTP API surfaces.
263
+ ## Use It When
318
264
 
319
- Source-tree links remain available from each package identity section; this ecosystem section is intentionally PyPI-first for package discovery and installation routing.
265
+ Use `tigrbl-kernel` when you want this subsystem directly as a package boundary instead of consuming it only through the top-level `tigrbl` facade.
320
266
 
321
- ## Install
267
+ ## Public Surface
322
268
 
323
- ```bash
324
- pip install tigrbl-kernel
325
- ```
269
+ - `tigrbl_kernel` exposes `import_module, Any, Dict, List, Mapping, build_rust_kernel, build_rust_parity_snapshot, normalize_rust_spec`.
326
270
 
327
- ## Package discovery
271
+ ## Internal Layout
328
272
 
329
- `tigrbl-kernel` is described for package indexes, search engines, answer engines, and AI coding tools as: Kernel orchestration for composing Tigrbl runtime plans, bindings, operation dispatch, and optimized ASGI execution.
273
+ - Workspace path: `pkgs/core/tigrbl_kernel`.
274
+ - Package class: `core framework package`.
275
+ - Python requirement: `>=3.10,<3.15`.
276
+ - `tigrbl_kernel` modules: `_build, _compile, atoms, cache, callbacks, core, eventkey, eventkey_hooks, events, helpers`.
330
277
 
331
- Use `tigrbl-kernel` when you need Tigrbl's schema-first ASGI package graph for REST APIs, JSON-RPC APIs, OpenAPI documentation, OpenRPC documentation, SQLAlchemy-backed models, Pydantic validation, typed operation specs, runtime dispatch, and installable engine or application extensions.
278
+ ## Dependency Surface
332
279
 
333
- Discovery terms: tigrbl, ASGI, schema-first API framework, REST API, JSON-RPC API, OpenAPI documentation, OpenRPC documentation, SQLAlchemy models, Pydantic validation, typed validation, operation dispatch, engine plugins, api, json-rpc, rest, sqlalchemy, pydantic, kernel, orchestration, dispatch, openapi, openrpc, schema-first.
280
+ - Workspace package dependencies: [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/), [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/), [`tigrbl-core`](https://pypi.org/project/tigrbl-core/).
281
+ - External runtime dependencies: none declared.
282
+ - Optional extras: none declared.
334
283
 
335
- ## Package-local entry point
284
+ ## Related Packages
336
285
 
337
- This file is a package-local distribution entry point.
338
- It is not the authoritative location for repository governance, current target status, current state reporting, certification claims, or release evidence.
286
+ - [`tigrbl`](https://pypi.org/project/tigrbl/)
287
+ - [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/)
288
+ - [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/)
289
+ - [`tigrbl-core`](https://pypi.org/project/tigrbl-core/)
339
290
 
340
- ## Canonical repository docs
291
+ ## Canonical Repository Docs
341
292
 
342
- - `README.md`
343
293
  - `docs/README.md`
344
294
  - `docs/conformance/CURRENT_TARGET.md`
345
295
  - `docs/conformance/CURRENT_STATE.md`
@@ -348,15 +298,12 @@ It is not the authoritative location for repository governance, current target s
348
298
  - `docs/developer/PACKAGE_CATALOG.md`
349
299
  - `docs/developer/PACKAGE_LAYOUT.md`
350
300
 
351
- ## Package identity
301
+ ## Package-local Boundary
302
+
303
+ This file is a package-local distribution entry point.
304
+ Use this page for package installation and boundary orientation. Repository governance, conformance state, target status, and release evidence remain governed from `docs/` and `.ssot/`.
352
305
 
353
- - canonical repository: `https://github.com/tigrbl/tigrbl`
354
- - organization: `https://github.com/tigrbl`
355
- - social: `https://discord.gg/K4YTAPapjR`
356
- - package path: `https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel`
357
- - workspace path: `pkgs/core/tigrbl_kernel`
358
- - workspace class: core Python package
359
- - implementation layout: `tigrbl_kernel/`
306
+ ## License
360
307
 
361
- Long-form repository documentation is governed from `docs/`.
308
+ Licensed under the Apache License, Version 2.0. See `LICENSE` and the official [Apache 2.0 license text](https://www.apache.org/licenses/LICENSE-2.0).
362
309
 
@@ -1,9 +1,10 @@
1
1
  tigrbl_kernel/__init__.py,sha256=9hH7UWbqXuR5F0o0doSOjwLiy6KCHB6qZr5sS_O6Kr0,2813
2
- tigrbl_kernel/_build.py,sha256=QDzkFIknjj2J7wdq1EZ3D3lg3OO2IzYaa84Dc78mPW0,50060
2
+ tigrbl_kernel/_build.py,sha256=xLaLHsVWSeY3mefyCEnGYEGzHlyMU_1SGgyr7T6hUeY,50369
3
3
  tigrbl_kernel/_compile.py,sha256=hQ3UscZ_zrCodWZfTe7mZ7I3MBMJzIxqF1SZLycRL9A,7771
4
4
  tigrbl_kernel/atoms.py,sha256=ZNGj2PBUMu1BvPjNYlz4_vu4vhx4gD20C7zNE_GKfe8,12253
5
5
  tigrbl_kernel/cache.py,sha256=NxuqvH03xYwcQoY86ie1hmtDeA36XdiLmNyx2ImLQ6k,2596
6
6
  tigrbl_kernel/callbacks.py,sha256=r_ZI19nbAoDM-uf-FMUmWWAF9WaEKJK3Fpg-58ui8a4,772
7
+ tigrbl_kernel/contract_classification.py,sha256=5ZbhtJr88VtIPAtPWD5eL4BKKQU734kZeMEvEqh9cvU,6009
7
8
  tigrbl_kernel/core.py,sha256=3lR3VrlHOFiP-POLluEpBKWeGDdaqX8tJYHQ0eRluP0,6667
8
9
  tigrbl_kernel/eventkey.py,sha256=aTwzBkAjeC-kaEUItL1Mcfcq_Ur1fUbZDY6XxKdwWdg,1980
9
10
  tigrbl_kernel/eventkey_hooks.py,sha256=Cbkev0GXgSH27dlFoVeaKC7XuQ9yJq4bI1Mlc3qB4Qs,2480
@@ -20,7 +21,7 @@ tigrbl_kernel/opchannel_capabilities.py,sha256=5zM9-1fc-W8BXyXF4VVWrIsmdwCH5xLra
20
21
  tigrbl_kernel/opview_compiler.py,sha256=DbZ3E0GYl_JEgExELjaNE7v2W4hl9LqvAB-CE5TwP7o,5370
21
22
  tigrbl_kernel/ordering.py,sha256=92elylml2LPDYiSnjj4QHNM3OR9utxN3Al9g-UJsyJ0,13542
22
23
  tigrbl_kernel/payload.py,sha256=eyHo-cAUXLWQQ9-xZVOl_rjFudA-djMZji9hoK-v9IE,2167
23
- tigrbl_kernel/protocol_bindings.py,sha256=A95wOqq4xrtJsZrM2TGhbDGJ2aLs23WVUmPq4V-x7iM,4381
24
+ tigrbl_kernel/protocol_bindings.py,sha256=u3XcmqyX3MJqyUUkUgKSBEMvM8hXCwwP_eT-n_GqfEQ,9985
24
25
  tigrbl_kernel/protocol_chains/__init__.py,sha256=iSnOw5R4ahGypm59bQgPpsBwFXbPcnKPozjSfc9N6GQ,151
25
26
  tigrbl_kernel/protocol_chains/http_stream.py,sha256=5dY86DBJzcGcmrvOuDJo8M0cjLdeSmNAa_fo9zHuBdE,1123
26
27
  tigrbl_kernel/protocol_chains/http_unary.py,sha256=7EABv0bUAJ5UI3TWP-S-8LtgwZJLj5pw-ZnZ_8qiD4g,1776
@@ -37,15 +38,15 @@ tigrbl_kernel/rust_plan.py,sha256=p4A46oOVtqamGJS_x_RGsGJo6IN81LKa1_KmGstyxoM,34
37
38
  tigrbl_kernel/rust_spec.py,sha256=ICfIenmocRucLunvSvS91L0vli6YSMBGWnWSGN-9ppE,14668
38
39
  tigrbl_kernel/segment_fusion.py,sha256=zbPNGd1eFJGFZHJxrfanaNMyrJjJw1aPRsl_jJfN4sM,1607
39
40
  tigrbl_kernel/subevent_handlers.py,sha256=4j4780QjQiqY4qpRsyxrPh_znRK3SkLAFDN_x6eidwU,1779
40
- tigrbl_kernel/subevent_taxonomy.py,sha256=6lhJV6lxEoYuUMT4Ysmv_9kHSRaE9P32GTP2Cxc5Yt8,1995
41
+ tigrbl_kernel/subevent_taxonomy.py,sha256=67RJ7ZkfJMLfa7evzVfTlFqtdWSnhp65zwA4qhNwSG8,2274
41
42
  tigrbl_kernel/trace.py,sha256=dWILtq9seOj-WwCx__Pk_VZAbFIN1tqTbs0gIndYkU8,9816
42
43
  tigrbl_kernel/transaction_units.py,sha256=_NeQHycjjDoLG1kmD74o10wDQpdA5qjs-Sd_fxPb0_E,863
43
44
  tigrbl_kernel/transport_atoms.py,sha256=enfNCMuLgLMKi8zraMm-QOk7ys5d9kcP-WPr0-wK6KE,2136
44
45
  tigrbl_kernel/transport_events.py,sha256=qogvEAAPPX_Y6V5evGuqvFCpIePYK4ryLmCDT9JHkFM,3777
45
46
  tigrbl_kernel/types.py,sha256=BM_uPtF17MSI-q2ya93BWheAlPxOu-NaflwmxuicutA,2198
46
47
  tigrbl_kernel/utils.py,sha256=iCcm0flQfAi4w4cbVEaq6yiPR-kAoXx2owiRpbBf-0o,6953
47
- tigrbl_kernel/webtransport_events.py,sha256=cGBZAyy2PuYDV9H2nuM2bulJ3cojz6SEqL5cJK8mhTg,2267
48
- tigrbl_kernel-0.4.1.dev3.dist-info/METADATA,sha256=KAJh0DMOQ6k08PHum3lGPt7UmpcTNkJcr2BY2DzX720,27183
49
- tigrbl_kernel-0.4.1.dev3.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
50
- tigrbl_kernel-0.4.1.dev3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
51
- tigrbl_kernel-0.4.1.dev3.dist-info/RECORD,,
48
+ tigrbl_kernel/webtransport_events.py,sha256=MqWpnB4QvCbGgV8Sk-247EugbsXrfmDeY5YzLv84URo,8858
49
+ tigrbl_kernel-0.4.2.dev3.dist-info/METADATA,sha256=IAVw83N-0MUH4O6HKXlRtX4UYgoswLGRbL9JZFZhkMo,18280
50
+ tigrbl_kernel-0.4.2.dev3.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
51
+ tigrbl_kernel-0.4.2.dev3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
52
+ tigrbl_kernel-0.4.2.dev3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.4.0
2
+ Generator: poetry-core 2.4.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any