tigrbl-kernel 0.4.5.dev4__tar.gz → 0.4.5.dev8__tar.gz

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.
Files changed (62) hide show
  1. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/PKG-INFO +9 -9
  2. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/README.md +5 -5
  3. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/pyproject.toml +4 -4
  4. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/__init__.py +2 -0
  5. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/_build.py +19 -1
  6. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/_compile.py +35 -7
  7. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/models.py +8 -0
  8. tigrbl_kernel-0.4.5.dev8/tigrbl_kernel/opview_compiler.py +312 -0
  9. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/packed_selectors.py +145 -5
  10. tigrbl_kernel-0.4.5.dev8/tigrbl_kernel/protocol_chains/websocket.py +533 -0
  11. tigrbl_kernel-0.4.5.dev8/tigrbl_kernel/webtransport_session_plan.py +92 -0
  12. tigrbl_kernel-0.4.5.dev4/tigrbl_kernel/opview_compiler.py +0 -136
  13. tigrbl_kernel-0.4.5.dev4/tigrbl_kernel/protocol_chains/websocket.py +0 -41
  14. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/LICENSE +0 -0
  15. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/NOTICE +0 -0
  16. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/atoms.py +0 -0
  17. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/cache.py +0 -0
  18. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/callbacks.py +0 -0
  19. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/channel_taxonomy.py +0 -0
  20. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/contract_classification.py +0 -0
  21. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/core.py +0 -0
  22. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/cross_transport.py +0 -0
  23. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/dispatch_taxonomy.py +0 -0
  24. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/eventkey.py +0 -0
  25. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/eventkey_hooks.py +0 -0
  26. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/events.py +0 -0
  27. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/helpers.py +0 -0
  28. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/hook_types.py +0 -0
  29. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/labels.py +0 -0
  30. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/lifecycle_matrix.py +0 -0
  31. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/loop_modes.py +0 -0
  32. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/loop_regions.py +0 -0
  33. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/measure.py +0 -0
  34. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/opchannel_capabilities.py +0 -0
  35. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/ordering.py +0 -0
  36. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/packed_access.py +0 -0
  37. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/payload.py +0 -0
  38. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_anchors.py +0 -0
  39. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_bindings.py +0 -0
  40. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_chains/__init__.py +0 -0
  41. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_chains/http_stream.py +0 -0
  42. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_chains/http_unary.py +0 -0
  43. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_chains/lifespan.py +0 -0
  44. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_chains/sse.py +0 -0
  45. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_chains/static_files.py +0 -0
  46. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_completion.py +0 -0
  47. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_fusion.py +0 -0
  48. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_legality_matrix.py +0 -0
  49. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_phase_tree.py +0 -0
  50. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/protocol_streams.py +0 -0
  51. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/resume_policy.py +0 -0
  52. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/runtime_contracts.py +0 -0
  53. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/segment_fusion.py +0 -0
  54. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/subevent_handlers.py +0 -0
  55. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/subevent_taxonomy.py +0 -0
  56. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/trace.py +0 -0
  57. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/transaction_units.py +0 -0
  58. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/transport_atoms.py +0 -0
  59. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/transport_events.py +0 -0
  60. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/types.py +0 -0
  61. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/utils.py +0 -0
  62. {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev8}/tigrbl_kernel/webtransport_events.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tigrbl-kernel
3
- Version: 0.4.5.dev4
3
+ Version: 0.4.5.dev8
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
@@ -225,14 +225,14 @@ Classifier: Programming Language :: Python :: 3.14
225
225
  Classifier: Topic :: Internet :: WWW/HTTP
226
226
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
227
227
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
228
- Requires-Dist: tigrbl-atoms
229
- Requires-Dist: tigrbl-core
228
+ Requires-Dist: tigrbl-atoms (>=0.4.5.dev5)
229
+ Requires-Dist: tigrbl-core (>=0.4.5.dev6)
230
230
  Requires-Dist: tigrbl-typing
231
231
  Project-URL: Discord, https://discord.gg/K4YTAPapjR
