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.
Files changed (138) hide show
  1. {mainsequence-4.3.8/mainsequence.egg-info → mainsequence-4.3.14}/PKG-INFO +1 -1
  2. mainsequence-4.3.14/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +102 -0
  3. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +46 -26
  4. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/migrations.py +125 -56
  5. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/metatables/core.py +77 -251
  6. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/persist_managers.py +0 -11
  7. mainsequence-4.3.8/mainsequence/meta_tables/migrations.py → mainsequence-4.3.14/mainsequence/meta_tables/migrations/__init__.py +61 -42
  8. mainsequence-4.3.14/mainsequence/meta_tables/migrations/alembic.py +165 -0
  9. mainsequence-4.3.14/mainsequence/meta_tables/migrations/env.py +119 -0
  10. mainsequence-4.3.14/mainsequence/meta_tables/migrations/provider.py +25 -0
  11. mainsequence-4.3.14/mainsequence/meta_tables/migrations/registry.py +75 -0
  12. mainsequence-4.3.14/mainsequence/meta_tables/migrations/scaffold.py +221 -0
  13. mainsequence-4.3.14/mainsequence/meta_tables/migrations/templates/__init__.py +1 -0
  14. mainsequence-4.3.14/mainsequence/meta_tables/migrations/templates/env.py.mako +8 -0
  15. mainsequence-4.3.14/mainsequence/meta_tables/migrations/templates/script.py.mako +28 -0
  16. {mainsequence-4.3.8 → mainsequence-4.3.14/mainsequence.egg-info}/PKG-INFO +1 -1
  17. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/SOURCES.txt +10 -1
  18. {mainsequence-4.3.8 → mainsequence-4.3.14}/pyproject.toml +2 -2
  19. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_cli_migrations.py +58 -0
  20. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_data_node_update_flow.py +30 -1
  21. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_meta_table_migrations.py +301 -15
  22. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_meta_tables_client_models.py +4 -57
  23. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_run_configuration.py +2 -11
  24. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_source_table_configuration.py +42 -0
  25. {mainsequence-4.3.8 → mainsequence-4.3.14}/LICENSE +0 -0
  26. {mainsequence-4.3.8 → mainsequence-4.3.14}/README.md +0 -0
  27. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/AGENTS.md +0 -0
  28. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
  29. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
  30. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
  31. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
  32. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
  33. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
  34. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
  35. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
  36. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
  37. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
  38. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
  39. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
  40. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
  41. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
  42. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
  43. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
  44. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
  45. {mainsequence-4.3.8 → mainsequence-4.3.14}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
  46. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/__init__.py +0 -0
  47. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/__main__.py +0 -0
  48. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/bootstrap.py +0 -0
  49. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/__init__.py +0 -0
  50. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/api.py +0 -0
  51. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/browser_auth.py +0 -0
  52. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/cli.py +0 -0
  53. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/config.py +0 -0
  54. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/docker_utils.py +0 -0
  55. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/doctor.py +0 -0
  56. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/local_ops.py +0 -0
  57. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/model_filters.py +0 -0
  58. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/project_status.py +0 -0
  59. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/pydantic_cli.py +0 -0
  60. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/sdk_utils.py +0 -0
  61. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/ssh_utils.py +0 -0
  62. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/cli/ui.py +0 -0
  63. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/__init__.py +0 -0
  64. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/agent_runtime_models.py +0 -0
  65. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/base.py +0 -0
  66. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/client.py +0 -0
  67. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/__init__.py +0 -0
  68. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/app_component.py +0 -0
  69. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/connections.py +0 -0
  70. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/data_models.py +0 -0
  71. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/workspace.py +0 -0
  72. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
  73. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/compute_validation.py +0 -0
  74. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
  75. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
  76. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
  77. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
  78. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/dtype_codec.py +0 -0
  79. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/exceptions.py +0 -0
  80. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/fastapi/__init__.py +0 -0
  81. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/fastapi/auth.py +0 -0
  82. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/metatables/__init__.py +0 -0
  83. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/models_foundry.py +0 -0
  84. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/models_helpers.py +0 -0
  85. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/models_user.py +0 -0
  86. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/client/utils.py +0 -0
  87. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/defaults.py +0 -0
  88. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/instrumentation/__init__.py +0 -0
  89. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/instrumentation/utils.py +0 -0
  90. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/logconf.py +0 -0
  91. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/__init__.py +0 -0
  92. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/__main__.py +0 -0
  93. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
  94. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
  95. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
  96. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
  97. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/data_nodes.py +0 -0
  98. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/models.py +0 -0
  99. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
  100. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
  101. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
  102. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/future_registry.py +0 -0
  103. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/hashing.py +0 -0
  104. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
  105. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/schema_names.py +0 -0
  106. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
  107. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence/runtime_flags.py +0 -0
  108. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/dependency_links.txt +0 -0
  109. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/entry_points.txt +0 -0
  110. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/requires.txt +0 -0
  111. {mainsequence-4.3.8 → mainsequence-4.3.14}/mainsequence.egg-info/top_level.txt +0 -0
  112. {mainsequence-4.3.8 → mainsequence-4.3.14}/setup.cfg +0 -0
  113. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_auth_precedence.py +0 -0
  114. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_build_operations_hashing.py +0 -0
  115. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_cli.py +0 -0
  116. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_cli_browser_auth.py +0 -0
  117. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_client.py +0 -0
  118. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_command_center_app_component_models.py +0 -0
  119. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_command_center_data_models.py +0 -0
  120. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_command_center_models.py +0 -0
  121. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_data_access_mixin_dimension_audit.py +0 -0
  122. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_data_node_storage_dimension_queries.py +0 -0
  123. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_dependency_extras.py +0 -0
  124. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_duckdb_interface_dimensions.py +0 -0
  125. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_filter_normalization.py +0 -0
  126. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_instrumentation.py +0 -0
  127. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_logconf.py +0 -0
  128. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_meta_tables_sqlalchemy_contracts.py +0 -0
  129. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_models_user_request_bound_auth.py +0 -0
  130. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_pod_project_resolution.py +0 -0
  131. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_project_batch_jobs_from_file.py +0 -0
  132. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_schema_names.py +0 -0
  133. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_secret_client_model.py +0 -0
  134. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_sqlite_interface_dimensions.py +0 -0
  135. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_update_runner_uid_runtime.py +0 -0
  136. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_update_statistics.py +0 -0
  137. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_update_uid_guards.py +0 -0
  138. {mainsequence-4.3.8 → mainsequence-4.3.14}/tests/test_workspace_snapshot.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence
3
- Version: 4.3.8
3
+ Version: 4.3.14
4
4
  Summary: Main Sequence SDK
5
5
  Author-email: Main Sequence GmbH <dev@main-sequence.io>
6
6
  License: MainSequence GmbH SDK License Agreement
@@ -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, registering, querying, migrating, or reviewing Main Sequence MetaTables. This skill owns SQLAlchemy table contracts, backend-managed table registration, external table registration, Alembic-based MetaTable migrations, governed compiled SQL operations, foreign keys, indexes, and validation rules. It does not own DataNode producers, API route contracts, scheduling, releases, or sharing policy.
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
- - register platform-managed tables through the model class API
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
- - design provider-based Alembic contract evolution for MetaTables
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, `docs/tutorial/metatable_migrations.md`
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 mainsequence_migrations:migration
115
- mainsequence migrations revision --provider mainsequence_migrations:migration
116
- mainsequence migrations upgrade --provider mainsequence_migrations:migration head
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(project_or_app, concept)` from `mainsequence.meta_tables` to
131
- generate that name. The mixin derives only the logical `storage_hash` from
132
- storage-relevant configuration and table shape; it must not use that hash as the
133
- SQLAlchemy table name.
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 = AlembicMetaTableMigration(
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, first read
295
- `docs/tutorial/metatable_migrations.md`. That document is the tutorial source
296
- for the provider-based Alembic lifecycle.
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
- - put the provider in `mainsequence_migrations.py:migration` or pass
314
- `--provider module.path:migration`
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(project_or_app, concept)` for the
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, call low-level
333
- migration request models, or use SDK helper functions directly. The backend
334
- request shape is reference material in the tutorial; the user-facing path is:
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 mainsequence_migrations:migration
338
- mainsequence migrations revision --provider mainsequence_migrations:migration
339
- mainsequence migrations upgrade --provider mainsequence_migrations:migration head
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
- ALEMBIC_PROVIDER_RESET_ENDPOINT = "/orm/api/ts_manager/meta_table/alembic-provider-reset/"
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
- action = "finalized" if finalized is not False else "finalize-failed"
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)