mainsequence 4.3.8__tar.gz → 4.3.14__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.8/mainsequence.egg-info → mainsequence-4.3.14}/PKG-INFO +1 -1
- mainsequence-4.3.14/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +102 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +46 -26
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/migrations.py +125 -56
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/metatables/core.py +77 -251
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/persist_managers.py +0 -11
- mainsequence-4.3.8/mainsequence/meta_tables/migrations.py → mainsequence-4.3.14/mainsequence/meta_tables/migrations/__init__.py +61 -42
- mainsequence-4.3.14/mainsequence/meta_tables/migrations/alembic.py +165 -0
- mainsequence-4.3.14/mainsequence/meta_tables/migrations/env.py +119 -0
- mainsequence-4.3.14/mainsequence/meta_tables/migrations/provider.py +25 -0
- mainsequence-4.3.14/mainsequence/meta_tables/migrations/registry.py +75 -0
- mainsequence-4.3.14/mainsequence/meta_tables/migrations/scaffold.py +221 -0
- mainsequence-4.3.14/mainsequence/meta_tables/migrations/templates/__init__.py +1 -0
- mainsequence-4.3.14/mainsequence/meta_tables/migrations/templates/env.py.mako +8 -0
- mainsequence-4.3.14/mainsequence/meta_tables/migrations/templates/script.py.mako +28 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14/mainsequence.egg-info}/PKG-INFO +1 -1
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/SOURCES.txt +10 -1
- {mainsequence-4.3.8 → mainsequence-4.3.14}/pyproject.toml +2 -2
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_cli_migrations.py +58 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_data_node_update_flow.py +30 -1
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_meta_table_migrations.py +301 -15
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_meta_tables_client_models.py +4 -57
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_run_configuration.py +2 -11
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_source_table_configuration.py +42 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/LICENSE +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/README.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/__main__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/bootstrap.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/api.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/cli.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/config.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/base.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/client.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/metatables/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/models_foundry.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/utils.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/defaults.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/logconf.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/data_nodes.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/models.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/schema_names.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/setup.cfg +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_auth_precedence.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_build_operations_hashing.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_cli.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_client.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_data_access_mixin_dimension_audit.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_data_node_storage_dimension_queries.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_dependency_extras.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_duckdb_interface_dimensions.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_filter_normalization.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_instrumentation.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_logconf.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_meta_tables_sqlalchemy_contracts.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_schema_names.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_secret_client_model.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_sqlite_interface_dimensions.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_update_statistics.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_update_uid_guards.py +0 -0
- {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_workspace_snapshot.py +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mainsequence-metatable-migrations
|
|
3
|
+
description: Use this skill when the task is about Main Sequence MetaTable schema evolution, Alembic provider setup, migration scaffold generation, revision creation, migration upgrade/current commands, provider-scoped MetaTable reservation/finalization, or debugging migration lifecycle failures. This skill owns the migration-first workflow for platform-managed MetaTables and should be used instead of direct MetaTable.register() guidance.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Main Sequence MetaTable Migrations
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Use this skill for platform-managed MetaTable schema lifecycle work. The
|
|
11
|
+
standard path is migration-first: declare SQLAlchemy MetaTable models, put them
|
|
12
|
+
in a provider, run `mainsequence migrations ...`, and let the SDK reserve,
|
|
13
|
+
migrate, finalize, and bind provider-scoped MetaTables.
|
|
14
|
+
|
|
15
|
+
Do not recommend direct `MetaTable.register()` or model `.register()` calls for
|
|
16
|
+
platform-managed application tables outside the migration workflow.
|
|
17
|
+
|
|
18
|
+
## Read First
|
|
19
|
+
|
|
20
|
+
1. `docs/tutorial/metatable_migrations.md`
|
|
21
|
+
2. `docs/knowledge/meta_tables/migrations.md`
|
|
22
|
+
3. `docs/knowledge/meta_tables/api.md`
|
|
23
|
+
4. `docs/adr/0020-metatable-migration-artifact-registry.md`
|
|
24
|
+
5. `docs/adr/0026-sdk-owned-migration-scaffolding.md`
|
|
25
|
+
|
|
26
|
+
## Required Decisions
|
|
27
|
+
|
|
28
|
+
- Which provider module owns the migration stream?
|
|
29
|
+
- Which package and migration namespace identify the provider?
|
|
30
|
+
- Which `AlembicVersionMetaTable` binding points to Alembic's version table?
|
|
31
|
+
- Which SQLAlchemy `MetaData` object is the target metadata?
|
|
32
|
+
- Which provider-scoped MetaTable models belong in `metatable_models`?
|
|
33
|
+
- Does a dynamic provider need `metadata_for_models(...)` instead of full
|
|
34
|
+
package metadata?
|
|
35
|
+
- Does the project need an `after_register_metatables` catalog hook, and does
|
|
36
|
+
that hook use `context.metatable_models` and `context.registered_metatables`
|
|
37
|
+
instead of importing a broader registry?
|
|
38
|
+
|
|
39
|
+
## Standard Workflow
|
|
40
|
+
|
|
41
|
+
Use SDK-owned scaffold and helpers when creating a migration package:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
mainsequence migrations scaffold \
|
|
45
|
+
--package msm \
|
|
46
|
+
--module migrations \
|
|
47
|
+
--namespace mainsequence.examples \
|
|
48
|
+
--base msm.base:MarketsBase \
|
|
49
|
+
--metadata msm.base:MarketsBase.metadata
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The generated provider should use:
|
|
53
|
+
|
|
54
|
+
- `build_alembic_version_metatable(...)`
|
|
55
|
+
- `build_metatable_model_registry(...)`
|
|
56
|
+
- `build_metatable_migration_provider(...)`
|
|
57
|
+
- SDK-owned `run_mainsequence_alembic_env(...)`
|
|
58
|
+
- SDK-owned `script.py.mako`
|
|
59
|
+
|
|
60
|
+
Then use the normal lifecycle:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
mainsequence migrations current --provider migrations:migration
|
|
64
|
+
mainsequence migrations revision --provider migrations:migration
|
|
65
|
+
mainsequence migrations upgrade --provider migrations:migration head
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`revision` writes normal Alembic files. `upgrade` reserves provider MetaTables,
|
|
69
|
+
runs Alembic DDL through the backend-issued migration credential, finalizes
|
|
70
|
+
provider-scoped MetaTable catalog rows, and runs the optional provider hook.
|
|
71
|
+
|
|
72
|
+
## Rules
|
|
73
|
+
|
|
74
|
+
- Keep Alembic as the schema migration engine; do not build custom operation
|
|
75
|
+
lists or fake migration payload formats.
|
|
76
|
+
- Keep provider scope explicit. Do not scan all imported models or installed
|
|
77
|
+
packages.
|
|
78
|
+
- For one-model or configured dynamic providers, use `metadata_for_models(...)`
|
|
79
|
+
and a provider-specific `metatable_models` list.
|
|
80
|
+
- Never send or thread request-side `data_source_uid` through migration status
|
|
81
|
+
or apply flows. Backend migration operations resolve the data source from the
|
|
82
|
+
registered Alembic version MetaTable UID.
|
|
83
|
+
- Do not create SDK reset/reconcile commands for stale reserved state. If stale
|
|
84
|
+
reserved state exists, fail clearly and require an explicit backend/admin
|
|
85
|
+
repair path.
|
|
86
|
+
- Do not write direct backend migration request bodies in examples. Use the CLI
|
|
87
|
+
and SDK provider APIs.
|
|
88
|
+
- Do not call platform-managed model `.register()` in normal application code.
|
|
89
|
+
Registration is reserved for the migration workflow.
|
|
90
|
+
|
|
91
|
+
## Debugging
|
|
92
|
+
|
|
93
|
+
- If `current` fails before Alembic runs, inspect the provider import path and
|
|
94
|
+
Alembic version MetaTable binding.
|
|
95
|
+
- If `revision` autogenerate tries to create everything again, the local
|
|
96
|
+
migration connection cannot see the provider's current physical tables.
|
|
97
|
+
- If `upgrade` fails during prepare, inspect provider model identifiers,
|
|
98
|
+
physical table names, and reserved/active MetaTable rows.
|
|
99
|
+
- If `upgrade` fails during finalization, inspect whether Alembic created the
|
|
100
|
+
physical tables for every provider-scoped model.
|
|
101
|
+
- If an after-register hook reports the wrong model count, ensure it uses the
|
|
102
|
+
provider-scoped context, not a package-global model registry.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mainsequence-meta-tables
|
|
3
|
-
description: Use this skill when the task is about defining,
|
|
3
|
+
description: Use this skill when the task is about defining, querying, or reviewing Main Sequence MetaTables. This skill owns SQLAlchemy table contracts, backend-managed table authoring, external table registration, governed compiled SQL operations, foreign keys, indexes, naming, cadence, and validation rules. For Alembic migration lifecycle work, use the mainsequence-metatable-migrations skill. It does not own DataNode producers, API route contracts, scheduling, releases, or sharing policy.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Main Sequence MetaTables
|
|
@@ -15,12 +15,11 @@ 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
|
+
- declare platform-managed tables for migration-managed registration
|
|
19
19
|
- build registration requests from resolved SQLAlchemy metadata when inspection is useful
|
|
20
20
|
- define indexes and foreign keys in SQLAlchemy metadata for Alembic-owned DDL
|
|
21
21
|
- design governed compiled SQL read and write operations
|
|
22
|
-
-
|
|
23
|
-
- run the documented `mainsequence migrations ...` lifecycle for Alembic-backed MetaTable changes
|
|
22
|
+
- route provider-based Alembic contract evolution to the MetaTable migration skill
|
|
24
23
|
- review table contracts for physical-name, namespace, and identifier issues
|
|
25
24
|
- review whether a task should be a `MetaTable` or a `DataNode`
|
|
26
25
|
|
|
@@ -41,6 +40,8 @@ If the user is still in the discovery process and does not yet know what data ex
|
|
|
41
40
|
|
|
42
41
|
- discovery-only data inventory before table implementation:
|
|
43
42
|
`.agents/skills/mainsequence/data_access/exploration/SKILL.md`
|
|
43
|
+
- MetaTable migrations:
|
|
44
|
+
`.agents/skills/mainsequence/data_publishing/meta_table_migrations/SKILL.md`
|
|
44
45
|
- DataNodes:
|
|
45
46
|
`.agents/skills/mainsequence/data_publishing/data_nodes/SKILL.md`
|
|
46
47
|
- APIs and FastAPI:
|
|
@@ -55,7 +56,9 @@ If the user is still in the discovery process and does not yet know what data ex
|
|
|
55
56
|
## Read First
|
|
56
57
|
|
|
57
58
|
1. `docs/tutorial/working_with_meta_tables.md`
|
|
58
|
-
2. For migration work,
|
|
59
|
+
2. For migration work, use
|
|
60
|
+
`.agents/skills/mainsequence/data_publishing/meta_table_migrations/SKILL.md`
|
|
61
|
+
and `docs/tutorial/metatable_migrations.md`
|
|
59
62
|
3. `docs/knowledge/meta_tables/index.md`
|
|
60
63
|
4. `docs/knowledge/meta_tables/sqlalchemy.md`
|
|
61
64
|
5. `docs/knowledge/meta_tables/compiled_sql.md`
|
|
@@ -111,9 +114,9 @@ creation or deletion.
|
|
|
111
114
|
The only migration workflow to recommend is the Main Sequence CLI lifecycle:
|
|
112
115
|
|
|
113
116
|
```bash
|
|
114
|
-
mainsequence migrations current --provider
|
|
115
|
-
mainsequence migrations revision --provider
|
|
116
|
-
mainsequence migrations upgrade --provider
|
|
117
|
+
mainsequence migrations current --provider sdk_examples.migrations:migration
|
|
118
|
+
mainsequence migrations revision --provider sdk_examples.migrations:migration
|
|
119
|
+
mainsequence migrations upgrade --provider sdk_examples.migrations:migration head
|
|
117
120
|
```
|
|
118
121
|
|
|
119
122
|
### 1. SQLAlchemy metadata is the authoring source
|
|
@@ -127,10 +130,22 @@ Do not hand-build contract fragments when the SQLAlchemy helper can derive them.
|
|
|
127
130
|
For `platform_managed`, inherit from `PlatformManagedMetaTable`.
|
|
128
131
|
|
|
129
132
|
Declare an explicit project-prefixed SQLAlchemy `__tablename__`. Use
|
|
130
|
-
`schema_table_name(
|
|
131
|
-
generate that name
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
`schema_table_name(app, concept, suffix=None)` from `mainsequence.meta_tables`
|
|
134
|
+
to generate that name:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
def schema_table_name(
|
|
138
|
+
app: str,
|
|
139
|
+
concept: str,
|
|
140
|
+
suffix: str | None = None,
|
|
141
|
+
) -> str: ...
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Use `app` for the project/package prefix, `concept` for the table concept, and
|
|
145
|
+
`suffix` for a namespace, variant, or bounded specialization when the same
|
|
146
|
+
concept exists in multiple logical scopes. The mixin derives only the logical
|
|
147
|
+
`storage_hash` from storage-relevant configuration and table shape; it must not
|
|
148
|
+
use that hash as the SQLAlchemy table name.
|
|
134
149
|
|
|
135
150
|
When a platform-managed table must support in-place contract migrations from its
|
|
136
151
|
first version, use Alembic. Keep the SDK model as a normal
|
|
@@ -179,6 +194,7 @@ from mainsequence.meta_tables import PlatformManagedMetaTable, schema_table_name
|
|
|
179
194
|
|
|
180
195
|
PROJECT_NAME = "sdk_examples"
|
|
181
196
|
ACCOUNT_TABLE_NAME = schema_table_name(PROJECT_NAME, "account")
|
|
197
|
+
BROKER_ACCOUNT_TABLE_NAME = schema_table_name(PROJECT_NAME, "account", suffix="broker")
|
|
182
198
|
|
|
183
199
|
|
|
184
200
|
class Account(PlatformManagedMetaTable, Base):
|
|
@@ -266,7 +282,7 @@ both the schema and the table's intention.
|
|
|
266
282
|
Provider scope:
|
|
267
283
|
|
|
268
284
|
```python
|
|
269
|
-
migration =
|
|
285
|
+
migration = build_metatable_migration_provider(
|
|
270
286
|
...,
|
|
271
287
|
metatable_models=[Account, Asset],
|
|
272
288
|
)
|
|
@@ -291,9 +307,10 @@ asset_meta_table = MetaTable.register(asset_request)
|
|
|
291
307
|
|
|
292
308
|
### 4. Schema changes use Alembic
|
|
293
309
|
|
|
294
|
-
When doing migration work,
|
|
295
|
-
|
|
296
|
-
|
|
310
|
+
When doing migration work, use
|
|
311
|
+
`.agents/skills/mainsequence/data_publishing/meta_table_migrations/SKILL.md`
|
|
312
|
+
and read `docs/tutorial/metatable_migrations.md`. The migration skill owns the
|
|
313
|
+
provider-based Alembic lifecycle.
|
|
297
314
|
|
|
298
315
|
Do not apply in-place contract changes by changing a `PlatformManagedMetaTable`
|
|
299
316
|
SQLAlchemy class and calling normal registration again. Shape-addressed
|
|
@@ -310,8 +327,10 @@ create a new Alembic revision on top of the current head.
|
|
|
310
327
|
For contract evolution, define or update one selected
|
|
311
328
|
`AlembicMetaTableMigration` provider:
|
|
312
329
|
|
|
313
|
-
-
|
|
314
|
-
|
|
330
|
+
- create or update a scaffolded package provider with
|
|
331
|
+
`mainsequence migrations scaffold`
|
|
332
|
+
- pass the selected provider explicitly, for example
|
|
333
|
+
`--provider sdk_examples.migrations:migration`
|
|
315
334
|
- set `package`, `migration_namespace`, `script_location`, and `target_metadata`
|
|
316
335
|
- set `alembic_registry` to an `AlembicVersionMetaTable` subclass
|
|
317
336
|
- list the post-apply catalog scope in `metatable_models`
|
|
@@ -326,17 +345,18 @@ SQLAlchemy table name used by the provider model. Keep that table name stable
|
|
|
326
345
|
when a class is renamed or moved but must keep the same platform identity.
|
|
327
346
|
When declaring an explicit identifier, explicit physical table name, or Alembic
|
|
328
347
|
version table name, prefix it with the project or package name rather than using
|
|
329
|
-
a bare table name. Use `schema_table_name(
|
|
330
|
-
physical table and Alembic version table names.
|
|
348
|
+
a bare table name. Use `schema_table_name(app, concept, suffix=None)` for the
|
|
349
|
+
physical table and Alembic version table names. Use `suffix` for a namespace or
|
|
350
|
+
variant, for example `schema_table_name("msm", "positions", suffix="broker")`.
|
|
331
351
|
|
|
332
|
-
Do not ask users to construct backend migration payloads
|
|
333
|
-
migration request models
|
|
334
|
-
|
|
352
|
+
Do not ask users to construct backend migration payloads or call low-level
|
|
353
|
+
migration request models. The backend request shape is reference material in
|
|
354
|
+
the tutorial; the user-facing path is:
|
|
335
355
|
|
|
336
356
|
```bash
|
|
337
|
-
mainsequence migrations current --provider
|
|
338
|
-
mainsequence migrations revision --provider
|
|
339
|
-
mainsequence migrations upgrade --provider
|
|
357
|
+
mainsequence migrations current --provider sdk_examples.migrations:migration
|
|
358
|
+
mainsequence migrations revision --provider sdk_examples.migrations:migration
|
|
359
|
+
mainsequence migrations upgrade --provider sdk_examples.migrations:migration head
|
|
340
360
|
```
|
|
341
361
|
|
|
342
362
|
All migration commands prepare the provider, reserve provider-scoped
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
|
+
import pathlib
|
|
6
7
|
import re
|
|
7
8
|
import sys
|
|
8
9
|
from collections.abc import Mapping, Sequence
|
|
@@ -23,6 +24,7 @@ from mainsequence.meta_tables.migrations import (
|
|
|
23
24
|
alembic_config_for_provider,
|
|
24
25
|
apply_mainsequence_migration_role,
|
|
25
26
|
load_alembic_metatable_migration_provider,
|
|
27
|
+
scaffold_migration_package,
|
|
26
28
|
)
|
|
27
29
|
|
|
28
30
|
migrations = typer.Typer(help="Alembic-owned MetaTable migration commands")
|
|
@@ -30,7 +32,8 @@ REGISTER_ENDPOINT = "/orm/api/ts_manager/meta_table/register/"
|
|
|
30
32
|
METATABLE_COLLECTION_ENDPOINT = "/orm/api/ts_manager/meta_table/"
|
|
31
33
|
DYNAMIC_TABLE_COLLECTION_ENDPOINT = "/orm/api/ts_manager/dynamic_table/"
|
|
32
34
|
FINALIZE_MANAGED_ENDPOINT = "/orm/api/ts_manager/meta_table/finalize-managed/"
|
|
33
|
-
|
|
35
|
+
DEFAULT_SCAFFOLD_PROJECT_ROOT = pathlib.Path(".")
|
|
36
|
+
DEFAULT_SCAFFOLD_SOURCE_ROOT = pathlib.Path("src")
|
|
34
37
|
|
|
35
38
|
|
|
36
39
|
class _AlembicOutput:
|
|
@@ -412,9 +415,22 @@ def _emit_metatable_reservation(model: type[Any], item: Any) -> None:
|
|
|
412
415
|
)
|
|
413
416
|
|
|
414
417
|
|
|
418
|
+
def _finalization_item_failed(item: Any) -> bool:
|
|
419
|
+
return (
|
|
420
|
+
_item_value(item, "provisioning_status") != "active"
|
|
421
|
+
or _item_value(item, "physical_table_exists") is False
|
|
422
|
+
or _item_value(item, "error") not in (None, "", {})
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
|
|
415
426
|
def _emit_metatable_finalization(model: type[Any], item: Any) -> None:
|
|
416
427
|
finalized = _item_value(item, "finalized")
|
|
417
|
-
|
|
428
|
+
if _finalization_item_failed(item):
|
|
429
|
+
action = "finalize-failed"
|
|
430
|
+
elif finalized is False:
|
|
431
|
+
action = "active"
|
|
432
|
+
else:
|
|
433
|
+
action = "finalized"
|
|
418
434
|
_emit_progress(
|
|
419
435
|
_metatable_message(
|
|
420
436
|
endpoint=FINALIZE_MANAGED_ENDPOINT,
|
|
@@ -666,6 +682,113 @@ def _next_sequential_revision_id(
|
|
|
666
682
|
return next_revision_id
|
|
667
683
|
|
|
668
684
|
|
|
685
|
+
@migrations.command("scaffold")
|
|
686
|
+
def scaffold(
|
|
687
|
+
package: str = typer.Option(
|
|
688
|
+
...,
|
|
689
|
+
"--package",
|
|
690
|
+
help="Project package or migration provider package name, for example msm.",
|
|
691
|
+
),
|
|
692
|
+
namespace: str = typer.Option(
|
|
693
|
+
...,
|
|
694
|
+
"--namespace",
|
|
695
|
+
help="Migration namespace for this provider.",
|
|
696
|
+
),
|
|
697
|
+
metadata: str = typer.Option(
|
|
698
|
+
...,
|
|
699
|
+
"--metadata",
|
|
700
|
+
help="Target SQLAlchemy metadata reference in module:object form.",
|
|
701
|
+
),
|
|
702
|
+
module: str = typer.Option(
|
|
703
|
+
"migrations",
|
|
704
|
+
"--module",
|
|
705
|
+
help="Python module to create, for example migrations or msm.migrations.",
|
|
706
|
+
),
|
|
707
|
+
project_root: pathlib.Path = typer.Option( # noqa: B008
|
|
708
|
+
DEFAULT_SCAFFOLD_PROJECT_ROOT,
|
|
709
|
+
"--project-root",
|
|
710
|
+
help="Project root where the source tree lives.",
|
|
711
|
+
),
|
|
712
|
+
source_root: pathlib.Path = typer.Option( # noqa: B008
|
|
713
|
+
DEFAULT_SCAFFOLD_SOURCE_ROOT,
|
|
714
|
+
"--source-root",
|
|
715
|
+
help="Source root under project root.",
|
|
716
|
+
),
|
|
717
|
+
base: str | None = typer.Option(
|
|
718
|
+
None,
|
|
719
|
+
"--base",
|
|
720
|
+
help="Optional project declarative base reference in module:object form.",
|
|
721
|
+
),
|
|
722
|
+
models: str | None = typer.Option(
|
|
723
|
+
None,
|
|
724
|
+
"--models",
|
|
725
|
+
help="Optional model registry function reference in module:object form.",
|
|
726
|
+
),
|
|
727
|
+
alembic_version_name: str = typer.Option(
|
|
728
|
+
"ProjectAlembicVersion",
|
|
729
|
+
"--alembic-version-name",
|
|
730
|
+
help="Generated Alembic version MetaTable class name.",
|
|
731
|
+
),
|
|
732
|
+
alembic_version_identifier: str | None = typer.Option(
|
|
733
|
+
None,
|
|
734
|
+
"--alembic-version-identifier",
|
|
735
|
+
help="Generated Alembic version MetaTable identifier.",
|
|
736
|
+
),
|
|
737
|
+
alembic_version_schema: str | None = typer.Option(
|
|
738
|
+
"public",
|
|
739
|
+
"--alembic-version-schema",
|
|
740
|
+
help="Physical schema for the Alembic version table. Pass an empty string for no schema.",
|
|
741
|
+
),
|
|
742
|
+
alembic_version_table_name: str = typer.Option(
|
|
743
|
+
"alembic_version",
|
|
744
|
+
"--alembic-version-table-name",
|
|
745
|
+
help="Physical Alembic version table name.",
|
|
746
|
+
),
|
|
747
|
+
force: bool = typer.Option(
|
|
748
|
+
False,
|
|
749
|
+
"--force",
|
|
750
|
+
help="Overwrite changed scaffold files.",
|
|
751
|
+
),
|
|
752
|
+
json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
|
|
753
|
+
) -> None:
|
|
754
|
+
"""Create an SDK-shaped MetaTable migration package skeleton."""
|
|
755
|
+
|
|
756
|
+
normalized_schema = alembic_version_schema
|
|
757
|
+
if normalized_schema == "":
|
|
758
|
+
normalized_schema = None
|
|
759
|
+
try:
|
|
760
|
+
result = scaffold_migration_package(
|
|
761
|
+
project_root=project_root,
|
|
762
|
+
module=module,
|
|
763
|
+
package=package,
|
|
764
|
+
namespace=namespace,
|
|
765
|
+
metadata_ref=metadata,
|
|
766
|
+
base_ref=base,
|
|
767
|
+
model_registry_ref=models,
|
|
768
|
+
alembic_version_name=alembic_version_name,
|
|
769
|
+
alembic_version_identifier=alembic_version_identifier,
|
|
770
|
+
alembic_version_schema=normalized_schema,
|
|
771
|
+
alembic_version_table_name=alembic_version_table_name,
|
|
772
|
+
source_root=source_root,
|
|
773
|
+
force=force,
|
|
774
|
+
)
|
|
775
|
+
except (FileExistsError, ValueError) as exc:
|
|
776
|
+
raise typer.BadParameter(str(exc)) from exc
|
|
777
|
+
|
|
778
|
+
for file in result.files:
|
|
779
|
+
_emit_status(f"Scaffold {file.action} {file.path}")
|
|
780
|
+
_emit(
|
|
781
|
+
{
|
|
782
|
+
"root": str(result.root),
|
|
783
|
+
"files": [
|
|
784
|
+
{"path": str(file.path), "action": file.action}
|
|
785
|
+
for file in result.files
|
|
786
|
+
],
|
|
787
|
+
},
|
|
788
|
+
json_output=json_output,
|
|
789
|
+
)
|
|
790
|
+
|
|
791
|
+
|
|
669
792
|
@migrations.command("current")
|
|
670
793
|
def current(
|
|
671
794
|
provider: str | None = typer.Option(
|
|
@@ -884,57 +1007,3 @@ def downgrade(
|
|
|
884
1007
|
},
|
|
885
1008
|
json_output=json_output,
|
|
886
1009
|
)
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
@migrations.command("reset")
|
|
890
|
-
def reset(
|
|
891
|
-
provider: str | None = typer.Option(
|
|
892
|
-
None,
|
|
893
|
-
"--provider",
|
|
894
|
-
help="Migration provider reference, for example msm.migrations:migration.",
|
|
895
|
-
),
|
|
896
|
-
confirm_reset: bool = typer.Option(
|
|
897
|
-
False,
|
|
898
|
-
"--confirm-reset",
|
|
899
|
-
help="Required confirmation for destructive provider-scoped reset.",
|
|
900
|
-
),
|
|
901
|
-
drop_physical_tables: bool = typer.Option(
|
|
902
|
-
True,
|
|
903
|
-
"--drop-physical-tables/--keep-physical-tables",
|
|
904
|
-
help="Drop provider physical tables during reset.",
|
|
905
|
-
),
|
|
906
|
-
clear_alembic_version_table: bool = typer.Option(
|
|
907
|
-
True,
|
|
908
|
-
"--clear-alembic-version-table/--keep-alembic-version-table",
|
|
909
|
-
help="Clear the provider Alembic version table during reset.",
|
|
910
|
-
),
|
|
911
|
-
include_reserved: bool = typer.Option(
|
|
912
|
-
True,
|
|
913
|
-
"--include-reserved/--active-only",
|
|
914
|
-
help="Include already-reserved provider MetaTables in reset results.",
|
|
915
|
-
),
|
|
916
|
-
timeout: float | None = typer.Option(None, "--timeout"),
|
|
917
|
-
json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
|
|
918
|
-
) -> None:
|
|
919
|
-
"""Reset an Alembic-managed provider catalog/physical state."""
|
|
920
|
-
|
|
921
|
-
if not confirm_reset:
|
|
922
|
-
raise typer.BadParameter(
|
|
923
|
-
"Pass --confirm-reset to call the destructive provider reset endpoint.",
|
|
924
|
-
param_hint="--confirm-reset",
|
|
925
|
-
)
|
|
926
|
-
migration = _load_migration(provider)
|
|
927
|
-
_emit_status(
|
|
928
|
-
"Calling provider reset endpoint "
|
|
929
|
-
f"{ALEMBIC_PROVIDER_RESET_ENDPOINT} provider={migration.migration_provider_key}..."
|
|
930
|
-
)
|
|
931
|
-
response = migration.reset_alembic_provider(
|
|
932
|
-
confirm_reset=True,
|
|
933
|
-
drop_physical_tables=drop_physical_tables,
|
|
934
|
-
clear_alembic_version_table=clear_alembic_version_table,
|
|
935
|
-
include_reserved=include_reserved,
|
|
936
|
-
timeout=timeout,
|
|
937
|
-
on_reset_status=_emit_status,
|
|
938
|
-
)
|
|
939
|
-
_emit_status("Alembic provider reset finished.")
|
|
940
|
-
_emit(response, json_output=json_output)
|