232
232
  Project-URL: Homepage, https://github.com/tigrbl/tigrbl
233
233
  Project-URL: Issues, https://github.com/tigrbl/tigrbl/issues
234
234
  Project-URL: Organization, https://github.com/tigrbl
235
- Project-URL: Repository, https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel
235
+ Project-URL: Repository, https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel
236
236
  Description-Content-Type: text/markdown
237
237
 
238
238
  <div align="center">
@@ -242,7 +242,7 @@ Description-Content-Type: text/markdown
242
242
  <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>
243
243
  <a href="https://pypi.org/project/tigrbl-kernel/"><img src="https://static.pepy.tech/badge/tigrbl-kernel" alt="Downloads for tigrbl-kernel"/></a>
244
244
  <a href="https://discord.gg/K4YTAPapjR"><img src="https://img.shields.io/badge/Discord-Join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord community for tigrbl-kernel"/></a>
245
- <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>
245
+ <a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/45_kernel/tigrbl_kernel/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/45_kernel/tigrbl_kernel/README.md.svg?label=hits" alt="Repository hits for tigrbl-kernel README"/></a>
246
246
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
247
247
  <a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%2C%203.11%2C%203.12%2C%203.13%2C%203.14-3776ab" alt="Python versions 3.10 | 3.11 | 3.12 | 3.13 | 3.14 for tigrbl-kernel"/></a>
248
248
  <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>
@@ -266,7 +266,7 @@ Framework maintainers, extension authors, and advanced users composing Tigrbl fr
266
266
 
267
267
  ## Where does tigrbl-kernel fit?
268
268
 
269
- `tigrbl-kernel` lives at `pkgs/core/tigrbl_kernel` and serves a focused layer in the split Tigrbl framework.
269
+ `tigrbl-kernel` lives at `pkgs/45_kernel/tigrbl_kernel` and serves a focused layer in the split Tigrbl framework.
270
270
 
271
271
  ## How does tigrbl-kernel work?
272
272
 
@@ -288,7 +288,7 @@ pip install tigrbl-kernel
288
288
  | Surface | Value |
289
289
  |---|---|
290
290
  | PyPI package | [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/) |
291
- | Repository path | [`pkgs/core/tigrbl_kernel`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel) |
291
+ | Repository path | [`pkgs/45_kernel/tigrbl_kernel`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel) |
292
292
  | Python import root | `tigrbl_kernel` |
293
293
  | Console scripts | none declared |
294
294
  | Entry points | none declared |
@@ -444,7 +444,7 @@ Choose `tigrbl-kernel` when the quick-answer table matches your use case. Choose
444
444
 
