mainsequence 4.3.9__tar.gz → 4.3.16__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.9/mainsequence.egg-info → mainsequence-4.3.16}/PKG-INFO +1 -1
  2. mainsequence-4.3.16/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +102 -0
  3. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +26 -20
  4. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/migrations.py +125 -56
  5. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/metatables/core.py +94 -251
  6. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/data_nodes/data_nodes.py +24 -3
  7. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/data_nodes/persist_managers.py +140 -29
  8. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/data_nodes/run_operations.py +174 -41
  9. mainsequence-4.3.9/mainsequence/meta_tables/migrations.py → mainsequence-4.3.16/mainsequence/meta_tables/migrations/__init__.py +61 -42
  10. mainsequence-4.3.16/mainsequence/meta_tables/migrations/alembic.py +165 -0
  11. mainsequence-4.3.16/mainsequence/meta_tables/migrations/env.py +119 -0
  12. mainsequence-4.3.16/mainsequence/meta_tables/migrations/provider.py +25 -0
  13. mainsequence-4.3.16/mainsequence/meta_tables/migrations/registry.py +75 -0
  14. mainsequence-4.3.16/mainsequence/meta_tables/migrations/scaffold.py +221 -0
  15. mainsequence-4.3.16/mainsequence/meta_tables/migrations/templates/__init__.py +1 -0
  16. mainsequence-4.3.16/mainsequence/meta_tables/migrations/templates/env.py.mako +8 -0
  17. mainsequence-4.3.16/mainsequence/meta_tables/migrations/templates/script.py.mako +28 -0
  18. {mainsequence-4.3.9 → mainsequence-4.3.16/mainsequence.egg-info}/PKG-INFO +1 -1
  19. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence.egg-info/SOURCES.txt +10 -1
  20. {mainsequence-4.3.9 → mainsequence-4.3.16}/pyproject.toml +2 -2
  21. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_cli_migrations.py +58 -0
  22. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_data_node_update_flow.py +30 -1
  23. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_meta_table_migrations.py +301 -15
  24. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_meta_tables_client_models.py +4 -57
  25. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_meta_tables_sqlalchemy_contracts.py +44 -2
  26. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_run_configuration.py +2 -11
  27. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_source_table_configuration.py +42 -0
  28. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_update_runner_uid_runtime.py +205 -1
  29. {mainsequence-4.3.9 → mainsequence-4.3.16}/LICENSE +0 -0
  30. {mainsequence-4.3.9 → mainsequence-4.3.16}/README.md +0 -0
  31. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/AGENTS.md +0 -0
  32. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
  33. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
  34. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
  35. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
  36. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
  37. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
  38. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
  39. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
  40. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
  41. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
  42. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
  43. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
  44. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
  45. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
  46. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
  47. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
  48. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
  49. {mainsequence-4.3.9 → mainsequence-4.3.16}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
  50. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/__init__.py +0 -0
  51. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/__main__.py +0 -0
  52. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/bootstrap.py +0 -0
  53. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/__init__.py +0 -0
  54. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/api.py +0 -0
  55. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/browser_auth.py +0 -0
  56. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/cli.py +0 -0
  57. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/config.py +0 -0
  58. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/docker_utils.py +0 -0
  59. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/doctor.py +0 -0
  60. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/local_ops.py +0 -0
  61. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/model_filters.py +0 -0
  62. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/project_status.py +0 -0
  63. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/pydantic_cli.py +0 -0
  64. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/sdk_utils.py +0 -0
  65. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/ssh_utils.py +0 -0
  66. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/cli/ui.py +0 -0
  67. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/__init__.py +0 -0
  68. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/agent_runtime_models.py +0 -0
  69. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/base.py +0 -0
  70. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/client.py +0 -0
  71. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/command_center/__init__.py +0 -0
  72. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/command_center/app_component.py +0 -0
  73. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/command_center/connections.py +0 -0
  74. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/command_center/data_models.py +0 -0
  75. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/command_center/workspace.py +0 -0
  76. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
  77. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/compute_validation.py +0 -0
  78. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
  79. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
  80. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
  81. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
  82. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/dtype_codec.py +0 -0
  83. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/exceptions.py +0 -0
  84. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/fastapi/__init__.py +0 -0
  85. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/fastapi/auth.py +0 -0
  86. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/metatables/__init__.py +0 -0
  87. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/models_foundry.py +0 -0
  88. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/models_helpers.py +0 -0
  89. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/models_user.py +0 -0
  90. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/client/utils.py +0 -0
  91. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/defaults.py +0 -0
  92. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/instrumentation/__init__.py +0 -0
  93. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/instrumentation/utils.py +0 -0
  94. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/logconf.py +0 -0
  95. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/__init__.py +0 -0
  96. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/__main__.py +0 -0
  97. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
  98. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
  99. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
  100. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
  101. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/data_nodes/models.py +0 -0
  102. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
  103. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
  104. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/future_registry.py +0 -0
  105. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/hashing.py +0 -0
  106. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
  107. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/schema_names.py +0 -0
  108. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
  109. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence/runtime_flags.py +0 -0
  110. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence.egg-info/dependency_links.txt +0 -0
  111. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence.egg-info/entry_points.txt +0 -0
  112. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence.egg-info/requires.txt +0 -0
  113. {mainsequence-4.3.9 → mainsequence-4.3.16}/mainsequence.egg-info/top_level.txt +0 -0
  114. {mainsequence-4.3.9 → mainsequence-4.3.16}/setup.cfg +0 -0
  115. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_auth_precedence.py +0 -0
  116. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_build_operations_hashing.py +0 -0
  117. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_cli.py +0 -0
  118. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_cli_browser_auth.py +0 -0
  119. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_client.py +0 -0
  120. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_command_center_app_component_models.py +0 -0
  121. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_command_center_data_models.py +0 -0
  122. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_command_center_models.py +0 -0
  123. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_data_access_mixin_dimension_audit.py +0 -0
  124. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_data_node_storage_dimension_queries.py +0 -0
  125. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_dependency_extras.py +0 -0
  126. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_duckdb_interface_dimensions.py +0 -0
  127. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_filter_normalization.py +0 -0
  128. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_instrumentation.py +0 -0
  129. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_logconf.py +0 -0
  130. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_models_user_request_bound_auth.py +0 -0
  131. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_pod_project_resolution.py +0 -0
  132. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_project_batch_jobs_from_file.py +0 -0
  133. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_schema_names.py +0 -0
  134. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_secret_client_model.py +0 -0
  135. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_sqlite_interface_dimensions.py +0 -0
  136. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_update_statistics.py +0 -0
  137. {mainsequence-4.3.9 → mainsequence-4.3.16}/tests/test_update_uid_guards.py +0 -0
  138. {mainsequence-4.3.9 → mainsequence-4.3.16}/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.9
