mainsequence 4.0.3__tar.gz → 4.0.6__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.3 → mainsequence-4.0.6}/PKG-INFO +1 -1
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +136 -11
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +68 -11
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/data_sources_interfaces/__init__.py +7 -1
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/data_sources_interfaces/duckdb.py +293 -263
- mainsequence-4.0.6/mainsequence/client/data_sources_interfaces/sqlite.py +486 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/models_metatables.py +93 -25
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/models_tdag.py +397 -98
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/__init__.py +1 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/base_persist_managers.py +28 -5
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/data_nodes/__init__.py +1 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/data_nodes/build_operations.py +21 -3
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/data_nodes/data_nodes.py +35 -4
- mainsequence-4.0.6/mainsequence/tdag/data_nodes/models.py +342 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/data_nodes/run_operations.py +6 -3
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/meta_tables/__init__.py +9 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/meta_tables/hashing.py +54 -0
- mainsequence-4.0.6/mainsequence/tdag/meta_tables/sqlalchemy_contracts.py +1075 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/pydantic_metadata.py +9 -3
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence.egg-info/PKG-INFO +1 -1
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence.egg-info/SOURCES.txt +3 -1
- {mainsequence-4.0.3 → mainsequence-4.0.6}/pyproject.toml +1 -1
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_build_operations_hashing.py +95 -9
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_data_node_storage_dimension_queries.py +153 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_data_node_update_flow.py +34 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_dependency_extras.py +9 -0
- mainsequence-4.0.6/tests/test_duckdb_interface_dimensions.py +285 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_meta_tables_client_models.py +0 -4
- mainsequence-4.0.6/tests/test_meta_tables_sqlalchemy_contracts.py +598 -0
- mainsequence-4.0.6/tests/test_pod_project_resolution.py +431 -0
- mainsequence-4.0.6/tests/test_sqlite_interface_dimensions.py +294 -0
- mainsequence-4.0.3/mainsequence/client/data_sources_interfaces/timescale.py +0 -524
- mainsequence-4.0.3/mainsequence/tdag/data_nodes/models.py +0 -112
- mainsequence-4.0.3/mainsequence/tdag/meta_tables/sqlalchemy_contracts.py +0 -476
- mainsequence-4.0.3/tests/test_meta_tables_sqlalchemy_contracts.py +0 -209
- mainsequence-4.0.3/tests/test_pod_project_resolution.py +0 -98
- {mainsequence-4.0.3 → mainsequence-4.0.6}/LICENSE +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/README.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/maintenance/local_journal/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/__init__.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/__main__.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/bootstrap.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/api.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/cli.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/config.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/__init__.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/base.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/client.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/utils.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/compute_validation.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/defaults.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/logconf.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/__main__.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/config.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/configuration_models.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/data_nodes/filters.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/data_nodes/namespacing.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/data_nodes/persist_managers.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/data_nodes/utils.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/filters.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/future_registry.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/meta_tables/compiled_sql.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/tdag/utils.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/setup.cfg +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_auth_precedence.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_cli.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_client.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_data_access_mixin_dimension_audit.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_data_node_search_join_filters.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_filter_normalization.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_logconf.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_run_configuration.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_update_statistics.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_update_uid_guards.py +0 -0
- {mainsequence-4.0.3 → mainsequence-4.0.6}/tests/test_workspace_snapshot.py +0 -0
{mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md
RENAMED
|
@@ -17,12 +17,13 @@ This skill is for producer-side table engineering.
|
|
|
17
17
|
- modify an existing `DataNode`
|
|
18
18
|
- review whether a DataNode change is breaking or non-breaking
|
|
19
19
|
- define or refactor `DataNodeConfiguration`
|
|
20
|
-
- classify config fields into dataset meaning, updater scope, and
|
|
20
|
+
- classify config fields into dataset meaning, updater scope, and hash-excluded metadata
|
|
21
21
|
- implement or review:
|
|
22
22
|
- `dependencies()`
|
|
23
23
|
- `update()`
|
|
24
24
|
- `get_asset_list()`
|
|
25
|
-
-
|
|
25
|
+
- `RecordDefinition` declarations and metadata
|
|
26
|
+
- DataNode source-table foreign key declarations to MetaTables
|
|
26
27
|
- design single-index or `(time_index, unique_identifier)` MultiIndex outputs
|
|
27
28
|
- define namespace-first validation strategy
|
|
28
29
|
- write or review DataNode smoke tests
|
|
@@ -71,7 +72,8 @@ Before changing code, collect or infer:
|
|
|
71
72
|
- dataset meaning
|
|
72
73
|
- intended published identifier
|
|
73
74
|
- expected index shape
|
|
74
|
-
- expected columns and dtypes
|
|
75
|
+
- expected columns and dtypes, declared as `RecordDefinition`
|
|
76
|
+
- whether declared columns should reference registered MetaTables through foreign keys
|
|
75
77
|
- upstream dependencies
|
|
76
78
|
- whether the node is asset-indexed
|
|
77
79
|
- first-run or backfill bounds
|
|
@@ -106,7 +108,8 @@ Do not change them casually.
|
|
|
106
108
|
|
|
107
109
|
- dataset meaning belongs in table identity
|
|
108
110
|
- updater scope belongs in updater identity
|
|
109
|
-
-
|
|
111
|
+
- descriptive metadata belongs in `hash_excluded` fields
|
|
112
|
+
- runtime knobs belong outside hashed identity
|
|
110
113
|
|
|
111
114
|
Do not mix these.
|
|
112
115
|
|
|
@@ -140,12 +143,127 @@ If the node emits `(time_index, unique_identifier)`:
|
|
|
140
143
|
- `get_asset_list()` must reflect the effective updater asset scope
|
|
141
144
|
- missing assets should be resolved or registered when required by the workflow
|
|
142
145
|
|
|
143
|
-
### 7.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
### 7. `RecordDefinition` is the canonical schema surface
|
|
147
|
+
|
|
148
|
+
Every new or materially edited `DataNodeConfiguration` must declare output
|
|
149
|
+
records with `RecordDefinition` unless there is a documented compatibility
|
|
150
|
+
reason not to. Treat `records` as the canonical table schema declaration, not
|
|
151
|
+
as optional UI metadata.
|
|
152
|
+
|
|
153
|
+
The canonical pattern is:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from pydantic import Field
|
|
157
|
+
|
|
158
|
+
from mainsequence.tdag import DataNodeConfiguration, RecordDefinition
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class PricesConfig(DataNodeConfiguration):
|
|
162
|
+
records: list[RecordDefinition] = Field(
|
|
163
|
+
default_factory=lambda: [
|
|
164
|
+
RecordDefinition(
|
|
165
|
+
column_name="price",
|
|
166
|
+
dtype="float64",
|
|
167
|
+
label="Price",
|
|
168
|
+
description="Observed price.",
|
|
169
|
+
)
|
|
170
|
+
]
|
|
171
|
+
)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Rules:
|
|
175
|
+
|
|
176
|
+
- `column_name` and `dtype` are structural and define the persisted record contract.
|
|
177
|
+
- `label` and `description` are descriptive discovery metadata and must not be treated as runtime controls.
|
|
178
|
+
- The DataFrame returned by `update()` must match declared `records`.
|
|
179
|
+
- Do not invent another schema object or parallel record declaration.
|
|
180
|
+
- Prefer `DataNodeConfiguration.records` over overriding `get_column_metadata()` for normal nodes.
|
|
181
|
+
|
|
182
|
+
### 8. Use `SourceTableForeignKey` when a DataNode references a MetaTable
|
|
183
|
+
|
|
184
|
+
When a DataNode source table has a column that should reference a registered
|
|
185
|
+
MetaTable, declare that relationship in `DataNodeConfiguration.foreign_keys`.
|
|
186
|
+
Do this only for DataNode source-table to MetaTable relationships. Do not
|
|
187
|
+
invent DataNode-to-DataNode or MetaTable-to-DataNode foreign keys.
|
|
188
|
+
|
|
189
|
+
The canonical pattern is:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from pydantic import Field
|
|
193
|
+
|
|
194
|
+
from mainsequence.tdag import (
|
|
195
|
+
DataNodeConfiguration,
|
|
196
|
+
RecordDefinition,
|
|
197
|
+
SourceTableForeignKey,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
ASSET_UID = RecordDefinition(
|
|
202
|
+
column_name="asset_uid",
|
|
203
|
+
dtype="uuid",
|
|
204
|
+
label="Asset",
|
|
205
|
+
description="Asset UID.",
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class PricesConfig(DataNodeConfiguration):
|
|
210
|
+
records: list[RecordDefinition] = Field(
|
|
211
|
+
default_factory=lambda: [
|
|
212
|
+
RecordDefinition(
|
|
213
|
+
column_name="time_index",
|
|
214
|
+
dtype="datetime64[ns, UTC]",
|
|
215
|
+
label="Time",
|
|
216
|
+
description="UTC observation timestamp.",
|
|
217
|
+
),
|
|
218
|
+
ASSET_UID,
|
|
219
|
+
RecordDefinition(
|
|
220
|
+
column_name="price",
|
|
221
|
+
dtype="float64",
|
|
222
|
+
label="Price",
|
|
223
|
+
description="Observed price.",
|
|
224
|
+
),
|
|
225
|
+
]
|
|
226
|
+
)
|
|
227
|
+
foreign_keys: list[SourceTableForeignKey] = Field(
|
|
228
|
+
default_factory=lambda: [
|
|
229
|
+
SourceTableForeignKey(
|
|
230
|
+
target=Asset,
|
|
231
|
+
source_columns=[ASSET_UID],
|
|
232
|
+
target_columns=[Asset.uid],
|
|
233
|
+
on_delete="restrict",
|
|
234
|
+
)
|
|
235
|
+
]
|
|
236
|
+
)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Rules:
|
|
240
|
+
|
|
241
|
+
- `SourceTableForeignKey` is the authoring model; do not hand-author
|
|
242
|
+
`SourceTableForeignKeyContract` in DataNode configs.
|
|
243
|
+
- `source_columns` should reference the same `RecordDefinition` objects listed
|
|
244
|
+
in `records`.
|
|
245
|
+
- `target_columns` should use MetaTable/SQLAlchemy column references such as
|
|
246
|
+
`Asset.uid`, not backend UID strings.
|
|
247
|
+
- Do not ask users to provide FK names.
|
|
248
|
+
- Do not ask users to provide `target_meta_table_uid`; the SDK resolves the
|
|
249
|
+
target MetaTable public `uid`.
|
|
250
|
+
- FK hash material is source column names, target MetaTable public `uid`,
|
|
251
|
+
target column names, and `on_delete`.
|
|
252
|
+
- FK hash material must not include generated names, backend database primary
|
|
253
|
+
keys, source-table FK row UIDs, backend projection/enforcement fields, target
|
|
254
|
+
storage hashes, or Python object/class repr values.
|
|
255
|
+
- If FK target registration or MetaTable ownership is unclear, route to
|
|
256
|
+
`.agents/skills/mainsequence/data_publishing/meta_tables/SKILL.md`.
|
|
257
|
+
|
|
258
|
+
### 9. Metadata is still required for production-quality nodes
|
|
259
|
+
|
|
260
|
+
When the node is not a throwaway example, also provide table metadata through
|
|
261
|
+
`DataNodeConfiguration.node_metadata` when a stable published identifier or
|
|
262
|
+
description is needed.
|
|
263
|
+
|
|
264
|
+
Use `json_schema_extra={"hash_excluded": True}` for descriptive metadata that
|
|
265
|
+
must not rotate `update_hash` or `storage_hash`. Keep the older `runtime_only`
|
|
266
|
+
marker only for legacy compatibility.
|
|
149
267
|
|
|
150
268
|
## Review Rules
|
|
151
269
|
|
|
@@ -153,7 +271,10 @@ When reviewing an existing DataNode, look for:
|
|
|
153
271
|
|
|
154
272
|
- identifier collisions
|
|
155
273
|
- accidental schema breaks
|
|
156
|
-
- wrong meaning/scope/
|
|
274
|
+
- wrong meaning/scope/hash-excluded split
|
|
275
|
+
- missing `RecordDefinition` declarations
|
|
276
|
+
- missing or incorrectly authored `SourceTableForeignKey` declarations when a
|
|
277
|
+
DataNode column references a MetaTable
|
|
157
278
|
- misuse of `hash_namespace`
|
|
158
279
|
- non-incremental `update()` behavior
|
|
159
280
|
- hidden dependency creation inside `update()`
|
|
@@ -167,6 +288,10 @@ Do not claim success until you have checked:
|
|
|
167
288
|
- the relevant docs were read first
|
|
168
289
|
- the identifier choice is intentional
|
|
169
290
|
- config fields are classified correctly
|
|
291
|
+
- `DataNodeConfiguration.records` is present for new or materially edited nodes
|
|
292
|
+
- declared `RecordDefinition` names and dtypes match the DataFrame returned by `update()`
|
|
293
|
+
- any DataNode-to-MetaTable relationships use `SourceTableForeignKey` with
|
|
294
|
+
source record references and target column references
|
|
170
295
|
- `dependencies()` is deterministic
|
|
171
296
|
- `update()` is incremental
|
|
172
297
|
- the DataFrame shape is valid
|
{mainsequence-4.0.3 → mainsequence-4.0.6}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md
RENAMED
|
@@ -15,7 +15,8 @@ This skill is for schema-driven application tables registered through TS Manager
|
|
|
15
15
|
|
|
16
16
|
- define SQLAlchemy/Core or ORM table models for `MetaTable` registration
|
|
17
17
|
- choose `platform_managed` or `external_registered` management mode
|
|
18
|
-
-
|
|
18
|
+
- register platform-managed tables through the model class API
|
|
19
|
+
- build registration requests from resolved SQLAlchemy metadata when inspection is useful
|
|
19
20
|
- define indexes and foreign keys in the table contract
|
|
20
21
|
- design governed compiled SQL read and write operations
|
|
21
22
|
- review table contracts for physical-name, namespace, and identifier issues
|
|
@@ -67,7 +68,7 @@ Before changing code, collect or infer:
|
|
|
67
68
|
- expected read patterns
|
|
68
69
|
- expected mutation patterns
|
|
69
70
|
- whether TS Manager should create the physical table
|
|
70
|
-
- the target `DynamicTableDataSource` UID
|
|
71
|
+
- for `external_registered`, the target `DynamicTableDataSource` UID
|
|
71
72
|
|
|
72
73
|
If ownership of the physical table lifecycle is unclear, stop before choosing a management mode.
|
|
73
74
|
|
|
@@ -92,15 +93,67 @@ Do not hand-build contract fragments when the SQLAlchemy helper can derive them.
|
|
|
92
93
|
|
|
93
94
|
### 2. Use storage-hash physical names for backend-managed tables
|
|
94
95
|
|
|
95
|
-
For `platform_managed`,
|
|
96
|
+
For `platform_managed`, inherit from `PlatformManagedMetaTable`.
|
|
96
97
|
|
|
97
|
-
The
|
|
98
|
+
The mixin derives the SQLAlchemy physical table name from storage-relevant configuration and table shape. Do not hand-write `__tablename__` for normal backend-managed tables.
|
|
99
|
+
|
|
100
|
+
Schema must come from SQLAlchemy table metadata, usually `__table_args__ = {"schema": "public"}` or the tuple form ending in `{"schema": ...}`. Do not add a separate MetaTable-specific schema attribute.
|
|
101
|
+
|
|
102
|
+
Register through the class API:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
account_meta_table = Account.register(
|
|
106
|
+
description="Example account table.",
|
|
107
|
+
labels=["sdk-example"],
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
For platform-managed registration, the data source is resolved from the active Main Sequence project/session, the same way DataNode does. Do not require or thread a `data_source_uid` through normal platform-managed example code.
|
|
112
|
+
|
|
113
|
+
Only call `build_registration_request()` when the task explicitly needs to inspect or validate the payload before registration.
|
|
114
|
+
|
|
115
|
+
For SDK examples, use a plain namespace constant:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
NAMESPACE = "sdk-examples"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Do not add an environment variable for namespace in examples.
|
|
122
|
+
|
|
123
|
+
Do not add generic labels such as `"meta-table"` or `"platform-managed"` to examples. Keep labels specific to the example or domain.
|
|
124
|
+
|
|
125
|
+
Do not add a `MAINSEQUENCE_META_TABLE_REGISTER` toggle in registration examples. Registration examples should register directly.
|
|
98
126
|
|
|
99
127
|
### 3. Register parent tables before child tables
|
|
100
128
|
|
|
101
129
|
Foreign-key contracts reference the target `MetaTable` UID.
|
|
102
130
|
|
|
103
|
-
|
|
131
|
+
For `PlatformManagedMetaTable`, register parent tables first and then register child tables normally. The SDK inspects SQLAlchemy foreign-key constraints and resolves each target `MetaTable` by looking up the already registered table in the same data source, schema, and physical table name.
|
|
132
|
+
|
|
133
|
+
Example registration order:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
account_meta_table = Account.register(...)
|
|
137
|
+
asset_meta_table = Asset.register(...)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The child registration will fail if the parent table has not already been registered, because there is no target `MetaTable.uid` for the backend FK contract.
|
|
141
|
+
|
|
142
|
+
Do not pass `target_meta_tables` or `target_meta_table_uid_by_fullname` in the normal platform-managed path. Use explicit FK target mappings only for edge cases where automatic lookup is ambiguous or impossible.
|
|
143
|
+
|
|
144
|
+
For `external_registered`, there is no platform-managed parent lookup through the model class. Register the parent first, then build the child registration request with the parent UID mapped by target table fullname:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
account_meta_table = MetaTable.register(account_request)
|
|
148
|
+
asset_request = external_registered_registration_request_from_sqlalchemy_model(
|
|
149
|
+
Asset,
|
|
150
|
+
data_source_uid=data_source_uid,
|
|
151
|
+
target_meta_table_uid_by_fullname={
|
|
152
|
+
Account.__table__.fullname: account_meta_table.uid,
|
|
153
|
+
},
|
|
154
|
+
)
|
|
155
|
+
asset_meta_table = MetaTable.register(asset_request)
|
|
156
|
+
```
|
|
104
157
|
|
|
105
158
|
### 4. Governed operations declare scope
|
|
106
159
|
|
|
@@ -110,7 +163,7 @@ Do not execute unrestricted SQL outside the MetaTable operation contract.
|
|
|
110
163
|
|
|
111
164
|
### 5. Physical names come from registered resources
|
|
112
165
|
|
|
113
|
-
Only use physical
|
|
166
|
+
Only use physical table names returned by registered `MetaTable` objects when composing SQL strings.
|
|
114
167
|
|
|
115
168
|
Do not hardcode platform-managed physical names manually.
|
|
116
169
|
|
|
@@ -119,9 +172,12 @@ Do not hardcode platform-managed physical names manually.
|
|
|
119
172
|
When reviewing an existing MetaTable workflow, look for:
|
|
120
173
|
|
|
121
174
|
- missing namespace or identifier
|
|
122
|
-
- backend-managed models that do not
|
|
175
|
+
- backend-managed models that do not inherit `PlatformManagedMetaTable`
|
|
176
|
+
- backend-managed examples that use namespace environment variables instead of a plain `sdk-examples` namespace
|
|
177
|
+
- duplicate schema sources outside SQLAlchemy table metadata
|
|
123
178
|
- external tables registered with unstable physical names
|
|
124
|
-
-
|
|
179
|
+
- platform-managed child tables that are registered before parent tables
|
|
180
|
+
- external child registrations that do not map foreign-key targets to registered parent `MetaTable.uid` values
|
|
125
181
|
- compiled SQL operations without complete table scope
|
|
126
182
|
- raw SQL that hardcodes stale physical names
|
|
127
183
|
- a table that should really be modeled as a DataNode instead
|
|
@@ -132,7 +188,7 @@ Do not claim success until you have checked:
|
|
|
132
188
|
|
|
133
189
|
- the table contract matches the intended row contract
|
|
134
190
|
- indexes are intentional
|
|
135
|
-
- foreign keys
|
|
191
|
+
- foreign keys resolve to the correct dependency targets
|
|
136
192
|
- management mode is correct
|
|
137
193
|
- backend-managed physical names match the storage hash
|
|
138
194
|
- registration returns a `MetaTable.uid`
|
|
@@ -141,13 +197,14 @@ Do not claim success until you have checked:
|
|
|
141
197
|
For related tables, also check:
|
|
142
198
|
|
|
143
199
|
- aliases are readable
|
|
144
|
-
- parent
|
|
200
|
+
- platform-managed parent tables are registered before child tables
|
|
201
|
+
- external child registration requests map FK targets to the registered parent UIDs
|
|
145
202
|
- query results still match the expected response contract
|
|
146
203
|
|
|
147
204
|
## This Skill Must Stop And Escalate When
|
|
148
205
|
|
|
149
206
|
- physical table lifecycle ownership is unclear
|
|
150
|
-
- the target data source is unknown
|
|
207
|
+
- the target data source is unknown for an `external_registered` workflow
|
|
151
208
|
- the task really requires a time-series published table
|
|
152
209
|
- the workflow requires direct database credentials outside TS Manager governance
|
|
153
210
|
- the task is actually an API or orchestration problem
|
{mainsequence-4.0.3 → mainsequence-4.0.6}/mainsequence/client/data_sources_interfaces/__init__.py
RENAMED
|
@@ -16,4 +16,10 @@ def get_duckdb_interface_class():
|
|
|
16
16
|
return DuckDBInterface
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
def get_sqlite_interface_class():
|
|
20
|
+
from .sqlite import SQLiteInterface
|
|
21
|
+
|
|
22
|
+
return SQLiteInterface
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ["get_duckdb_interface_class", "get_sqlite_interface_class"]
|