loxtep 0.2.0__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 (75) hide show
  1. loxtep-0.2.0/PKG-INFO +372 -0
  2. loxtep-0.2.0/README.md +354 -0
  3. loxtep-0.2.0/pyproject.toml +43 -0
  4. loxtep-0.2.0/setup.cfg +4 -0
  5. loxtep-0.2.0/src/loxtep/__init__.py +68 -0
  6. loxtep-0.2.0/src/loxtep/activity.py +82 -0
  7. loxtep-0.2.0/src/loxtep/build.py +22 -0
  8. loxtep-0.2.0/src/loxtep/catalog.py +48 -0
  9. loxtep-0.2.0/src/loxtep/cli.py +650 -0
  10. loxtep-0.2.0/src/loxtep/cli_config.py +296 -0
  11. loxtep-0.2.0/src/loxtep/client.py +270 -0
  12. loxtep-0.2.0/src/loxtep/codegen.py +277 -0
  13. loxtep-0.2.0/src/loxtep/connect.py +14 -0
  14. loxtep-0.2.0/src/loxtep/connectors.py +190 -0
  15. loxtep-0.2.0/src/loxtep/context.py +16 -0
  16. loxtep-0.2.0/src/loxtep/data_contracts.py +106 -0
  17. loxtep-0.2.0/src/loxtep/data_products.py +614 -0
  18. loxtep-0.2.0/src/loxtep/define.py +20 -0
  19. loxtep-0.2.0/src/loxtep/discovery.py +148 -0
  20. loxtep-0.2.0/src/loxtep/domains.py +80 -0
  21. loxtep-0.2.0/src/loxtep/errors.py +230 -0
  22. loxtep-0.2.0/src/loxtep/gateway_url.py +130 -0
  23. loxtep-0.2.0/src/loxtep/http_client.py +244 -0
  24. loxtep-0.2.0/src/loxtep/improvements.py +72 -0
  25. loxtep-0.2.0/src/loxtep/instances.py +59 -0
  26. loxtep-0.2.0/src/loxtep/meaning.py +12 -0
  27. loxtep-0.2.0/src/loxtep/models.py +144 -0
  28. loxtep-0.2.0/src/loxtep/observe.py +49 -0
  29. loxtep-0.2.0/src/loxtep/observe_facade.py +36 -0
  30. loxtep-0.2.0/src/loxtep/procedures.py +64 -0
  31. loxtep-0.2.0/src/loxtep/process_intelligence.py +119 -0
  32. loxtep-0.2.0/src/loxtep/project_context.py +109 -0
  33. loxtep-0.2.0/src/loxtep/projects.py +345 -0
  34. loxtep-0.2.0/src/loxtep/quality.py +73 -0
  35. loxtep-0.2.0/src/loxtep/query.py +27 -0
  36. loxtep-0.2.0/src/loxtep/queues.py +191 -0
  37. loxtep-0.2.0/src/loxtep/review.py +19 -0
  38. loxtep-0.2.0/src/loxtep/rstreams/__init__.py +28 -0
  39. loxtep-0.2.0/src/loxtep/rstreams/config.py +96 -0
  40. loxtep-0.2.0/src/loxtep/rstreams/reader.py +249 -0
  41. loxtep-0.2.0/src/loxtep/rstreams/writer.py +251 -0
  42. loxtep-0.2.0/src/loxtep/schemas.py +65 -0
  43. loxtep-0.2.0/src/loxtep/sdk_ingest_bundle.py +192 -0
  44. loxtep-0.2.0/src/loxtep/session.py +28 -0
  45. loxtep-0.2.0/src/loxtep/standards.py +68 -0
  46. loxtep-0.2.0/src/loxtep/targets.py +362 -0
  47. loxtep-0.2.0/src/loxtep/templates.py +80 -0
  48. loxtep-0.2.0/src/loxtep/thesaurus.py +110 -0
  49. loxtep-0.2.0/src/loxtep/triggers.py +370 -0
  50. loxtep-0.2.0/src/loxtep/workflows.py +285 -0
  51. loxtep-0.2.0/src/loxtep/workspace.py +21 -0
  52. loxtep-0.2.0/src/loxtep.egg-info/PKG-INFO +372 -0
  53. loxtep-0.2.0/src/loxtep.egg-info/SOURCES.txt +73 -0
  54. loxtep-0.2.0/src/loxtep.egg-info/dependency_links.txt +1 -0
  55. loxtep-0.2.0/src/loxtep.egg-info/entry_points.txt +2 -0
  56. loxtep-0.2.0/src/loxtep.egg-info/requires.txt +10 -0
  57. loxtep-0.2.0/src/loxtep.egg-info/top_level.txt +1 -0
  58. loxtep-0.2.0/tests/test_cli.py +94 -0
  59. loxtep-0.2.0/tests/test_cli_config_api_base_url.py +53 -0
  60. loxtep-0.2.0/tests/test_cli_config_local_credentials.py +103 -0
  61. loxtep-0.2.0/tests/test_cli_generate.py +88 -0
  62. loxtep-0.2.0/tests/test_client.py +221 -0
  63. loxtep-0.2.0/tests/test_codegen.py +125 -0
  64. loxtep-0.2.0/tests/test_config_export.py +236 -0
  65. loxtep-0.2.0/tests/test_data_products_kind.py +202 -0
  66. loxtep-0.2.0/tests/test_data_products_warehouse.py +70 -0
  67. loxtep-0.2.0/tests/test_errors.py +144 -0
  68. loxtep-0.2.0/tests/test_gateway_url.py +124 -0
  69. loxtep-0.2.0/tests/test_project_context.py +78 -0
  70. loxtep-0.2.0/tests/test_rstreams.py +400 -0
  71. loxtep-0.2.0/tests/test_sdk_ingest_bundle.py +68 -0
  72. loxtep-0.2.0/tests/test_sdk_type_contract.py +180 -0
  73. loxtep-0.2.0/tests/test_targets.py +166 -0
  74. loxtep-0.2.0/tests/test_triggers.py +140 -0
  75. loxtep-0.2.0/tests/test_workflows_projects_parity.py +45 -0
