mainsequence 4.0.16__tar.gz → 4.1.1__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 (134) hide show
  1. {mainsequence-4.0.16 → mainsequence-4.1.1}/PKG-INFO +9 -10
  2. {mainsequence-4.0.16 → mainsequence-4.1.1}/README.md +8 -8
  3. mainsequence-4.1.1/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +365 -0
  4. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/api.py +408 -96
  5. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/cli.py +489 -27
  6. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/__init__.py +4 -1
  7. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/base.py +1 -2
  8. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/data_sources_interfaces/duckdb.py +11 -9
  9. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/data_sources_interfaces/sqlite.py +15 -7
  10. mainsequence-4.1.1/mainsequence/client/models_foundry.py +1064 -0
  11. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/models_helpers.py +2 -3
  12. mainsequence-4.0.16/mainsequence/client/models_tdag.py → mainsequence-4.1.1/mainsequence/client/models_metatables.py +3679 -4185
  13. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/utils.py +39 -30
  14. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence}/meta_tables/__init__.py +20 -1
  15. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/config.py +18 -27
  16. mainsequence-4.1.1/mainsequence/meta_tables/configuration_models.py +5 -0
  17. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/data_nodes/__init__.py +1 -2
  18. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/data_nodes/build_operations.py +66 -333
  19. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/data_nodes/data_nodes.py +194 -504
  20. mainsequence-4.1.1/mainsequence/meta_tables/data_nodes/models.py +106 -0
  21. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/data_nodes/namespacing.py +10 -7
  22. mainsequence-4.0.16/mainsequence/tdag/base_persist_managers.py → mainsequence-4.1.1/mainsequence/meta_tables/data_nodes/persist_managers.py +244 -230
  23. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/data_nodes/run_operations.py +105 -52
  24. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence}/meta_tables/hashing.py +5 -7
  25. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/pydantic_metadata.py +20 -31
  26. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence}/meta_tables/sqlalchemy_contracts.py +779 -16
  27. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence.egg-info/PKG-INFO +9 -10
  28. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence.egg-info/SOURCES.txt +19 -24
  29. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence.egg-info/requires.txt +0 -1
  30. {mainsequence-4.0.16 → mainsequence-4.1.1}/pyproject.toml +1 -2
  31. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_build_operations_hashing.py +31 -133
  32. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_cli.py +277 -76
  33. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_data_access_mixin_dimension_audit.py +37 -20
  34. mainsequence-4.1.1/tests/test_data_node_storage_dimension_queries.py +316 -0
  35. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_data_node_update_flow.py +95 -46
  36. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_dependency_extras.py +5 -2
  37. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_duckdb_interface_dimensions.py +10 -12
  38. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_filter_normalization.py +60 -45
  39. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_meta_tables_client_models.py +1 -1
  40. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_meta_tables_sqlalchemy_contracts.py +379 -8
  41. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_pod_project_resolution.py +114 -96
  42. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_project_batch_jobs_from_file.py +2 -3
  43. mainsequence-4.1.1/tests/test_run_configuration.py +796 -0
  44. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_secret_client_model.py +1 -1
  45. mainsequence-4.1.1/tests/test_source_table_configuration.py +233 -0
  46. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_sqlite_interface_dimensions.py +7 -7
  47. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_update_runner_uid_runtime.py +6 -4
  48. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_update_statistics.py +2 -2
  49. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_update_uid_guards.py +4 -4
  50. mainsequence-4.0.16/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -334
  51. mainsequence-4.0.16/mainsequence/client/models_metatables.py +0 -582
  52. mainsequence-4.0.16/mainsequence/tdag/__init__.py +0 -37
  53. mainsequence-4.0.16/mainsequence/tdag/configuration_models.py +0 -23
  54. mainsequence-4.0.16/mainsequence/tdag/data_nodes/filters.py +0 -85
  55. mainsequence-4.0.16/mainsequence/tdag/data_nodes/models.py +0 -349
  56. mainsequence-4.0.16/mainsequence/tdag/data_nodes/persist_managers.py +0 -131
  57. mainsequence-4.0.16/mainsequence/tdag/filters.py +0 -201
  58. mainsequence-4.0.16/tests/test_data_node_search_join_filters.py +0 -209
  59. mainsequence-4.0.16/tests/test_data_node_storage_dimension_queries.py +0 -508
  60. mainsequence-4.0.16/tests/test_run_configuration.py +0 -413
  61. mainsequence-4.0.16/tests/test_source_table_configuration.py +0 -400
  62. {mainsequence-4.0.16 → mainsequence-4.1.1}/LICENSE +0 -0
  63. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/AGENTS.md +0 -0
  64. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
  65. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
  66. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
  67. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
  68. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
  69. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
  70. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
  71. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
  72. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
  73. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
  74. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
  75. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +0 -0
  76. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
  77. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
  78. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
  79. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
  80. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
  81. {mainsequence-4.0.16 → mainsequence-4.1.1}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
  82. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/__init__.py +0 -0
  83. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/__main__.py +0 -0
  84. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/bootstrap.py +0 -0
  85. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/__init__.py +0 -0
  86. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/browser_auth.py +0 -0
  87. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/config.py +0 -0
  88. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/docker_utils.py +0 -0
  89. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/doctor.py +0 -0
  90. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/local_ops.py +0 -0
  91. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/model_filters.py +0 -0
  92. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/project_status.py +0 -0
  93. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/pydantic_cli.py +0 -0
  94. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/sdk_utils.py +0 -0
  95. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/ssh_utils.py +0 -0
  96. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/cli/ui.py +0 -0
  97. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/agent_runtime_models.py +0 -0
  98. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/client.py +0 -0
  99. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/command_center/__init__.py +0 -0
  100. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/command_center/app_component.py +0 -0
  101. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/command_center/connections.py +0 -0
  102. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/command_center/data_models.py +0 -0
  103. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/command_center/workspace.py +0 -0
  104. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
  105. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
  106. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/dtype_codec.py +0 -0
  107. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/exceptions.py +0 -0
  108. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/fastapi/__init__.py +0 -0
  109. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/fastapi/auth.py +0 -0
  110. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/client/models_user.py +0 -0
  111. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/compute_validation.py +0 -0
  112. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/defaults.py +0 -0
  113. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/instrumentation/__init__.py +0 -0
  114. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/instrumentation/utils.py +0 -0
  115. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/logconf.py +0 -0
  116. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/__main__.py +0 -0
  117. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence}/meta_tables/compiled_sql.py +0 -0
  118. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/data_nodes/utils.py +0 -0
  119. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/future_registry.py +0 -0
  120. {mainsequence-4.0.16/mainsequence/tdag → mainsequence-4.1.1/mainsequence/meta_tables}/utils.py +0 -0
  121. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence/runtime_flags.py +0 -0
  122. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence.egg-info/dependency_links.txt +0 -0
  123. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence.egg-info/entry_points.txt +0 -0
  124. {mainsequence-4.0.16 → mainsequence-4.1.1}/mainsequence.egg-info/top_level.txt +0 -0
  125. {mainsequence-4.0.16 → mainsequence-4.1.1}/setup.cfg +0 -0
  126. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_auth_precedence.py +0 -0
  127. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_cli_browser_auth.py +0 -0
  128. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_client.py +0 -0
  129. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_command_center_app_component_models.py +0 -0
  130. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_command_center_data_models.py +0 -0
  131. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_command_center_models.py +0 -0
  132. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_logconf.py +0 -0
  133. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_models_user_request_bound_auth.py +0 -0
  134. {mainsequence-4.0.16 → mainsequence-4.1.1}/tests/test_workspace_snapshot.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence
3
- Version: 4.0.16
3
+ Version: 4.1.1
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 a normalized structure through `DataNode`s
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.tdag`: data orchestration, `DataNode`s, update workflows, and persistence
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
- - [Create Your First API](docs/tutorial/create_your_first_api.md)
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. create your first `DataNode`
193
- 2. model app-facing relational data with backend-managed `MetaTable`s when needed
194
- 3. add an API or another application surface
195
- 4. understand sharing and RBAC
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 a normalized structure through `DataNode`s
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.tdag`: data orchestration, `DataNode`s, update workflows, and persistence
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
- - [Create Your First API](docs/tutorial/create_your_first_api.md)
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. create your first `DataNode`
113
- 2. model app-facing relational data with backend-managed `MetaTable`s when needed
114
- 3. add an API or another application surface
115
- 4. understand sharing and RBAC
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,365 @@
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
+ Do not accept `test_node`. It has been removed. Use explicit
165
+ `hash_namespace(...)` or `hash_namespace="..."`.
166
+
167
+ Pattern:
168
+
169
+ ```python
170
+ from mainsequence.meta_tables import DataNode, DataNodeConfiguration
171
+ from mainsequence.meta_tables import PlatformTimeIndexMetaData
172
+
173
+
174
+ class PricesConfig(DataNodeConfiguration):
175
+ shard_id: str
176
+
177
+
178
+ class PricesUpdate(DataNode):
179
+ def __init__(
180
+ self,
181
+ config: PricesConfig,
182
+ storage_table: type[PlatformTimeIndexMetaData],
183
+ *,
184
+ hash_namespace: str | None = None,
185
+ ):
186
+ self.config = config
187
+ super().__init__(
188
+ config=config,
189
+ storage_table=storage_table,
190
+ hash_namespace=hash_namespace,
191
+ )
192
+
193
+ def dependencies(self):
194
+ return {}
195
+
196
+ def update(self):
197
+ ...
198
+ ```
199
+
200
+ ### 3. Configuration Is Update-Scoped By Default
201
+
202
+ Every `DataNodeConfiguration` field participates in `update_hash` by default.
203
+
204
+ Do not use:
205
+
206
+ - `json_schema_extra={"update_only": True}`
207
+ - `json_schema_extra={"runtime_only": True}`
208
+ - `json_schema_extra={"ignore_from_storage_hash": True}`
209
+ - `_ARGS_IGNORE_IN_STORAGE_HASH`
210
+
211
+ Those are removed. The only supported opt-out is:
212
+
213
+ ```python
214
+ Field(..., json_schema_extra={"hash_excluded": True})
215
+ ```
216
+
217
+ Use `hash_excluded` only for descriptive metadata that must not affect update
218
+ identity. If a field changes output values, dependencies, source choice, or
219
+ updater scope, it must remain a normal config field.
220
+
221
+ ### 4. `hash_namespace` Is Isolation Only
222
+
223
+ Use explicit `hash_namespace(...)` for:
224
+
225
+ - namespaced tests
226
+ - isolated experimentation
227
+ - shared-backend safety
228
+
229
+ Do not use namespace to encode business meaning.
230
+
231
+ Do not use `test_node=True`; it is not supported.
232
+
233
+ ### 5. `update()` Should Be Incremental By Default
234
+
235
+ Use `UpdateStatistics`.
236
+
237
+ Do not fetch or return full history every run unless there is a documented
238
+ reason.
239
+
240
+ ### 6. `time_index` Must Be Nanosecond UTC
241
+
242
+ Every non-empty DataFrame returned by `update()` must have its first index
243
+ level named `time_index` with dtype exactly `datetime64[ns, UTC]`.
244
+
245
+ Do not rely on `pd.Timestamp.now("UTC").normalize()` or
246
+ `pd.Timestamp.now("UTC").floor(...)` alone. Some pandas versions preserve
247
+ microsecond resolution and produce `datetime64[us, UTC]`, which the DataNode
248
+ runtime rejects.
249
+
250
+ For a single-index DataFrame, construct the index with an explicit dtype:
251
+
252
+ ```python
253
+ time_index = pd.Timestamp.now("UTC").normalize()
254
+ return pd.DataFrame(
255
+ {"close": [100.0]},
256
+ index=pd.DatetimeIndex(
257
+ [time_index],
258
+ name="time_index",
259
+ dtype="datetime64[ns, UTC]",
260
+ ),
261
+ )
262
+ ```
263
+
264
+ For a MultiIndex DataFrame, construct the time level separately:
265
+
266
+ ```python
267
+ time_index = pd.DatetimeIndex(
268
+ [row[0] for row in rows],
269
+ dtype="datetime64[ns, UTC]",
270
+ )
271
+ index = pd.MultiIndex.from_arrays(
272
+ [
273
+ time_index,
274
+ [row[1] for row in rows],
275
+ ],
276
+ names=["time_index", "unique_identifier"],
277
+ )
278
+ ```
279
+
280
+ The validator error to prevent is:
281
+
282
+ ```text
283
+ Time index must be datetime64[ns, UTC]
284
+ ```
285
+
286
+ ### 7. Dependencies Must Be Deterministic
287
+
288
+ Dependencies belong in constructor setup and `dependencies()`.
289
+
290
+ Do not construct dependency graphs dynamically inside `update()`.
291
+
292
+ ### 8. Asset-Scoped Updates Must Be Explicit
293
+
294
+ If the node emits `(time_index, unique_identifier)`:
295
+
296
+ - `unique_identifier` should represent an Asset identity
297
+ - asset scope should live in update configuration when it affects the updater
298
+ - `get_asset_list()` must reflect the effective updater asset scope when the
299
+ workflow uses that hook
300
+ - missing assets should be resolved or registered by the relevant workflow
301
+
302
+ ### 9. Foreign Keys Belong To The Storage Contract
303
+
304
+ For new code, model foreign keys on the `PlatformTimeIndexMetaData` storage
305
+ class or route the storage-contract work to the MetaTable skill.
306
+
307
+ Do not add DataNode configuration fields just to mutate storage metadata.
308
+
309
+ ### 10. Metadata Belongs To Storage
310
+
311
+ Production-quality table identifiers, descriptions, labels, column docs, and
312
+ foreign-key metadata belong to the storage class/MetaTable registration path.
313
+
314
+ Do not use `DataNodeMetaData` or `RecordDefinition` as the canonical schema
315
+ surface for new DataNode work.
316
+
317
+ ## Review Rules
318
+
319
+ When reviewing an existing DataNode, look for:
320
+
321
+ - storage contract hidden in `DataNodeConfiguration`
322
+ - old `RecordDefinition` or `DataNodeMetaData` schema patterns
323
+ - `update_only`, `runtime_only`, or `ignore_from_storage_hash`
324
+ - `test_node=True`
325
+ - missing explicit `storage_table`
326
+ - accidental storage registration inside the DataNode
327
+ - wrong meaning/scope/hash-excluded split
328
+ - misuse of `hash_namespace`
329
+ - non-incremental `update()` behavior
330
+ - hidden dependency creation inside `update()`
331
+ - invalid asset-indexed output shape
332
+ - `time_index` dtype that is not exactly `datetime64[ns, UTC]`
333
+ - DataFrame columns that do not match the `PlatformTimeIndexMetaData` class
334
+
335
+ ## Validation Checklist
336
+
337
+ Do not claim success until you have checked:
338
+
339
+ - the relevant docs were read first
340
+ - storage is a registered or bound `PlatformTimeIndexMetaData` class
341
+ - the DataNode constructor requires `storage_table`
342
+ - config fields are updater-scoped by default
343
+ - no removed hash metadata markers remain
344
+ - no `test_node` usage remains
345
+ - `dependencies()` is deterministic
346
+ - `update()` is incremental
347
+ - the DataFrame shape matches the storage class
348
+ - non-empty outputs have first index level `time_index` with dtype `datetime64[ns, UTC]`
349
+ - the first validation run uses explicit `hash_namespace(...)` when it touches a shared backend
350
+
351
+ For asset-scoped updates, also check:
352
+
353
+ - `get_asset_list()` is correct when used
354
+ - no duplicate `(time_index, unique_identifier)` rows are emitted
355
+ - assets exist or are registered idempotently when needed
356
+
357
+ ## This Skill Must Stop And Escalate When
358
+
359
+ - the change may break an existing published table contract and the versioning decision is unclear
360
+ - the intended storage class or MetaTable registration path is unclear
361
+ - the node needs asset identities but the asset-resolution strategy is unclear
362
+ - the task is actually an API, MetaTable, orchestration, or sharing problem
363
+ - docs, skill instructions, and code disagree on hashing or runtime behavior
364
+
365
+ Do not guess through contract changes.