445
445
  - Community: [Discord](https://discord.gg/K4YTAPapjR).
446
446
  - Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
447
- - Repository: [pkgs/core/tigrbl_kernel](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel).
447
+ - Repository: [pkgs/45_kernel/tigrbl_kernel](https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel).
448
448
 
449
449
  ## Package-local Boundary
450
450
 
@@ -455,7 +455,7 @@ This file is a package-local distribution entry point. This README is the packag
455
455
  - Package status: governed package in the `tigrbl/tigrbl` workspace.
456
456
  - Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
457
457
  - Release evidence: [publish workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml) validates package builds, tests, GitHub release assets, and PyPI publication for managed packages.
458
- - Local certification guard: `pkgs/core/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
458
+ - Local certification guard: `pkgs/97_tests/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
459
459
  - Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
460
460
 
461
461
  ## License
@@ -5,7 +5,7 @@
5
5
  <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>
6
6
  <a href="https://pypi.org/project/tigrbl-kernel/"><img src="https://static.pepy.tech/badge/tigrbl-kernel" alt="Downloads for tigrbl-kernel"/></a>
7
7
  <a href="https://discord.gg/K4YTAPapjR"><img src="https://img.shields.io/badge/Discord-Join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord community for tigrbl-kernel"/></a>
8
- <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>
8
+ <a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/45_kernel/tigrbl_kernel/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/45_kernel/tigrbl_kernel/README.md.svg?label=hits" alt="Repository hits for tigrbl-kernel README"/></a>
9
9
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
10
10
  <a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%2C%203.11%2C%203.12%2C%203.13%2C%203.14-3776ab" alt="Python versions 3.10 | 3.11 | 3.12 | 3.13 | 3.14 for tigrbl-kernel"/></a>
11
11
  <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>
@@ -29,7 +29,7 @@ Framework maintainers, extension authors, and advanced users composing Tigrbl fr
29
29
 
30
30
  ## Where does tigrbl-kernel fit?
31
31
 
32
- `tigrbl-kernel` lives at `pkgs/core/tigrbl_kernel` and serves a focused layer in the split Tigrbl framework.
32
+ `tigrbl-kernel` lives at `pkgs/45_kernel/tigrbl_kernel` and serves a focused layer in the split Tigrbl framework.
33
33
 
34
34
  ## How does tigrbl-kernel work?
35
35
 
@@ -51,7 +51,7 @@ pip install tigrbl-kernel
51
51
  | Surface | Value |
52
52
  |---|---|
53
53
  | PyPI package | [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/) |
54
- | Repository path | [`pkgs/core/tigrbl_kernel`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel) |
54
+ | Repository path | [`pkgs/45_kernel/tigrbl_kernel`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel) |
55
55
  | Python import root | `tigrbl_kernel` |
56
56
  | Console scripts | none declared |
57
57
  | Entry points | none declared |
@@ -207,7 +207,7 @@ Choose `tigrbl-kernel` when the quick-answer table matches your use case. Choose
207
207
 
208
208
  - Community: [Discord](https://discord.gg/K4YTAPapjR).
209
209
  - Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
210
- - Repository: [pkgs/core/tigrbl_kernel](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel).
210
+ - Repository: [pkgs/45_kernel/tigrbl_kernel](https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel).
211
211
 
212
212
  ## Package-local Boundary
213
213
 
@@ -218,7 +218,7 @@ This file is a package-local distribution entry point. This README is the packag
218
218
  - Package status: governed package in the `tigrbl/tigrbl` workspace.
219
219
  - Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
220
220
  - Release evidence: [publish workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml) validates package builds, tests, GitHub release assets, and PyPI publication for managed packages.
221
- - Local certification guard: `pkgs/core/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
221
+ - Local certification guard: `pkgs/97_tests/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
222
222
  - Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
223
223
 
224
224
  ## License
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tigrbl-kernel"
3
- version = "0.4.5.dev4"
3
+ version = "0.4.5.dev8"
4
4
  description = "Kernel orchestration for composing Tigrbl runtime plans, bindings, operation dispatch, and optimized ASGI execution."
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -42,8 +42,8 @@ authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
42
42
 
43
43
  dependencies = [
44
44
  "tigrbl-typing",
45
- "tigrbl-atoms",
46
- "tigrbl-core",
45
+ "tigrbl-atoms>=0.4.5.dev5",
46
+ "tigrbl-core>=0.4.5.dev6",
47
47
  ]
48
48
 
49
49
 
@@ -51,7 +51,7 @@ dependencies = [
51
51
  Organization = "https://github.com/tigrbl"
52
52
  Discord = "https://discord.gg/K4YTAPapjR"
53
53
  Homepage = "https://github.com/tigrbl/tigrbl"
54
- Repository = "https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_kernel"
54
+ Repository = "https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel"
55
55
  Issues = "https://github.com/tigrbl/tigrbl/issues"
56
56
 
57
57
  [tool.uv.sources]
@@ -18,6 +18,7 @@ _LAZY_EXPORTS = {
18
18
  "PackedKernel": "models",
19
19
  "SchemaIn": "models",
20
20
  "SchemaOut": "models",
21
+ "SchemaStored": "models",
21
22
  }
22
23
 
23
24
  _default_kernel = None
@@ -73,6 +74,7 @@ __all__ = [
73
74
  "PackedKernel",
74
75
  "SchemaIn",
75
76
  "SchemaOut",
77
+ "SchemaStored",
76
78
  "build_kernel_plan",
77
79
  "build_packed_kernel",
78
80
  "build_packed_kernel_measurement_view",
@@ -91,6 +91,12 @@ _DECODER_TIME = 9
91
91
  _WS_FAST_PATH_BYPASS_ATOM_NAMES = frozenset(
92
92
  {
93
93
  "ingress.ctx_init",
94
+ "ingress.transport_extract",
95
+ "transport.sink_bind",
96
+ "ingress.input_prepare",
97
+ "dispatch.binding_match",
98
+ "dispatch.binding_parse",
99
+ "dispatch.input_normalize",
94
100
  "dispatch.op_resolve",
95
101
  "schema.collect_in",
96
102
  "handler.custom",
@@ -213,6 +219,8 @@ def _is_batch_domain_run(run: Any) -> bool:
213
219
  except ValueError:
214
220
  return False
215
221
  domain = parts[index + 1] if index + 1 < len(parts) else None
222
+ if domain == "transport" and parts[-1] == "sink_bind":
223
+ return False
216
224
  return domain in {"transport", "intent", "batch", "fanout"}
217
225
 
218
226
 
@@ -1156,8 +1164,18 @@ def _pack_kernel_plan(
1156
1164
  )
1157
1165
  alias_name = str(getattr(meta, "alias", "") or "")
1158
1166
  target_name = str(getattr(meta, "target", "") or "")
1167
+ opview = opviews[program_id] if program_id < len(opviews) else None
1159
1168
  compiled_param_eligible = not (
1160
- alias_name.startswith("bulk_") or target_name.startswith("bulk_")
1169
+ alias_name.startswith("bulk_")
1170
+ or target_name.startswith("bulk_")
1171
+ # Selector aliases and URL precedence are validated by wire.validate_in.
1172
+ # The scalar compiled decoder does not implement that contract yet.
1173
+ or any(
1174
+ entry.get("selector")
1175
+ for entry in (
1176
+ getattr(getattr(opview, "schema_in", None), "by_field", {}) or {}
1177
+ ).values()
1178
+ )
1161
1179
  )
1162
1180
  compiled_param_phase_steps = (
1163
1181
  program_compiled_param_phase_steps[program_id]
@@ -95,6 +95,7 @@ def _route_metadata_for_binding(binding: Any) -> dict[str, Any]:
95
95
  metadata["lane"] = lane
96
96
  metadata["inner_framing"] = framing_kind(inner_framing)
97
97
  metadata["inner_framing_spec"] = framing_spec_name(inner_framing)
98
+ metadata["rpc_method"] = getattr(binding, "rpc_method", None)
98
99
  if inner_framing is not None:
99
100
  metadata["inner_framing_kind"] = str(inner_framing)
100
101
  metadata["inner_framing_spec"] = framing_spec_name(inner_framing)
@@ -206,8 +207,6 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
206
207
  from tigrbl_core._spec.binding_spec import (
207
208
  HttpJsonRpcBindingSpec,
208
209
  HttpRestBindingSpec,
209
- HttpJsonRpcProtocolBindingSpec,
210
- HttpRestProtocolBindingSpec,
211
210
  HttpStreamBindingSpec,
212
211
  SseBindingSpec,
213
212
  WebSocketProtocolBindingSpec,
@@ -281,7 +280,9 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
281
280
  meta_index
282
281
  )
283
282
 
284
- elif isinstance(binding, (HttpJsonRpcBindingSpec, HttpJsonRpcProtocolBindingSpec)):
283
+ elif isinstance(
284
+ binding, (HttpJsonRpcBindingSpec, HttpJsonRpcProtocolBindingSpec)
285
+ ):
285
286
  rpc_path = str(
286
287
  getattr(
287
288
  binding,
@@ -302,8 +303,12 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
302
303
  proto_bucket = route_data.setdefault(
303
304
  binding.proto, {"paths": {}, "endpoints": {}}
304
305
  )
305
- path_bucket = proto_bucket.setdefault("paths", {}).setdefault(rpc_path, {})
306
- endpoint_bucket = proto_bucket.setdefault("endpoints", {}).setdefault(rpc_path, {})
306
+ path_bucket = proto_bucket.setdefault("paths", {}).setdefault(
307
+ rpc_path, {}
308
+ )
309
+ endpoint_bucket = proto_bucket.setdefault(
310
+ "endpoints", {}
311
+ ).setdefault(rpc_path, {})
307
312
  proto_bucket[rpc_method] = meta_index
308
313
  row = {
309
314
  "meta_index": meta_index,
@@ -326,6 +331,17 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
326
331
  bucket = route_data.setdefault(
327
332
  binding.proto, {"exact": {}, "templated": []}
328
333
  )
334
+ if (
335
+ isinstance(
336
+ binding, (WsBindingSpec, WebSocketProtocolBindingSpec)
337
+ )
338
+ and framing_kind(getattr(binding, "framing", None)) == "jsonrpc"
339
+ and bool(getattr(sp, "expose_method", True))
340
+ ):
341
+ # JSON-RPC method operations are dispatched inside the
342
+ # framework-owned WebSocket session. Only the hidden
343
+ # transport operation may own the socket path itself.
344
+ continue
329
345
  selector = binding.path
330
346
  route_metadata = _route_metadata_for_binding(binding)
331
347
  opkey_to_meta[OpKey(proto=binding.proto, selector=selector)] = (
@@ -345,13 +361,25 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
345
361
  }
346
362
  )
347
363
  else:
348
- bucket["exact"][selector] = meta_index
349
- bucket.setdefault("exact_metadata", {})[selector] = {
364
+ route_row = {
350
365
  "path": binding.path,
351
366
  "meta_index": meta_index,
352
367
  "selector": selector,
353
368
  **route_metadata,
354
369
  }
370
+ if binding.proto == "webtransport":
371
+ bucket["exact"].setdefault(selector, meta_index)
372
+ bucket.setdefault("routes", {}).setdefault(
373
+ selector, []
374
+ ).append(route_row)
375
+ bucket.setdefault("exact_metadata", {}).setdefault(
376
+ selector, route_row
377
+ )
378
+ else:
379
+ bucket["exact"][selector] = meta_index
380
+ bucket.setdefault("exact_metadata", {})[selector] = (
381
+ route_row
382
+ )
355
383
 
356
384
  semantic = KernelPlan(
357
385
  proto_indices=route_data,
@@ -51,6 +51,13 @@ class SchemaOut:
51
51
  expose: Tuple[str, ...]
52
52
 
53
53
 
54
+ @dataclass(frozen=True)
55
+ class SchemaStored:
56
+ fields: Tuple[str, ...]
57
+ by_field: Dict[str, Dict[str, object]]
58
+ required_from_client: Tuple[str, ...] = ()
59
+
60
+
54
61
  @dataclass(frozen=True)
55
62
  class OpView:
56
63
  schema_in: SchemaIn
@@ -59,6 +66,7 @@ class OpView:
59
66
  virtual_producers: Dict[str, Callable[[object, dict], object]]
60
67
  to_stored_transforms: Dict[str, Callable[[object, dict], object]]
61
68
  refresh_hints: Tuple[str, ...]
69
+ schema_stored: SchemaStored | None = None
62
70
 
63
71
 
64
72
  @dataclass(frozen=True, slots=True)
@@ -0,0 +1,312 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Dict, Mapping
4
+
5
+ from tigrbl_core.schema.builder.helpers import (
6
+ _normalize_py_type,
7
+ _storage_python_type,
8
+ _spec_python_type,
9
+ _input_selector_entries,
10
+ _input_filter_entries,
11
+ )
12
+
13
+ from .models import OpView, SchemaIn, SchemaOut, SchemaStored
14
+
15
+ _READ_ONLY_TARGETS = frozenset(
16
+ {
17
+ "read",
18
+ "list",
19
+ "count",
20
+ "exists",
21
+ "aggregate",
22
+ "group_by",
23
+ "subscribe",
24
+ "tail",
25
+ "download",
26
+ }
27
+ )
28
+ _NON_PERSISTING_TARGETS = frozenset(
29
+ {
30
+ "delete",
31
+ "clear",
32
+ "bulk_delete",
33
+ "close_stream",
34
+ "close_session",
35
+ }
36
+ )
37
+ _CREATE_LIKE_TARGETS = frozenset({"create", "bulk_create"})
38
+ _UPDATE_LIKE_TARGETS = frozenset({"update", "merge", "bulk_update", "bulk_merge"})
39
+ _REPLACE_LIKE_TARGETS = frozenset({"replace", "bulk_replace"})
40
+
41
+
42
+ def _storage_requires_input(storage: Any, alias: str) -> bool:
43
+ if storage is None or alias == "update":
44
+ return False
45
+ if bool(getattr(storage, "primary_key", False)):
46
+ if alias in {"replace", "delete"}:
47
+ return True
48
+ auto = getattr(storage, "autoincrement", False)
49
+ if auto not in (False, None) or getattr(storage, "identity", None) is not None:
50
+ return False
51
+ has_default = (
52
+ getattr(storage, "default", None) is not None
53
+ or getattr(storage, "server_default", None) is not None
54
+ or callable(getattr(storage, "default_factory", None))
55
+ )
56
+ return not bool(getattr(storage, "nullable", True)) and not has_default
57
+
58
+
59
+ def _storage_has_server_default(spec: Any, storage: Any) -> bool:
60
+ return bool(
61
+ getattr(storage, "default", None) is not None
62
+ or getattr(storage, "server_default", None) is not None
63
+ or callable(getattr(storage, "default_factory", None))
64
+ or callable(getattr(spec, "default_factory", None))
65
+ )
66
+
67
+
68
+ def _supports_stored_shape(target: str) -> bool:
69
+ lowered = str(target or "").lower()
70
+ return lowered not in _READ_ONLY_TARGETS and lowered not in _NON_PERSISTING_TARGETS
71
+
72
+
73
+ def _is_input_enabled(io: Any, semantic_verbs: tuple[str, ...]) -> bool:
74
+ in_verbs = set(getattr(io, "in_verbs", ()) or ())
75
+ return any(name in in_verbs for name in semantic_verbs)
76
+
77
+
78
+ def _is_paired_enabled(io: Any, semantic_verbs: tuple[str, ...]) -> bool:
79
+ cfg = getattr(io, "_paired", None)
80
+ if cfg is None:
81
+ return False
82
+ paired_verbs = set(getattr(cfg, "verbs", ()) or ())
83
+ return any(name in paired_verbs for name in semantic_verbs)
84
+
85
+
86
+ def _include_in_stored_schema(
87
+ *,
88
+ spec: Any,
89
+ io: Any,
90
+ storage: Any,
91
+ semantic_verbs: tuple[str, ...],
92
+ target: str,
93
+ ) -> bool:
94
+ lowered = str(target or "").lower()
95
+ if storage is None or not _supports_stored_shape(lowered):
96
+ return False
97
+ if _is_input_enabled(io, semantic_verbs) or _is_paired_enabled(io, semantic_verbs):
98
+ return True
99
+ if lowered in _CREATE_LIKE_TARGETS or lowered in _UPDATE_LIKE_TARGETS:
100
+ return True
101
+ if lowered in _REPLACE_LIKE_TARGETS:
102
+ return True
103
+ return False
104
+
105
+
106
+ def _stored_required(storage: Any, spec: Any, target: str, *, derived: bool) -> bool:
107
+ lowered = str(target or "").lower()
108
+ if lowered in _UPDATE_LIKE_TARGETS:
109
+ return False
110
+ if lowered in _NON_PERSISTING_TARGETS or lowered in _READ_ONLY_TARGETS:
111
+ return False
112
+ if derived:
113
+ return True
114
+ return not bool(
115
+ getattr(storage, "nullable", True)
116
+ ) and not _storage_has_server_default(
117
+ spec,
118
+ storage,
119
+ )
120
+
121
+
122
+ def compile_opview_from_specs(specs: Mapping[str, Any], sp: Any) -> OpView:
123
+ """Build a basic OpView from collected specs when no app/model is present."""
124
+ alias = str(getattr(sp, "alias", "") or "")
125
+ target = str(getattr(sp, "target", alias) or alias)
126
+ semantic_verbs = tuple(
127
+ dict.fromkeys(
128
+ name for name in (alias, target) if isinstance(name, str) and name
129
+ )
130
+ )
131
+
132
+ in_fields: list[str] = []
133
+ out_fields: list[str] = []
134
+ stored_fields: list[str] = []
135
+ by_field_in: Dict[str, Dict[str, object]] = {}
136
+ by_field_out: Dict[str, Dict[str, object]] = {}
137
+ by_field_stored: Dict[str, Dict[str, object]] = {}
138
+ required_from_client: list[str] = []
139
+ to_stored_transforms: Dict[str, Any] = {}
140
+
141
+ for name, spec in specs.items():
142
+ io = getattr(spec, "io", None)
143
+ fs = getattr(spec, "field", None)
144
+ storage = getattr(spec, "storage", None)
145
+ in_verbs = set(getattr(io, "in_verbs", ()) or ())
146
+ out_verbs = set(getattr(io, "out_verbs", ()) or ())
147
+
148
+ if any(name in in_verbs for name in semantic_verbs):
149
+ in_fields.append(name)
150
+ meta: Dict[str, object] = {"in_enabled": True}
151
+ if storage is None:
152
+ meta["virtual"] = True
153
+ py_type = _spec_python_type(spec)
154
+ if py_type is not None and py_type is not Any:
155
+ meta["py_type"] = py_type
156
+ constraints = getattr(fs, "constraints", {}) or {}
157
+ if isinstance(constraints, Mapping):
158
+ max_length = constraints.get("max_length")
159
+ if isinstance(max_length, int) and max_length > 0:
160
+ meta["max_length"] = max_length
161
+ default_factory = getattr(spec, "default_factory", None)
162
+ if callable(default_factory):
163
+ meta["default_factory"] = default_factory
164
+ alias_in = getattr(io, "alias_in", None)
165
+ if alias_in:
166
+ meta["alias_in"] = alias_in
167
+ header_in = getattr(io, "header_in", None)
168
+ if header_in:
169
+ meta["header_in"] = header_in
170
+ meta["header_required_in"] = bool(
171
+ getattr(io, "header_required_in", False)
172
+ )
173
+ required = bool(
174
+ (
175
+ fs
176
+ and any(
177
+ name in getattr(fs, "required_in", ())
178
+ for name in semantic_verbs
179
+ )
180
+ )
181
+ or _storage_requires_input(storage, target)
182
+ )
183
+ meta["required"] = required
184
+ base_nullable = (
185
+ True if storage is None else getattr(storage, "nullable", True)
186
+ )
187
+ meta["nullable"] = base_nullable
188
+ meta["coerce"] = True
189
+ by_field_in[name] = meta
190
+
191
+ if any(name in out_verbs for name in semantic_verbs):
192
+ out_fields.append(name)
193
+ meta_out: Dict[str, object] = {}
194
+ alias_out = getattr(io, "alias_out", None)
195
+ if alias_out:
196
+ meta_out["alias_out"] = alias_out
197
+ if storage is None:
198
+ meta_out["virtual"] = True
199
+ py_type = getattr(getattr(fs, "py_type", None), "__name__", None)
200
+ if py_type:
201
+ meta_out["py_type"] = py_type
202
+ by_field_out[name] = meta_out
203
+
204
+ if _include_in_stored_schema(
205
+ spec=spec,
206
+ io=io,
207
+ storage=storage,
208
+ semantic_verbs=semantic_verbs,
209
+ target=target,
210
+ ):
211
+ stored_fields.append(name)
212
+ input_enabled = _is_input_enabled(io, semantic_verbs)
213
+ paired_enabled = _is_paired_enabled(io, semantic_verbs)
214
+ server_default = _storage_has_server_default(spec, storage)
215
+ py_type = getattr(fs, "py_type", None)
216
+ if py_type is None or py_type is Any:
217
+ py_type = _storage_python_type(getattr(storage, "type_", None))
218
+ else:
219
+ py_type = _normalize_py_type(py_type)
220
+ stored_meta: Dict[str, object] = {
221
+ "nullable": bool(getattr(storage, "nullable", True)),
222
+ "from_client": input_enabled,
223
+ "required_from_client": bool(
224
+ input_enabled and _storage_requires_input(storage, target)
225
+ ),
226
+ "server_default": server_default,
227
+ }
228
+ if py_type is not Any:
229
+ stored_meta["py_type"] = py_type
230
+ constraints = getattr(fs, "constraints", {}) or {}
231
+ if isinstance(constraints, Mapping):
232
+ max_length = constraints.get("max_length")
233
+ if isinstance(max_length, int) and max_length > 0:
234
+ stored_meta["max_length"] = max_length
235
+
236
+ transform = getattr(getattr(storage, "transform", None), "to_stored", None)
237
+ if callable(transform):
238
+ to_stored_transforms[name] = transform
239
+
240
+ derived = paired_enabled or callable(transform)
241
+ stored_meta["derived"] = derived
242
+ stored_meta["required"] = _stored_required(
243
+ storage,
244
+ spec,
245
+ target,
246
+ derived=derived,
247
+ )
248
+ if stored_meta["required_from_client"]:
249
+ required_from_client.append(name)
250
+ by_field_stored[name] = stored_meta
251
+
252
+ for name, meta in {
253
+ **_input_filter_entries(specs, target),
254
+ **_input_selector_entries(specs, target),
255
+ }.items():
256
+ if name not in by_field_in:
257
+ in_fields.append(name)
258
+ by_field_in[name] = meta
259
+ elif meta.get("selector"):
260
+ by_field_in[name] = {**meta, **by_field_in[name], "selector": True}
261
+
262
+ schema_in = SchemaIn(
263
+ fields=tuple(sorted(in_fields)),
264
+ by_field={field: by_field_in.get(field, {}) for field in sorted(in_fields)},
265
+ )
266
+ schema_out = SchemaOut(
267
+ fields=tuple(sorted(out_fields)),
268
+ by_field={field: by_field_out.get(field, {}) for field in sorted(out_fields)},
269
+ expose=tuple(sorted(out_fields)),
270
+ )
271
+ stored_fields_sorted = tuple(sorted(stored_fields))
272
+ schema_stored = (
273
+ SchemaStored(
274
+ fields=stored_fields_sorted,
275
+ by_field={
276
+ field: by_field_stored.get(field, {}) for field in stored_fields_sorted
277
+ },
278
+ required_from_client=tuple(sorted(required_from_client)),
279
+ )
280
+ if stored_fields_sorted
281
+ else None
282
+ )
283
+ paired_index: Dict[str, Dict[str, object]] = {}
284
+ for field, col in specs.items():
285
+ io = getattr(col, "io", None)
286
+ cfg = getattr(io, "_paired", None)
287
+ if cfg and any(name in getattr(cfg, "verbs", ()) for name in semantic_verbs): # type: ignore[attr-defined]
288
+ field_spec = getattr(col, "field", None)
289
+ max_length = None
290
+ if field_spec is not None:
291
+ max_length = getattr(
292
+ getattr(field_spec, "constraints", {}),
293
+ "get",
294
+ lambda k, d=None: None,
295
+ )("max_length")
296
+ paired_index[field] = {
297
+ "alias": cfg.alias,
298
+ "gen": cfg.gen,
299
+ "store": cfg.store,
300
+ "mask_last": cfg.mask_last,
301
+ "max_length": max_length,
302
+ }
303
+
304
+ return OpView(
305
+ schema_in=schema_in,
306
+ schema_out=schema_out,
307
+ paired_index=paired_index,
308
+ virtual_producers={},
309
+ to_stored_transforms=to_stored_transforms,
310
+ refresh_hints=(),
311
+ schema_stored=schema_stored,
312
+ )