mainsequence 4.0.16__tar.gz → 4.1.2__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.
- {mainsequence-4.0.16 → mainsequence-4.1.2}/PKG-INFO +9 -10
- {mainsequence-4.0.16 → mainsequence-4.1.2}/README.md +8 -8
- mainsequence-4.1.2/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +380 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/api.py +408 -96
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/cli.py +489 -27
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/__init__.py +4 -1
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/base.py +1 -2
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/data_sources_interfaces/duckdb.py +11 -9
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/data_sources_interfaces/sqlite.py +15 -7
- mainsequence-4.1.2/mainsequence/client/models_foundry.py +1064 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/models_helpers.py +2 -3
- mainsequence-4.0.16/mainsequence/client/models_tdag.py → mainsequence-4.1.2/mainsequence/client/models_metatables.py +3679 -4185
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/utils.py +39 -30
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence}/meta_tables/__init__.py +20 -1
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/config.py +18 -27
- mainsequence-4.1.2/mainsequence/meta_tables/configuration_models.py +5 -0
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/data_nodes/__init__.py +1 -2
- mainsequence-4.1.2/mainsequence/meta_tables/data_nodes/build_operations.py +476 -0
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/data_nodes/data_nodes.py +194 -504
- mainsequence-4.1.2/mainsequence/meta_tables/data_nodes/models.py +106 -0
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/data_nodes/namespacing.py +10 -7
- mainsequence-4.0.16/mainsequence/tdag/base_persist_managers.py → mainsequence-4.1.2/mainsequence/meta_tables/data_nodes/persist_managers.py +244 -230
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/data_nodes/run_operations.py +142 -111
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence}/meta_tables/hashing.py +5 -7
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/pydantic_metadata.py +20 -31
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence}/meta_tables/sqlalchemy_contracts.py +782 -16
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence.egg-info/PKG-INFO +9 -10
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence.egg-info/SOURCES.txt +19 -24
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence.egg-info/requires.txt +0 -1
- {mainsequence-4.0.16 → mainsequence-4.1.2}/pyproject.toml +1 -2
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_build_operations_hashing.py +58 -119
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_cli.py +277 -76
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_data_access_mixin_dimension_audit.py +37 -20
- mainsequence-4.1.2/tests/test_data_node_storage_dimension_queries.py +316 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_data_node_update_flow.py +95 -46
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_dependency_extras.py +5 -2
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_duckdb_interface_dimensions.py +10 -12
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_filter_normalization.py +60 -45
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_meta_tables_client_models.py +1 -1
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_meta_tables_sqlalchemy_contracts.py +379 -8
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_pod_project_resolution.py +70 -104
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_project_batch_jobs_from_file.py +2 -3
- mainsequence-4.1.2/tests/test_run_configuration.py +796 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_secret_client_model.py +1 -1
- mainsequence-4.1.2/tests/test_source_table_configuration.py +233 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_sqlite_interface_dimensions.py +7 -7
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_update_runner_uid_runtime.py +91 -8
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_update_statistics.py +2 -2
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_update_uid_guards.py +4 -4
- mainsequence-4.0.16/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -334
- mainsequence-4.0.16/mainsequence/client/models_metatables.py +0 -582
- mainsequence-4.0.16/mainsequence/tdag/__init__.py +0 -37
- mainsequence-4.0.16/mainsequence/tdag/configuration_models.py +0 -23
- mainsequence-4.0.16/mainsequence/tdag/data_nodes/build_operations.py +0 -797
- mainsequence-4.0.16/mainsequence/tdag/data_nodes/filters.py +0 -85
- mainsequence-4.0.16/mainsequence/tdag/data_nodes/models.py +0 -349
- mainsequence-4.0.16/mainsequence/tdag/data_nodes/persist_managers.py +0 -131
- mainsequence-4.0.16/mainsequence/tdag/filters.py +0 -201
- mainsequence-4.0.16/tests/test_data_node_search_join_filters.py +0 -209
- mainsequence-4.0.16/tests/test_data_node_storage_dimension_queries.py +0 -508
- mainsequence-4.0.16/tests/test_run_configuration.py +0 -413
- mainsequence-4.0.16/tests/test_source_table_configuration.py +0 -400
- {mainsequence-4.0.16 → mainsequence-4.1.2}/LICENSE +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/__init__.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/__main__.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/bootstrap.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/config.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/client.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/compute_validation.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/defaults.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/logconf.py +0 -0
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/__main__.py +0 -0
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence}/meta_tables/compiled_sql.py +0 -0
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/data_nodes/utils.py +0 -0
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/future_registry.py +0 -0
- {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.2/mainsequence/meta_tables}/utils.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/setup.cfg +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_auth_precedence.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_client.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_logconf.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.0.16 → mainsequence-4.1.2}/tests/test_workspace_snapshot.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mainsequence
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.1.2
|
|
4
4
|
Summary: Main Sequence SDK
|
|
5
5
|
Author-email: Main Sequence GmbH <dev@main-sequence.io>
|
|
6
6
|
License: MainSequence GmbH SDK License Agreement
|
|
@@ -55,7 +55,6 @@ Description-Content-Type: text/markdown
|
|
|
55
55
|
License-File: LICENSE
|
|
56
56
|
Requires-Dist: cachetools
|
|
57
57
|
Requires-Dist: click>=8.3.0
|
|
58
|
-
Requires-Dist: cloudpickle
|
|
59
58
|
Requires-Dist: concurrent-log-handler
|
|
60
59
|
Requires-Dist: numpy
|
|
61
60
|
Requires-Dist: opentelemetry-api
|
|
@@ -93,7 +92,7 @@ The Main Sequence Python SDK is the client and development toolkit for the Main
|
|
|
93
92
|
|
|
94
93
|
The Main Sequence platform allows you to:
|
|
95
94
|
|
|
96
|
-
1. rapidly build and deploy data products and data workflows as a unified API with
|
|
95
|
+
1. rapidly build and deploy data products and data workflows as a unified API with normalized table contracts through `MetaTable`s and `DataNode`s
|
|
97
96
|
2. rapidly deploy RBAC-enabled dashboards on the platform
|
|
98
97
|
3. rapidly deploy agents using the Google Agent SDK
|
|
99
98
|
|
|
@@ -114,7 +113,7 @@ This repository contains the SDK and the documentation used to build and operate
|
|
|
114
113
|
|
|
115
114
|
Main package areas:
|
|
116
115
|
|
|
117
|
-
- `mainsequence.
|
|
116
|
+
- `mainsequence.meta_tables`: `MetaTable`s, `DataNode`s, update workflows, and persistence
|
|
118
117
|
- `mainsequence.client`: API client models for projects, jobs, data node storages, sharing, and platform resources
|
|
119
118
|
- `mainsequence.cli`: the `mainsequence` command-line interface
|
|
120
119
|
|
|
@@ -137,10 +136,10 @@ Recommended entry points:
|
|
|
137
136
|
|
|
138
137
|
- Tutorial:
|
|
139
138
|
- [Setting a Project (CLI)](docs/tutorial/setting_a_project.md)
|
|
140
|
-
- [Creating a Data Node](docs/tutorial/creating_a_simple_data_node.md)
|
|
141
139
|
- [Working With MetaTables](docs/tutorial/working_with_meta_tables.md)
|
|
142
|
-
- [
|
|
140
|
+
- [Creating a Data Node](docs/tutorial/creating_a_simple_data_node.md)
|
|
143
141
|
- [Role-Based Access Control](docs/tutorial/role_based_access_control.md)
|
|
142
|
+
- [Create Your First API](docs/tutorial/create_your_first_api.md)
|
|
144
143
|
- [Turn Your Project Into an Agent](docs/tutorial/project_to_agent.md)
|
|
145
144
|
- Knowledge:
|
|
146
145
|
- [Data Nodes](docs/knowledge/data_nodes.md)
|
|
@@ -189,10 +188,10 @@ mainsequence project build_local_venv --path .
|
|
|
189
188
|
|
|
190
189
|
From there, the normal learning path is:
|
|
191
190
|
|
|
192
|
-
1.
|
|
193
|
-
2.
|
|
194
|
-
3.
|
|
195
|
-
4.
|
|
191
|
+
1. model your first canonical table with a backend-managed `MetaTable`
|
|
192
|
+
2. create your first `DataNode` as an opinionated MetaTable-backed update workflow
|
|
193
|
+
3. understand sharing and RBAC for published tables
|
|
194
|
+
4. add an API or another application surface
|
|
196
195
|
5. schedule jobs
|
|
197
196
|
6. build dashboards or downstream consumers
|
|
198
197
|
7. package the project as an agent-facing surface when the repository is ready
|
|
@@ -13,7 +13,7 @@ The Main Sequence Python SDK is the client and development toolkit for the Main
|
|
|
13
13
|
|
|
14
14
|
The Main Sequence platform allows you to:
|
|
15
15
|
|
|
16
|
-
1. rapidly build and deploy data products and data workflows as a unified API with
|
|
16
|
+
1. rapidly build and deploy data products and data workflows as a unified API with normalized table contracts through `MetaTable`s and `DataNode`s
|
|
17
17
|
2. rapidly deploy RBAC-enabled dashboards on the platform
|
|
18
18
|
3. rapidly deploy agents using the Google Agent SDK
|
|
19
19
|
|
|
@@ -34,7 +34,7 @@ This repository contains the SDK and the documentation used to build and operate
|
|
|
34
34
|
|
|
35
35
|
Main package areas:
|
|
36
36
|
|
|
37
|
-
- `mainsequence.
|
|
37
|
+
- `mainsequence.meta_tables`: `MetaTable`s, `DataNode`s, update workflows, and persistence
|
|
38
38
|
- `mainsequence.client`: API client models for projects, jobs, data node storages, sharing, and platform resources
|
|
39
39
|
- `mainsequence.cli`: the `mainsequence` command-line interface
|
|
40
40
|
|
|
@@ -57,10 +57,10 @@ Recommended entry points:
|
|
|
57
57
|
|
|
58
58
|
- Tutorial:
|
|
59
59
|
- [Setting a Project (CLI)](docs/tutorial/setting_a_project.md)
|
|
60
|
-
- [Creating a Data Node](docs/tutorial/creating_a_simple_data_node.md)
|
|
61
60
|
- [Working With MetaTables](docs/tutorial/working_with_meta_tables.md)
|
|
62
|
-
- [
|
|
61
|
+
- [Creating a Data Node](docs/tutorial/creating_a_simple_data_node.md)
|
|
63
62
|
- [Role-Based Access Control](docs/tutorial/role_based_access_control.md)
|
|
63
|
+
- [Create Your First API](docs/tutorial/create_your_first_api.md)
|
|
64
64
|
- [Turn Your Project Into an Agent](docs/tutorial/project_to_agent.md)
|
|
65
65
|
- Knowledge:
|
|
66
66
|
- [Data Nodes](docs/knowledge/data_nodes.md)
|
|
@@ -109,10 +109,10 @@ mainsequence project build_local_venv --path .
|
|
|
109
109
|
|
|
110
110
|
From there, the normal learning path is:
|
|
111
111
|
|
|
112
|
-
1.
|
|
113
|
-
2.
|
|
114
|
-
3.
|
|
115
|
-
4.
|
|
112
|
+
1. model your first canonical table with a backend-managed `MetaTable`
|
|
113
|
+
2. create your first `DataNode` as an opinionated MetaTable-backed update workflow
|
|
114
|
+
3. understand sharing and RBAC for published tables
|
|
115
|
+
4. add an API or another application surface
|
|
116
116
|
5. schedule jobs
|
|
117
117
|
6. build dashboards or downstream consumers
|
|
118
118
|
7. package the project as an agent-facing surface when the repository is ready
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mainsequence-data-nodes
|
|
3
|
+
description: Use this skill when the task is about producing, changing, validating, or reviewing Main Sequence DataNode update processes. This skill owns DataNode update configuration, dependencies, update logic, hashing, namespaces, and validation against a PlatformTimeIndexMetaData storage contract. It does not own generic MetaTable governance, API route contracts, scheduling, sharing policy, or storage registration internals.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Main Sequence Data Nodes
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Use this skill when the task changes a DataNode producer.
|
|
11
|
+
|
|
12
|
+
A DataNode is an update process. It is not the canonical storage model. Storage
|
|
13
|
+
is defined by a registered `PlatformTimeIndexMetaData` SQLAlchemy model.
|
|
14
|
+
|
|
15
|
+
Canonical workflow:
|
|
16
|
+
|
|
17
|
+
1. Define a `PlatformTimeIndexMetaData` storage class.
|
|
18
|
+
2. Register or bind that storage class before constructing the DataNode.
|
|
19
|
+
3. Construct the DataNode with `config=...` and `storage_table=StorageClass`.
|
|
20
|
+
4. Return a DataFrame from `update()` that matches the storage class contract.
|
|
21
|
+
|
|
22
|
+
## This Skill Can Do
|
|
23
|
+
|
|
24
|
+
- create a new `DataNode` update process
|
|
25
|
+
- modify an existing `DataNode` update process
|
|
26
|
+
- review whether a DataNode change affects update identity or table contract
|
|
27
|
+
- define or refactor `DataNodeConfiguration`
|
|
28
|
+
- classify config fields into update identity and hash-excluded descriptive metadata
|
|
29
|
+
- implement or review:
|
|
30
|
+
- `dependencies()`
|
|
31
|
+
- `update()`
|
|
32
|
+
- `prepare_update_statistics()`
|
|
33
|
+
- `get_asset_list()` when the update is asset scoped
|
|
34
|
+
- design single-index or `(time_index, unique_identifier)` DataFrame outputs
|
|
35
|
+
- validate output shape against a `PlatformTimeIndexMetaData` storage contract
|
|
36
|
+
- define explicit `hash_namespace(...)` validation strategy
|
|
37
|
+
- write or review DataNode smoke tests
|
|
38
|
+
- decide whether a consumer should use `APIDataNode`
|
|
39
|
+
|
|
40
|
+
## This Skill Must Not Claim
|
|
41
|
+
|
|
42
|
+
This skill must not claim ownership of:
|
|
43
|
+
|
|
44
|
+
- generic MetaTable registration or governed operation semantics
|
|
45
|
+
- storage creation inside `DataNode` or `PersistManager`
|
|
46
|
+
- HTTP route design or FastAPI response contracts
|
|
47
|
+
- workspace/widget layout payloads
|
|
48
|
+
- job creation, scheduling, image pinning, or release creation
|
|
49
|
+
- RBAC or sharing policy
|
|
50
|
+
- domain strategy semantics
|
|
51
|
+
|
|
52
|
+
If the task depends on one of those areas, route it explicitly instead of guessing.
|
|
53
|
+
|
|
54
|
+
## Route Adjacent Work
|
|
55
|
+
|
|
56
|
+
- MetaTables and storage contracts:
|
|
57
|
+
`.agents/skills/mainsequence/data_publishing/meta_tables/SKILL.md`
|
|
58
|
+
- APIs and FastAPI:
|
|
59
|
+
`.agents/skills/mainsequence/application_surfaces/api_surfaces/SKILL.md`
|
|
60
|
+
- Command Center workspaces:
|
|
61
|
+
`.agents/skills/mainsequence/command_center/workspace_builder/SKILL.md`
|
|
62
|
+
- AppComponents and custom forms:
|
|
63
|
+
`.agents/skills/mainsequence/command_center/app_components/SKILL.md`
|
|
64
|
+
- Jobs, images, resources, and releases:
|
|
65
|
+
`.agents/skills/mainsequence/platform_operations/orchestration_and_releases/SKILL.md`
|
|
66
|
+
- RBAC and sharing:
|
|
67
|
+
`.agents/skills/mainsequence/platform_operations/access_control_and_sharing/SKILL.md`
|
|
68
|
+
|
|
69
|
+
## Read First
|
|
70
|
+
|
|
71
|
+
1. `docs/knowledge/data_nodes.md`
|
|
72
|
+
2. `docs/knowledge/meta_tables/sqlalchemy.md`
|
|
73
|
+
|
|
74
|
+
## Inputs This Skill Needs
|
|
75
|
+
|
|
76
|
+
Before changing code, collect or infer:
|
|
77
|
+
|
|
78
|
+
- dataset meaning
|
|
79
|
+
- registered `PlatformTimeIndexMetaData` storage class or the class to create
|
|
80
|
+
- expected time index and identity index shape
|
|
81
|
+
- expected columns and dtypes from the storage class
|
|
82
|
+
- upstream dependencies
|
|
83
|
+
- whether the update is asset scoped
|
|
84
|
+
- first-run or backfill bounds
|
|
85
|
+
- whether the change must preserve the existing table contract
|
|
86
|
+
|
|
87
|
+
If one of these is unknown and changes the contract, stop and resolve it before
|
|
88
|
+
implementation.
|
|
89
|
+
|
|
90
|
+
## Required Decisions
|
|
91
|
+
|
|
92
|
+
For every non-trivial DataNode task, make these decisions explicitly:
|
|
93
|
+
|
|
94
|
+
1. Is this a new dataset or the same dataset?
|
|
95
|
+
2. Is this change storage-contract work or update-process work?
|
|
96
|
+
3. Is the storage class already registered or should the MetaTable skill handle it?
|
|
97
|
+
4. Is the node single-index or MultiIndex?
|
|
98
|
+
5. Does the first validation run happen under an explicit `hash_namespace(...)`?
|
|
99
|
+
|
|
100
|
+
## Build Rules
|
|
101
|
+
|
|
102
|
+
### 1. Treat Storage As A PlatformTimeIndexMetaData Contract
|
|
103
|
+
|
|
104
|
+
The following are storage-contract decisions:
|
|
105
|
+
|
|
106
|
+
- table namespace and identifier
|
|
107
|
+
- SQLAlchemy columns and dtypes
|
|
108
|
+
- time index name
|
|
109
|
+
- identity index names
|
|
110
|
+
- foreign keys
|
|
111
|
+
- table description and labels
|
|
112
|
+
|
|
113
|
+
Do not put those concerns in `DataNodeConfiguration`.
|
|
114
|
+
|
|
115
|
+
Minimal pattern:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
import datetime
|
|
119
|
+
|
|
120
|
+
from sqlalchemy import DateTime, Float, MetaData
|
|
121
|
+
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
122
|
+
|
|
123
|
+
from mainsequence.meta_tables import PlatformTimeIndexMetaData
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class Base(DeclarativeBase):
|
|
127
|
+
metadata = MetaData()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class PricesTable(PlatformTimeIndexMetaData, Base):
|
|
131
|
+
__metatable_namespace__ = "<domain_namespace>"
|
|
132
|
+
__metatable_identifier__ = "<table_identifier>"
|
|
133
|
+
__time_index_name__ = "time_index"
|
|
134
|
+
__index_names__ = ["time_index", "unique_identifier"]
|
|
135
|
+
|
|
136
|
+
time_index: Mapped[datetime.datetime] = mapped_column(
|
|
137
|
+
DateTime(timezone=True),
|
|
138
|
+
nullable=False,
|
|
139
|
+
)
|
|
140
|
+
unique_identifier: Mapped[str] = mapped_column(nullable=False)
|
|
141
|
+
close: Mapped[float] = mapped_column(Float, nullable=False)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Register or bind storage before constructing the DataNode:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
PricesTable.register(data_source_uid=data_source_uid)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
or:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
PricesTable.bind_meta_table(existing_meta_table)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 2. Keep DataNode As Update Logic
|
|
157
|
+
|
|
158
|
+
The DataNode constructor should accept:
|
|
159
|
+
|
|
160
|
+
- a `DataNodeConfiguration`
|
|
161
|
+
- a registered `storage_table: type[PlatformTimeIndexMetaData]`
|
|
162
|
+
- optional `hash_namespace`
|
|
163
|
+
|
|
164
|
+
The constructor `storage_table` is the output storage contract. Keep it out of
|
|
165
|
+
`DataNodeConfiguration`.
|
|
166
|
+
|
|
167
|
+
If the DataNode needs to select another DataNode's storage table as a
|
|
168
|
+
dependency, put that dependency storage reference in the config as
|
|
169
|
+
`type[PlatformTimeIndexMetaData]`. Do not add an extra constructor argument for
|
|
170
|
+
dependency storage tables. Config values of this type are hashed by the bound
|
|
171
|
+
`TimeIndexMetaData.uid` from `StorageClass.__time_index_metadata__`, so the class
|
|
172
|
+
must be registered or bound before DataNode construction.
|
|
173
|
+
|
|
174
|
+
Do not accept `test_node`. It has been removed. Use explicit
|
|
175
|
+
`hash_namespace(...)` or `hash_namespace="..."`.
|
|
176
|
+
|
|
177
|
+
Pattern:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from mainsequence.meta_tables import DataNode, DataNodeConfiguration
|
|
181
|
+
from mainsequence.meta_tables import PlatformTimeIndexMetaData
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class PricesConfig(DataNodeConfiguration):
|
|
185
|
+
shard_id: str
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class PricesUpdate(DataNode):
|
|
189
|
+
def __init__(
|
|
190
|
+
self,
|
|
191
|
+
config: PricesConfig,
|
|
192
|
+
storage_table: type[PlatformTimeIndexMetaData],
|
|
193
|
+
*,
|
|
194
|
+
hash_namespace: str | None = None,
|
|
195
|
+
):
|
|
196
|
+
self.config = config
|
|
197
|
+
super().__init__(
|
|
198
|
+
config=config,
|
|
199
|
+
storage_table=storage_table,
|
|
200
|
+
hash_namespace=hash_namespace,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def dependencies(self):
|
|
204
|
+
return {}
|
|
205
|
+
|
|
206
|
+
def update(self):
|
|
207
|
+
...
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 3. Configuration Is Update-Scoped By Default
|
|
211
|
+
|
|
212
|
+
Every `DataNodeConfiguration` field participates in `update_hash` by default.
|
|
213
|
+
|
|
214
|
+
Do not use:
|
|
215
|
+
|
|
216
|
+
- `json_schema_extra={"update_only": True}`
|
|
217
|
+
- `json_schema_extra={"runtime_only": True}`
|
|
218
|
+
- `json_schema_extra={"ignore_from_storage_hash": True}`
|
|
219
|
+
- `_ARGS_IGNORE_IN_STORAGE_HASH`
|
|
220
|
+
|
|
221
|
+
Those are removed. The only supported opt-out is:
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
Field(..., json_schema_extra={"hash_excluded": True})
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Use `hash_excluded` only for descriptive metadata that must not affect update
|
|
228
|
+
identity. If a field changes output values, dependencies, source choice, or
|
|
229
|
+
updater scope, it must remain a normal config field.
|
|
230
|
+
|
|
231
|
+
### 4. `hash_namespace` Is Isolation Only
|
|
232
|
+
|
|
233
|
+
Use explicit `hash_namespace(...)` for:
|
|
234
|
+
|
|
235
|
+
- namespaced tests
|
|
236
|
+
- isolated experimentation
|
|
237
|
+
- shared-backend safety
|
|
238
|
+
|
|
239
|
+
Do not use namespace to encode business meaning.
|
|
240
|
+
|
|
241
|
+
Do not use `test_node=True`; it is not supported.
|
|
242
|
+
|
|
243
|
+
### 5. `update()` Should Be Incremental By Default
|
|
244
|
+
|
|
245
|
+
Use `UpdateStatistics`.
|
|
246
|
+
|
|
247
|
+
Do not fetch or return full history every run unless there is a documented
|
|
248
|
+
reason.
|
|
249
|
+
|
|
250
|
+
### 6. `time_index` Must Be Nanosecond UTC
|
|
251
|
+
|
|
252
|
+
Every non-empty DataFrame returned by `update()` must have its first index
|
|
253
|
+
level named `time_index` with dtype exactly `datetime64[ns, UTC]`.
|
|
254
|
+
|
|
255
|
+
Do not rely on `pd.Timestamp.now("UTC").normalize()` or
|
|
256
|
+
`pd.Timestamp.now("UTC").floor(...)` alone. Some pandas versions preserve
|
|
257
|
+
microsecond resolution and produce `datetime64[us, UTC]`, which the DataNode
|
|
258
|
+
runtime rejects.
|
|
259
|
+
|
|
260
|
+
For a single-index DataFrame, construct the index with an explicit dtype:
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
time_index = pd.Timestamp.now("UTC").normalize()
|
|
264
|
+
return pd.DataFrame(
|
|
265
|
+
{"close": [100.0]},
|
|
266
|
+
index=pd.DatetimeIndex(
|
|
267
|
+
[time_index],
|
|
268
|
+
name="time_index",
|
|
269
|
+
dtype="datetime64[ns, UTC]",
|
|
270
|
+
),
|
|
271
|
+
)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
For a MultiIndex DataFrame, construct the time level separately:
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
time_index = pd.DatetimeIndex(
|
|
278
|
+
[row[0] for row in rows],
|
|
279
|
+
dtype="datetime64[ns, UTC]",
|
|
280
|
+
)
|
|
281
|
+
index = pd.MultiIndex.from_arrays(
|
|
282
|
+
[
|
|
283
|
+
time_index,
|
|
284
|
+
[row[1] for row in rows],
|
|
285
|
+
],
|
|
286
|
+
names=["time_index", "unique_identifier"],
|
|
287
|
+
)
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
The validator error to prevent is:
|
|
291
|
+
|
|
292
|
+
```text
|
|
293
|
+
Time index must be datetime64[ns, UTC]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 7. Dependencies Must Be Deterministic
|
|
297
|
+
|
|
298
|
+
Dependencies belong in constructor setup and `dependencies()`.
|
|
299
|
+
|
|
300
|
+
Dependency storage-table selection belongs in `DataNodeConfiguration`, because
|
|
301
|
+
changing it changes the dependency graph and update identity.
|
|
302
|
+
|
|
303
|
+
Do not construct dependency graphs dynamically inside `update()`.
|
|
304
|
+
|
|
305
|
+
### 8. Asset-Scoped Updates Must Be Explicit
|
|
306
|
+
|
|
307
|
+
If the node emits `(time_index, unique_identifier)`:
|
|
308
|
+
|
|
309
|
+
- `unique_identifier` should represent an Asset identity
|
|
310
|
+
- asset scope should live in update configuration when it affects the updater
|
|
311
|
+
- `get_asset_list()` must reflect the effective updater asset scope when the
|
|
312
|
+
workflow uses that hook
|
|
313
|
+
- missing assets should be resolved or registered by the relevant workflow
|
|
314
|
+
|
|
315
|
+
### 9. Foreign Keys Belong To The Storage Contract
|
|
316
|
+
|
|
317
|
+
For new code, model foreign keys on the `PlatformTimeIndexMetaData` storage
|
|
318
|
+
class or route the storage-contract work to the MetaTable skill.
|
|
319
|
+
|
|
320
|
+
Do not add DataNode configuration fields just to mutate storage metadata.
|
|
321
|
+
|
|
322
|
+
### 10. Metadata Belongs To Storage
|
|
323
|
+
|
|
324
|
+
Production-quality table identifiers, descriptions, labels, column docs, and
|
|
325
|
+
foreign-key metadata belong to the storage class/MetaTable registration path.
|
|
326
|
+
|
|
327
|
+
Do not use `DataNodeMetaData` or `RecordDefinition` as the canonical schema
|
|
328
|
+
surface for new DataNode work.
|
|
329
|
+
|
|
330
|
+
## Review Rules
|
|
331
|
+
|
|
332
|
+
When reviewing an existing DataNode, look for:
|
|
333
|
+
|
|
334
|
+
- output storage contract hidden in `DataNodeConfiguration`
|
|
335
|
+
- dependency storage table passed as an ad hoc constructor argument
|
|
336
|
+
- old `RecordDefinition` or `DataNodeMetaData` schema patterns
|
|
337
|
+
- `update_only`, `runtime_only`, or `ignore_from_storage_hash`
|
|
338
|
+
- `test_node=True`
|
|
339
|
+
- missing explicit `storage_table`
|
|
340
|
+
- accidental storage registration inside the DataNode
|
|
341
|
+
- wrong meaning/scope/hash-excluded split
|
|
342
|
+
- misuse of `hash_namespace`
|
|
343
|
+
- non-incremental `update()` behavior
|
|
344
|
+
- hidden dependency creation inside `update()`
|
|
345
|
+
- invalid asset-indexed output shape
|
|
346
|
+
- `time_index` dtype that is not exactly `datetime64[ns, UTC]`
|
|
347
|
+
- DataFrame columns that do not match the `PlatformTimeIndexMetaData` class
|
|
348
|
+
|
|
349
|
+
## Validation Checklist
|
|
350
|
+
|
|
351
|
+
Do not claim success until you have checked:
|
|
352
|
+
|
|
353
|
+
- the relevant docs were read first
|
|
354
|
+
- storage is a registered or bound `PlatformTimeIndexMetaData` class
|
|
355
|
+
- the DataNode constructor requires `storage_table`
|
|
356
|
+
- dependency storage-table references live in config and are registered or bound
|
|
357
|
+
- config fields are updater-scoped by default
|
|
358
|
+
- no removed hash metadata markers remain
|
|
359
|
+
- no `test_node` usage remains
|
|
360
|
+
- `dependencies()` is deterministic
|
|
361
|
+
- `update()` is incremental
|
|
362
|
+
- the DataFrame shape matches the storage class
|
|
363
|
+
- non-empty outputs have first index level `time_index` with dtype `datetime64[ns, UTC]`
|
|
364
|
+
- the first validation run uses explicit `hash_namespace(...)` when it touches a shared backend
|
|
365
|
+
|
|
366
|
+
For asset-scoped updates, also check:
|
|
367
|
+
|
|
368
|
+
- `get_asset_list()` is correct when used
|
|
369
|
+
- no duplicate `(time_index, unique_identifier)` rows are emitted
|
|
370
|
+
- assets exist or are registered idempotently when needed
|
|
371
|
+
|
|
372
|
+
## This Skill Must Stop And Escalate When
|
|
373
|
+
|
|
374
|
+
- the change may break an existing published table contract and the versioning decision is unclear
|
|
375
|
+
- the intended storage class or MetaTable registration path is unclear
|
|
376
|
+
- the node needs asset identities but the asset-resolution strategy is unclear
|
|
377
|
+
- the task is actually an API, MetaTable, orchestration, or sharing problem
|
|
378
|
+
- docs, skill instructions, and code disagree on hashing or runtime behavior
|
|
379
|
+
|
|
380
|
+
Do not guess through contract changes.
|