mainsequence 4.3.19__tar.gz → 4.3.20__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.3.19/mainsequence.egg-info → mainsequence-4.3.20}/PKG-INFO +1 -1
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +82 -4
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +20 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/cli.py +60 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/models_foundry.py +10 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20/mainsequence.egg-info}/PKG-INFO +1 -1
- {mainsequence-4.3.19 → mainsequence-4.3.20}/pyproject.toml +1 -1
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_cli.py +53 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/LICENSE +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/README.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/__main__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/bootstrap.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/api.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/config.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/migrations.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/base.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/client.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/metatables/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/metatables/core.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/utils.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/defaults.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/logconf.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/data_nodes.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/models.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/persist_managers.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/alembic.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/env.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/provider.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/registry.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/scaffold.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/templates/__init__.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/templates/env.py.mako +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/migrations/templates/script.py.mako +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/schema_names.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence.egg-info/SOURCES.txt +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/setup.cfg +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_auth_precedence.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_build_operations_hashing.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_cli_migrations.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_client.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_data_access_mixin_dimension_audit.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_data_node_storage_dimension_queries.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_data_node_update_flow.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_dependency_extras.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_duckdb_interface_dimensions.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_filter_normalization.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_instrumentation.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_logconf.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_meta_table_migrations.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_meta_tables_client_models.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_meta_tables_sqlalchemy_contracts.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_run_configuration.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_schema_names.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_secret_client_model.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_sqlite_interface_dimensions.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_update_statistics.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_update_uid_guards.py +0 -0
- {mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_workspace_snapshot.py +0 -0
|
@@ -335,7 +335,80 @@ Use `UpdateStatistics`.
|
|
|
335
335
|
Do not fetch or return full history every run unless there is a documented
|
|
336
336
|
reason.
|
|
337
337
|
|
|
338
|
-
### 6.
|
|
338
|
+
### 6. DataNode Tail Deletes Must Use `delete_after_date(...)`
|
|
339
|
+
|
|
340
|
+
When a DataNode workflow needs to remove persisted rows from its
|
|
341
|
+
`PlatformTimeIndexMetaTable` storage table, use
|
|
342
|
+
`TimeIndexMetaTable.delete_after_date(...)`. This is the only normal DataNode
|
|
343
|
+
storage deletion path.
|
|
344
|
+
|
|
345
|
+
Do not use raw SQL, compiled SQL operations, direct database clients,
|
|
346
|
+
`run_query(...)`, backend-private endpoints, table truncation, or ad hoc
|
|
347
|
+
delete helpers to clean DataNode storage rows.
|
|
348
|
+
|
|
349
|
+
The SDK call targets:
|
|
350
|
+
|
|
351
|
+
```text
|
|
352
|
+
POST /orm/api/ts_manager/dynamic_table/<dynamic_table_uid>/delete_after_date/
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Use a global tail delete only when all streams in the table should be rolled
|
|
356
|
+
back from the same inclusive cutoff:
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
storage = MyStorageTable.get_time_index_meta_table()
|
|
360
|
+
storage.delete_after_date("2026-04-01T00:00:00Z")
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
For multidimensional storage, prefer an explicit scope. Use
|
|
364
|
+
`dimension_filters` when deleting all rows for one or more dimension values:
|
|
365
|
+
|
|
366
|
+
```python
|
|
367
|
+
storage.delete_after_date(
|
|
368
|
+
"2026-04-01T00:00:00Z",
|
|
369
|
+
dimension_filters={
|
|
370
|
+
"asset_identifier": ["example-asset-btc", "example-asset-eth"],
|
|
371
|
+
},
|
|
372
|
+
)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Use `index_coordinates` when deleting exact coordinate streams:
|
|
376
|
+
|
|
377
|
+
```python
|
|
378
|
+
storage.delete_after_date(
|
|
379
|
+
"2026-04-01T00:00:00Z",
|
|
380
|
+
index_coordinates=[
|
|
381
|
+
{
|
|
382
|
+
"account_uid": "account-a",
|
|
383
|
+
"asset_identifier": "example-asset-btc",
|
|
384
|
+
}
|
|
385
|
+
],
|
|
386
|
+
)
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Deleting all rows for scoped streams is allowed only with an explicit scope:
|
|
390
|
+
|
|
391
|
+
```python
|
|
392
|
+
storage.delete_after_date(
|
|
393
|
+
None,
|
|
394
|
+
dimension_filters={"asset_identifier": ["example-asset-btc"]},
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
storage.delete_after_date(
|
|
398
|
+
None,
|
|
399
|
+
index_coordinates=[
|
|
400
|
+
{
|
|
401
|
+
"account_uid": "account-a",
|
|
402
|
+
"asset_identifier": "example-asset-btc",
|
|
403
|
+
}
|
|
404
|
+
],
|
|
405
|
+
)
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Never send `after_date=None` without `dimension_filters` or
|
|
409
|
+
`index_coordinates`. That is an unbounded table delete and must be rejected.
|
|
410
|
+
|
|
411
|
+
### 7. `time_index` Must Be Nanosecond UTC
|
|
339
412
|
|
|
340
413
|
Every non-empty DataFrame returned by `update()` must have its first index
|
|
341
414
|
level named `time_index` with dtype exactly `datetime64[ns, UTC]`.
|
|
@@ -386,7 +459,7 @@ physical schema evolution. Keep the `PlatformTimeIndexMetaTable` catalog model a
|
|
|
386
459
|
the SDK storage contract, apply Alembic-rendered SQL through the migration
|
|
387
460
|
workflow, then register or refresh the MetaTable catalog binding separately.
|
|
388
461
|
|
|
389
|
-
###
|
|
462
|
+
### 8. Dependencies Must Be Deterministic
|
|
390
463
|
|
|
391
464
|
Dependencies belong in constructor setup and `dependencies()`.
|
|
392
465
|
|
|
@@ -395,7 +468,7 @@ changing it changes the dependency graph and update identity.
|
|
|
395
468
|
|
|
396
469
|
Do not construct dependency graphs dynamically inside `update()`.
|
|
397
470
|
|
|
398
|
-
###
|
|
471
|
+
### 9. Foreign Keys Belong To SQLAlchemy And Alembic
|
|
399
472
|
|
|
400
473
|
For new code, model foreign keys on the `PlatformTimeIndexMetaTable` storage
|
|
401
474
|
class, or route the storage work to the MetaTable skill. When a DataNode storage
|
|
@@ -416,7 +489,7 @@ binding after upgrade.
|
|
|
416
489
|
|
|
417
490
|
Do not add DataNode configuration fields just to mutate storage metadata.
|
|
418
491
|
|
|
419
|
-
###
|
|
492
|
+
### 10. Metadata Belongs To Storage
|
|
420
493
|
|
|
421
494
|
Production-quality table identifiers, descriptions, labels, column docs, and
|
|
422
495
|
foreign-key metadata belong to the storage class/MetaTable registration path.
|
|
@@ -444,6 +517,8 @@ When reviewing an existing DataNode, look for:
|
|
|
444
517
|
- misuse of `hash_namespace`
|
|
445
518
|
- non-incremental `update()` behavior
|
|
446
519
|
- hidden dependency creation inside `update()`
|
|
520
|
+
- DataNode storage cleanup that bypasses `TimeIndexMetaTable.delete_after_date(...)`
|
|
521
|
+
- `delete_after_date(None)` without explicit `dimension_filters` or `index_coordinates`
|
|
447
522
|
- invalid identity-indexed output shape
|
|
448
523
|
- `time_index` dtype that is not exactly `datetime64[ns, UTC]`
|
|
449
524
|
- DataFrame columns that do not match the `PlatformTimeIndexMetaTable` class
|
|
@@ -464,6 +539,9 @@ Do not claim success until you have checked:
|
|
|
464
539
|
- no `test_node` usage remains
|
|
465
540
|
- `dependencies()` is deterministic
|
|
466
541
|
- `update()` is incremental
|
|
542
|
+
- DataNode storage deletion, rollback, and repair paths use
|
|
543
|
+
`TimeIndexMetaTable.delete_after_date(...)`
|
|
544
|
+
- unbounded deletes with `after_date=None` and no dimension/coordinate scope are absent
|
|
467
545
|
- the DataFrame shape matches the storage class
|
|
468
546
|
- non-empty outputs have first index level `time_index` with dtype `datetime64[ns, UTC]`
|
|
469
547
|
- the first validation run uses explicit `hash_namespace(...)` when it touches a shared backend
|
|
@@ -387,6 +387,24 @@ Only use physical table names returned by registered `MetaTable` objects when co
|
|
|
387
387
|
|
|
388
388
|
Do not hardcode platform-managed physical names manually.
|
|
389
389
|
|
|
390
|
+
### 7. DataNode storage deletes use the DataNode tail-delete API
|
|
391
|
+
|
|
392
|
+
For `PlatformTimeIndexMetaTable` storage owned by DataNodes, do not design raw
|
|
393
|
+
SQL delete operations or compiled SQL delete operations for rollback, repair, or
|
|
394
|
+
stream cleanup. Route that work to the DataNode skill and use
|
|
395
|
+
`TimeIndexMetaTable.delete_after_date(...)`.
|
|
396
|
+
|
|
397
|
+
The DataNode delete path is:
|
|
398
|
+
|
|
399
|
+
```text
|
|
400
|
+
POST /orm/api/ts_manager/dynamic_table/<dynamic_table_uid>/delete_after_date/
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Use `after_date` for global tail rollback. Use `dimension_filters` or
|
|
404
|
+
`index_coordinates` for scoped deletes, including scoped full-stream deletes
|
|
405
|
+
where `after_date=None`. Never allow `after_date=None` without an explicit
|
|
406
|
+
dimension or coordinate scope.
|
|
407
|
+
|
|
390
408
|
## Review Rules
|
|
391
409
|
|
|
392
410
|
When reviewing an existing MetaTable workflow, look for:
|
|
@@ -406,6 +424,8 @@ When reviewing an existing MetaTable workflow, look for:
|
|
|
406
424
|
- migration work that asks users to define backend payloads, artifact rows, or SDK request objects
|
|
407
425
|
- compiled SQL operations without complete table scope
|
|
408
426
|
- raw SQL that hardcodes stale physical names
|
|
427
|
+
- raw SQL or compiled SQL deletes against DataNode-owned
|
|
428
|
+
`PlatformTimeIndexMetaTable` storage instead of `delete_after_date(...)`
|
|
409
429
|
- a table that should really be modeled as a DataNode instead
|
|
410
430
|
|
|
411
431
|
## Validation Checklist
|
|
@@ -11450,6 +11450,66 @@ def project_sync(
|
|
|
11450
11450
|
success(f"Synced: {repo_name}")
|
|
11451
11451
|
|
|
11452
11452
|
|
|
11453
|
+
@project.command("sync-after-commit")
|
|
11454
|
+
def project_sync_after_commit(
|
|
11455
|
+
project_uid: str | None = typer.Argument(
|
|
11456
|
+
None,
|
|
11457
|
+
help="Project UID. If omitted, read MAIN_SEQUENCE_PROJECT_UID from local .env.",
|
|
11458
|
+
),
|
|
11459
|
+
path: str | None = typer.Option(
|
|
11460
|
+
None,
|
|
11461
|
+
"--path",
|
|
11462
|
+
help="Project directory used to resolve MAIN_SEQUENCE_PROJECT_UID when PROJECT_UID is omitted.",
|
|
11463
|
+
),
|
|
11464
|
+
timeout: int | None = typer.Option(None, "--timeout", help="Request timeout in seconds."),
|
|
11465
|
+
):
|
|
11466
|
+
"""
|
|
11467
|
+
Trigger backend post-commit project sync.
|
|
11468
|
+
|
|
11469
|
+
This directly calls:
|
|
11470
|
+
|
|
11471
|
+
POST /orm/api/pods/projects/<project_uid>/sync_project_after_commit/
|
|
11472
|
+
|
|
11473
|
+
Examples
|
|
11474
|
+
--------
|
|
11475
|
+
```bash
|
|
11476
|
+
mainsequence project sync-after-commit project-uid-123
|
|
11477
|
+
mainsequence project sync-after-commit --path .
|
|
11478
|
+
```
|
|
11479
|
+
"""
|
|
11480
|
+
_require_login()
|
|
11481
|
+
|
|
11482
|
+
resolved_project_uid = project_uid
|
|
11483
|
+
if resolved_project_uid is None:
|
|
11484
|
+
project_dir = normalize_path(path) if path else pathlib.Path.cwd()
|
|
11485
|
+
if path and not project_dir.exists():
|
|
11486
|
+
error(f"Folder does not exist: {project_dir}")
|
|
11487
|
+
raise typer.Exit(1)
|
|
11488
|
+
resolved_project_uid = _read_project_ref_from_env_file(project_dir)
|
|
11489
|
+
|
|
11490
|
+
if resolved_project_uid is None:
|
|
11491
|
+
error(
|
|
11492
|
+
"Could not determine project uid. Pass PROJECT_UID or ensure "
|
|
11493
|
+
"MAIN_SEQUENCE_PROJECT_UID is present in local .env."
|
|
11494
|
+
)
|
|
11495
|
+
raise typer.Exit(1)
|
|
11496
|
+
|
|
11497
|
+
try:
|
|
11498
|
+
payload = sync_project_after_commit(resolved_project_uid, timeout=timeout)
|
|
11499
|
+
except ApiError as e:
|
|
11500
|
+
error(f"Backend post-commit sync failed: {e}")
|
|
11501
|
+
raise typer.Exit(1) from e
|
|
11502
|
+
|
|
11503
|
+
result = payload or {
|
|
11504
|
+
"project_uid": resolved_project_uid,
|
|
11505
|
+
"detail": "sync_project_after_commit triggered",
|
|
11506
|
+
}
|
|
11507
|
+
if _emit_json(result):
|
|
11508
|
+
return
|
|
11509
|
+
|
|
11510
|
+
success(f"Triggered backend sync for project {resolved_project_uid}.")
|
|
11511
|
+
|
|
11512
|
+
|
|
11453
11513
|
@project.command("sync_project", hidden=True)
|
|
11454
11514
|
def project_sync_project(
|
|
11455
11515
|
message: str = typer.Argument(..., help="Git commit message"),
|
|
@@ -183,6 +183,16 @@ class Project(LabelableObjectMixin, ShareableObjectMixin, BasePydanticModel, Bas
|
|
|
183
183
|
examples=["git@github.com:mainsequence/data-pipeline.git"],
|
|
184
184
|
json_schema_extra={"label": "Git SSH URL"},
|
|
185
185
|
)
|
|
186
|
+
latest_git_version: str = Field(
|
|
187
|
+
"",
|
|
188
|
+
title="Latest Git Version",
|
|
189
|
+
description=(
|
|
190
|
+
"Normalized highest valid version extracted from repository tags for the "
|
|
191
|
+
"project's configured branch. Empty when the backend has not found a valid version."
|
|
192
|
+
),
|
|
193
|
+
examples=["1.2.3"],
|
|
194
|
+
json_schema_extra={"label": "Latest Git Version"},
|
|
195
|
+
)
|
|
186
196
|
created_by: str | int | dict[str, Any] | None = Field(
|
|
187
197
|
None,
|
|
188
198
|
title="Created By",
|
|
@@ -10294,6 +10294,59 @@ def test_project_sync_triggers_backend_sync_after_push(cli_mod, runner, monkeypa
|
|
|
10294
10294
|
assert "Triggered backend sync for project project-uid-123." in result.output
|
|
10295
10295
|
|
|
10296
10296
|
|
|
10297
|
+
def test_project_sync_after_commit_uses_project_uid(cli_mod, runner, monkeypatch):
|
|
10298
|
+
captured = {}
|
|
10299
|
+
|
|
10300
|
+
monkeypatch.setattr(cli_mod, "_require_login", lambda: {"username": "u"})
|
|
10301
|
+
monkeypatch.setattr(
|
|
10302
|
+
cli_mod,
|
|
10303
|
+
"sync_project_after_commit",
|
|
10304
|
+
lambda project_uid, timeout=None: captured.update(
|
|
10305
|
+
project_uid=project_uid,
|
|
10306
|
+
timeout=timeout,
|
|
10307
|
+
)
|
|
10308
|
+
or {"uid": project_uid},
|
|
10309
|
+
)
|
|
10310
|
+
|
|
10311
|
+
result = runner.invoke(
|
|
10312
|
+
cli_mod.app,
|
|
10313
|
+
["project", "sync-after-commit", "project-uid-123", "--timeout", "30"],
|
|
10314
|
+
)
|
|
10315
|
+
|
|
10316
|
+
assert result.exit_code == 0
|
|
10317
|
+
assert captured == {"project_uid": "project-uid-123", "timeout": 30}
|
|
10318
|
+
assert "Triggered backend sync for project project-uid-123." in result.output
|
|
10319
|
+
|
|
10320
|
+
|
|
10321
|
+
def test_project_sync_after_commit_reads_project_uid_from_env_file(
|
|
10322
|
+
cli_mod, runner, monkeypatch, tmp_path
|
|
10323
|
+
):
|
|
10324
|
+
target = tmp_path / "project"
|
|
10325
|
+
target.mkdir()
|
|
10326
|
+
(target / ".env").write_text("MAIN_SEQUENCE_PROJECT_UID=project-uid-123\n", encoding="utf-8")
|
|
10327
|
+
|
|
10328
|
+
monkeypatch.setattr(cli_mod, "_require_login", lambda: {"username": "u"})
|
|
10329
|
+
monkeypatch.setattr(
|
|
10330
|
+
cli_mod,
|
|
10331
|
+
"sync_project_after_commit",
|
|
10332
|
+
lambda project_uid, timeout=None: {
|
|
10333
|
+
"project_uid": project_uid,
|
|
10334
|
+
"status": "queued",
|
|
10335
|
+
},
|
|
10336
|
+
)
|
|
10337
|
+
|
|
10338
|
+
result = runner.invoke(
|
|
10339
|
+
cli_mod.app,
|
|
10340
|
+
["project", "sync-after-commit", "--path", str(target), "--json"],
|
|
10341
|
+
)
|
|
10342
|
+
|
|
10343
|
+
assert result.exit_code == 0
|
|
10344
|
+
assert json.loads(result.output) == {
|
|
10345
|
+
"project_uid": "project-uid-123",
|
|
10346
|
+
"status": "queued",
|
|
10347
|
+
}
|
|
10348
|
+
|
|
10349
|
+
|
|
10297
10350
|
def test_project_sync_project(cli_mod, runner, monkeypatch, tmp_path):
|
|
10298
10351
|
target = tmp_path / "project"
|
|
10299
10352
|
target.mkdir(parents=True, exist_ok=True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/a2a_communication/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/dashboards/streamlit/SKILL.md
RENAMED
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/data_access/exploration/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/app_component.py
RENAMED
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/connections.py
RENAMED
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/data_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/command_center/workspace_snapshot.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/data_sources_interfaces/__init__.py
RENAMED
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/data_sources_interfaces/duckdb.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/client/data_sources_interfaces/sqlite.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/compiled_sql/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/build_operations.py
RENAMED
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/data_nodes.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/namespacing.py
RENAMED
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/persist_managers.py
RENAMED
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/data_nodes/run_operations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/mainsequence/meta_tables/sqlalchemy_contracts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_command_center_app_component_models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.3.19 → mainsequence-4.3.20}/tests/test_data_node_storage_dimension_queries.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|