loxtep-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,372 @@
1
+ Metadata-Version: 2.1
2
+ Name: loxtep
3
+ Version: 0.2.0
4
+ Summary: Loxtep Python SDK - data products, workflows, triggers, targets, queues
5
+ Author: Loxtep
6
+ License: UNLICENSED
7
+ Keywords: loxtep,sdk,data-mesh,streaming
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: httpx>=0.27.0
11
+ Requires-Dist: pydantic>=2.0.0
12
+ Provides-Extra: streams
13
+ Requires-Dist: boto3>=1.28.0; extra == "streams"
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest>=7.0; extra == "dev"
16
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
17
+ Requires-Dist: boto3>=1.28.0; extra == "dev"
18
+
19
+ # Loxtep Python SDK
20
+
21
+ Python client for the Loxtep API, organized around one journey: **ingest →
22
+ define → deliver**. Reach for the namespace that matches the stage you're in:
23
+
24
+ - **Ingest** — `triggers`, `connectors`, `workflows`, `data_products.get_writer`
25
+ - **Define** — `data_products`, `schemas`, `quality`, `catalog`, `discovery`,
26
+ `thesaurus`, `domains`, `standards`, `data_contracts`
27
+ - **Deliver** — `data_products` (get_reader/stream/replay/query), `targets`
28
+ - **Advanced / platform** — `projects`, `templates`, `instances`, `observe`,
29
+ `queues`, `metrics`*, `process_intelligence`
30
+
31
+ <sub>* `metrics` is a no-op reporter — matching the Node.js SDK, where it is
32
+ also a no-op stub.</sub>
33
+
34
+ The namespace names, casing, method names, and journey grouping match the
35
+ Node.js SDK — see **Parity with the Node.js SDK** at the bottom.
36
+
37
+ > **Stream bus:** `loxtep.rstreams` is a native Leo data-plane client (Kinesis
38
+ > **write** + DynamoDB/S3 **read**). Enable it with `pip install loxtep[streams]`
39
+ > and pass `streams=` (or set `LEO_*` env).
40
+ >
41
+ > **Not yet ported from the Node.js SDK:** the `config`, `auth`, `codegen`,
42
+ > `skills`, `authoring`, `http`, `checkpoint` modules (client namespaces are at
43
+ > parity). rstreams perf/edge follow-ups: S3 byte-range fast-read, and
44
+ > snapshot/archive queue transitions.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pip install -e .
50
+ # or from repo root: pip install -e sdks/python
51
+ ```
52
+
53
+ ## Quick start
54
+
55
+ ### Sync client
56
+
57
+ ```python
58
+ from loxtep import LoxtepClient
59
+
60
+ client = LoxtepClient(
61
+ api_url="https://api.loxtep.com",
62
+ auth={"type": "jwt", "token": "YOUR_JWT"},
63
+ organization_id="org-id",
64
+ project_id="project-id",
65
+ )
66
+
67
+ # --- Ingest: connect a source and write events ---
68
+ triggers = client.triggers.list()
69
+ # With stream config (streams= / LEO_* env + pip install loxtep[streams]) this
70
+ # writer produces to the Kinesis bus; otherwise it uses the HTTP data path.
71
+ writer = client.data_products.get_writer("my-data-product") # resolves name→id
72
+ writer.write({"id": "e1", "name": "Alice"})
73
+ writer.close()
74
+
75
+ # Workflows (the ingestion → transformation → export DAG)
76
+ workflows = client.workflows.list(project_id="project-id")
77
+ graph = client.workflows.get_graph("workflow-id", "project-id")
78
+
79
+ # --- Define: data products, schema, quality, discovery ---
80
+ asset = client.data_products.get("data-product-id")
81
+ items, pagination = client.data_products.list(page=1, page_size=20)
82
+ results = client.data_products.query("data-product-id", "SELECT * FROM t LIMIT 10")
83
+ client.quality.list()
84
+ client.catalog.search("query")
85
+ # Discovery (access-filtered when user context present)
86
+ client.discovery.search("events", include_evidence=True)
87
+ client.schemas.get("data-product-id")
88
+
89
+ # --- Deliver: consume events and route data out ---
90
+ for event in client.data_products.stream("data-product-id"):
91
+ print(event)
92
+
93
+ # Targets — how a data product delivers data to external systems
94
+ client.targets.list("data-product-id")
95
+ client.targets.create(
96
+ "data-product-id",
97
+ target_type="webhook",
98
+ endpoint_url="https://example.com/hook",
99
+ method="POST",
100
+ )
101
+
102
+ client.close()
103
+ ```
104
+
105
+ ### Async client
106
+
107
+ ```python
108
+ import asyncio
109
+ from loxtep import AsyncLoxtepClient
110
+
111
+ async def main():
112
+ async with AsyncLoxtepClient(
113
+ api_url="https://api.loxtep.com",
114
+ auth={"type": "jwt", "token": "YOUR_JWT"},
115
+ ) as client:
116
+ asset = await client.data_products.get("data-product-id")
117
+ workflows = await client.workflows.list(project_id="project-id")
118
+ async for event in client.data_products.stream("data-product-id"):
119
+ print(event)
120
+
121
+ asyncio.run(main())
122
+ ```
123
+
124
+ ## API surface
125
+
126
+ Grouped by journey stage; kind labels: **Resource** (full CRUD), **Reference**
127
+ (read-only), **Runtime** (live stream I/O).
128
+
129
+ ### Ingest
130
+
131
+ | Surface | Kind | Methods |
132
+ | --- | --- | --- |
133
+ | **triggers** | Resource | `get`, `list`, `create`, `update`, `delete`, `test` |
134
+ | **connectors** | Resource | `list`, `get`, `create`, `update`, `delete`, `test`, `get_oauth_url` |
135
+ | **workflows** | Resource | `list`, `get`, `create`, `get_graph`, `deploy` |
136
+ | **data_products.get_writer** | Runtime | the write path for events (resolves name→id) |
137
+
138
+ ### Define
139
+
140
+ | Surface | Kind | Methods |
141
+ | --- | --- | --- |
142
+ | **data_products** | Resource + Runtime | `get`, `get_lexicon`, `list`, `create`, `readiness`, `promote`, `get_usage_map`, `invalidate_cache`, `search`, `query`, `list_tables`, `get_queue_info`, `get_reader_checkpoint`, `stream`, `replay` |
143
+ | **schemas** | Reference | `get`, `list`, `tag_pii_fields` |
144
+ | **quality** | Resource | `list`, `get`, `create` |
145
+ | **catalog** | Reference | `search` |
146
+ | **discovery** | Reference | `search`, `get_evidence`, `get_lineage_impact`, `get_governance_flags`, `run` |
147
+ | **thesaurus** | Reference | `list_terms`, `resolve_canonical_key`, `append_synonym` |
148
+ | **domains** | Reference | `list`, `get` |
149
+ | **standards** | Reference | `list`, `get` |
150
+ | **data_contracts** | Resource | `list`, `get`, `create`, `update`, `delete` |
151
+
152
+ ### Deliver
153
+
154
+ | Surface | Kind | Methods |
155
+ | --- | --- | --- |
156
+ | **targets** | Resource | `list`, `get`, `create`, `update`, `delete` |
157
+
158
+ ### Advanced / platform
159
+
160
+ | Surface | Kind | Methods |
161
+ | --- | --- | --- |
162
+ | **projects** | Resource | `list`, `get`, `create`, `update`, `delete`, `apply_template`, `repository` |
163
+ | **templates** | Reference | `list`, `get` |
164
+ | **instances** | Reference | `list`, `get`, `get_stream_config` |
165
+ | **procedures** | Reference | `list` |
166
+ | **queues** | — | `get_queue_metadata`, `get_reader_checkpoint`, `open_reader`, `open_writer` |
167
+ | **observe** | — | `status` |
168
+ | **metrics** | — | `log`, `get_reporter` — no-ops (matches Node.js) |
169
+ | **process_intelligence** | — (experimental) | `get_entity_context`, `decision_traces_list` |
170
+
171
+ ### `client.workflows`
172
+
173
+ | Method | Description |
174
+ | --- | --- |
175
+ | `list(project_id, *, page, page_size, status, search)` | List workflows for a project |
176
+ | `get(id)` | Get a workflow (with nodes) |
177
+ | `create(name, project_id, *, template_id, description, configuration)` | Create a workflow |
178
+ | `get_graph(workflow_id, project_id)` | Get the workflow graph definition |
179
+ | `deploy(project_id, instance_id, *, version_id, force_redeploy)` | Deploy a project to an instance |
180
+
181
+ ### `client.triggers`
182
+
183
+ Ingest-side source bindings (external systems that feed a workflow).
184
+
185
+ | Method | Description |
186
+ | --- | --- |
187
+ | `list(*, page, page_size, search, type, status)` | List triggers |
188
+ | `get(id)` | Get a trigger by ID |
189
+ | `create(name, type, key, *, data, configuration, metadata)` | Create a trigger |
190
+ | `update(id, *, name, data, configuration, metadata)` | Update a trigger |
191
+ | `delete(id)` | Delete a trigger |
192
+ | `test(id)` | Test trigger connectivity |
193
+
194
+ ### `client.targets`
195
+
196
+ Delivery sink bindings — how a data product delivers data to external systems
197
+ (webhooks, API endpoints, exports, database syncs, BI connections, event streams).
198
+
199
+ | Method | Description |
200
+ | --- | --- |
201
+ | `list(data_product_id, *, page, page_size, status, is_active)` | List targets for a data product |
202
+ | `get(data_product_id, target_id)` | Get a single target |
203
+ | `create(data_product_id, target_type="webhook", **kwargs)` | Create a target |
204
+ | `update(data_product_id, target_id, **kwargs)` | Update a target |
205
+ | `delete(data_product_id, target_id)` | Delete a target |
206
+
207
+ **`Target` model fields:** `consumption_id`, `data_product_id`,
208
+ `organization_id`, `target_type`, `delivery_method`, `status`, `is_active`,
209
+ `endpoint_url`, `method`, `name`, `description`, `headers`, `filters`,
210
+ `configuration`, `metadata`, `created_at`, `updated_at`.
211
+
212
+ **`target_type` values:** `webhook`, `api_endpoint`, `export`, `database_sync`,
213
+ `bi_connect`, `event_stream`.
214
+
215
+ ### `client.connectors`
216
+
217
+ | Method | Description |
218
+ | --- | --- |
219
+ | `list(*, organization_id, connector_type, page, page_size, sort_by, sort_order)` | List connectors |
220
+ | `get(connector_id)` | Get a single connector |
221
+ | `create(connector_type, *, metadata)` | Create a connector |
222
+ | `update(connector_id, *, connector_type, metadata)` | Update a connector |
223
+ | `delete(connector_id)` | Delete a connector |
224
+ | `test(connector_id)` | Test connector connectivity |
225
+ | `get_oauth_url(connector_id, *, callback_url, toolkit)` | Get the OAuth authorization URL |
226
+
227
+ ### `client.projects`
228
+
229
+ | Method | Description |
230
+ | --- | --- |
231
+ | `list(*, status, search, page, page_size)` | List projects |
232
+ | `get(project_id)` | Get a project by ID |
233
+ | `create(name, *, description, status, metadata, configuration, template_slug, domain_id, ...)` | Create a project |
234
+ | `update(project_id, *, name, description, status, metadata, configuration, ...)` | Update a project |
235
+ | `delete(project_id)` | Delete a project |
236
+ | `apply_template(project_id, *, template_type, template_slug, preview, placeholder_overrides)` | Apply a template |
237
+
238
+ ### `client.templates`
239
+
240
+ | Method | Description |
241
+ | --- | --- |
242
+ | `list(*, category, search, page, page_size)` | List available templates |
243
+ | `get(template_id)` | Get a template by ID |
244
+
245
+ ### `client.data_products`
246
+
247
+ | Method | Description |
248
+ | --- | --- |
249
+ | `get(id, *, include_schema, include_quality)` | Get a data product by ID |
250
+ | `get_lexicon(id)` | Glossary terms + field→glossary map for a data product |
251
+ | `list(*, page, page_size, domain_id, status, kind, sort_by, sort_order)` | List data products |
252
+ | `create(*, name, kind, description, domain, **kwargs)` | Create a data product (`kind` required: `'source'` or `'consumer'`) |
253
+ | `readiness(data_product_id)` | Promotion readiness (prerequisites, progress, promotable) |
254
+ | `promote(data_product_id, target_tier)` | Execute medallion tier promotion (`'silver'` / `'gold'`) |
255
+ | `get_usage_map()` | Fetch the Data Product Usage Map (source→consumer relationships) |
256
+ | `invalidate_cache(id_or_name=None)` | Clear the name→id resolution cache |
257
+ | `get_writer(id_or_name)` | Writer bound to the data product (resolves name→id) |
258
+ | `get_reader(id_or_name, *, start, batch_size)` | Iterator of events (resolves name→id) |
259
+ | `search(query, *, type, limit, offset)` | Search data products |
260
+ | `query(id, sql)` | Run SQL against a data product |
261
+ | `list_tables(id)` | List tables in a data product |
262
+ | `get_queue_info(id)` | Get queue info for a data product |
263
+ | `get_reader_checkpoint(id, bot_id)` | Get reader checkpoint for a bot |
264
+ | `stream(id, *, start, batch_size)` | Stream events (sync generator) |
265
+ | `replay(id, *, start, batch_size)` | Replay events (sync generator) |
266
+
267
+ > **Writer/reader transport:** when the client is configured with stream-bus
268
+ > config (`streams=` or `LEO_*` env) and `boto3` is installed
269
+ > (`pip install loxtep[streams]`), `data_products.get_writer` returns a **native
270
+ > Kinesis producer** and `get_reader` a **native DynamoDB/S3 consumer** — the
271
+ > performant path, matching the Node.js SDK — on both the sync and async
272
+ > clients. Without stream config both fall back to the HTTP data path. Pass
273
+ > `auto_checkpoint=True` (or call `reader.checkpoint()`) to persist read
274
+ > position to LeoCron. See the `loxtep.rstreams` module.
275
+
276
+ ### `client.thesaurus`
277
+
278
+ Canonical correlation keys + aliases.
279
+
280
+ | Method | Description |
281
+ | --- | --- |
282
+ | `list_terms(org_id=None)` | List thesaurus terms for the organization |
283
+ | `resolve_canonical_key(key_or_alias, org_id=None)` | Resolve a key/alias to its canonical key (client-side match) |
284
+ | `append_synonym(canonical_key, alias_path, *, system, precedence, org_id)` | Append a synonym/alias to a canonical key |
285
+
286
+ ### `client.instances`
287
+
288
+ | Method | Description |
289
+ | --- | --- |
290
+ | `list()` | List runtime instances for the organization |
291
+ | `get(instance_id)` | Get a single instance by ID |
292
+
293
+ ### `client.procedures`
294
+
295
+ | Method | Description |
296
+ | --- | --- |
297
+ | `list(organization_id, *, page, page_size)` | List procedures for an organization |
298
+
299
+ ### `client.observe`
300
+
301
+ | Method | Description |
302
+ | --- | --- |
303
+ | `status()` | GET /observe/bots — bot/queue observability summary |
304
+
305
+ ### `client.metrics`
306
+
307
+ `metrics.log` / `metrics.get_reporter` are no-ops — matching the Node.js SDK,
308
+ where the metrics surface is also a no-op stub (it POSTs nowhere).
309
+
310
+ ### `client.process_intelligence` (experimental)
311
+
312
+ Returns unified context from connected systems for a given entity. Experimental
313
+ and excluded from the core surface (parity with the Node.js SDK).
314
+
315
+ ```python
316
+ context = client.process_intelligence.get_entity_context("org-id", "order", "4821")
317
+ ```
318
+
319
+ ## Type hints
320
+
321
+ Types are hand-written; all public methods and responses use type hints. Run
322
+ `mypy src/loxtep` for static checking.
323
+
324
+ ## CLI
325
+
326
+ After `pip install -e .` you get a `loxtep` command:
327
+
328
+ - **login** – runs Node.js `loxtep login` (requires Node/npx)
329
+ - **query** / **stream** / **replay** – data-product operations (Python SDK)
330
+ - **workflows list** / **workflows deploy** – (Python SDK)
331
+ - **observe status** – bot/queue status (Python SDK)
332
+ - **projects list** / **projects get** – (Python SDK)
333
+ - **templates list** / **templates get** – (Python SDK)
334
+ - **config export** – export SDK bootstrap config from a connector (Python SDK)
335
+
336
+ Config: `~/.loxtep/config.json` or env `LOXTEP_API_URL`,
337
+ `LOXTEP_ORGANIZATION_ID`, `LOXTEP_PROJECT_ID`. Auth: run `loxtep login` once or
338
+ set `LOXTEP_TOKEN`.
339
+
340
+ See [docs/CLI.md](docs/CLI.md) for full CLI usage.
341
+
342
+ ## Parity with the Node.js SDK
343
+
344
+ The **client surface matches**: same namespace names, same `snake_case` method
345
+ names, same ingest → define → deliver grouping. `flows` merged into `workflows`,
346
+ `connections`→`triggers`, `delivery`→`targets`, `data_products` writer/reader +
347
+ `get_lexicon`/`readiness`/`promote`/`invalidate_cache`, `schemas.list`/
348
+ `tag_pii_fields`, `quality.create`, `projects.repository`,
349
+ `instances.get_stream_config`, and the `thesaurus` namespace are all present.
350
+ `improvements`/`activity`/`process_intelligence` exist and are internal/
351
+ experimental (excluded from the documented surface), matching Node.
352
+
353
+ Remaining, intentional differences:
354
+
355
+ | Area | Node.js | Python |
356
+ | --- | --- | --- |
357
+ | `get_writer` / `get_reader` transport (sync + async) | rstreams stream bus | **native Kinesis producer + DynamoDB/S3 consumer** (`loxtep.rstreams`) when configured; HTTP fallback |
358
+ | LeoCron checkpoint persistence | yes | yes (`auto_checkpoint=` / `reader.checkpoint()`) |
359
+ | large-payload S3 write-offload (>600 KB) | auto | auto (uploads gzipped NDJSON + emits S3-pointer record) |
360
+ | S3 byte-range fast-read; snapshot/archive queues | yes | follow-ups (whole-object read is correct; live/modern queues supported) |
361
+ | `metrics` | no-op stub | no-op stub (identical) |
362
+ | Author-side modules (`config`, `auth`, `codegen`, `skills`, `authoring`, `http`, `checkpoint`) | present | not ported |
363
+
364
+ `domains`, `standards`, and `data_contracts` are real HTTP-backed namespaces.
365
+ The `loxtep.rstreams` module is a native Leo data-plane client — sync **and**
366
+ async write + read, LeoCron checkpointing, and >600 KB S3 write-offload — with no
367
+ dependency on any external Leo SDK. Remaining follow-ups are perf/edge only:
368
+ S3 byte-range fast-read, and snapshot/archive queue transitions.
369
+
370
+ The low-level writer escape hatch (`workflows.get_writer`, formerly
371
+ `flows.get_writer`) exists in both and is intentionally undocumented for
372
+ customers.