3
+ Version: 4.3.16
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
@@ -279,7 +282,7 @@ both the schema and the table's intention.
279
282
  Provider scope:
280
283
 
281
284
  ```python
282
- migration = AlembicMetaTableMigration(
285
+ migration = build_metatable_migration_provider(
283
286
  ...,
284
287
  metatable_models=[Account, Asset],
285
288
  )
@@ -304,9 +307,10 @@ asset_meta_table = MetaTable.register(asset_request)
304
307
 
305
308
  ### 4. Schema changes use Alembic
306
309
 
307
- When doing migration work, first read
308
- `docs/tutorial/metatable_migrations.md`. That document is the tutorial source
309
- 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.
310
314
 
311
315
  Do not apply in-place contract changes by changing a `PlatformManagedMetaTable`
312
316
  SQLAlchemy class and calling normal registration again. Shape-addressed
@@ -323,8 +327,10 @@ create a new Alembic revision on top of the current head.
323
327
  For contract evolution, define or update one selected
324
328
  `AlembicMetaTableMigration` provider:
325
329
 
326
- - put the provider in `mainsequence_migrations.py:migration` or pass
327
- `--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`
328
334
  - set `package`, `migration_namespace`, `script_location`, and `target_metadata`
329
335
  - set `alembic_registry` to an `AlembicVersionMetaTable` subclass
330
336
  - list the post-apply catalog scope in `metatable_models`
@@ -343,14 +349,14 @@ a bare table name. Use `schema_table_name(app, concept, suffix=None)` for the
343
349
  physical table and Alembic version table names. Use `suffix` for a namespace or
344
350
  variant, for example `schema_table_name("msm", "positions", suffix="broker")`.
345
351
 
346
- Do not ask users to construct backend migration payloads, call low-level
347
- migration request models, or use SDK helper functions directly. The backend
348
- 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:
349
355
 
350
356
  ```bash
351
- mainsequence migrations current --provider mainsequence_migrations:migration
352
- mainsequence migrations revision --provider mainsequence_migrations:migration
353
- 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
354
360
  ```
355
361
 
356
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)