mainsequence 8.1.20.dev3__tar.gz → 8.1.20.dev7__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 (142) hide show
  1. {mainsequence-8.1.20.dev3/mainsequence.egg-info → mainsequence-8.1.20.dev7}/PKG-INFO +1 -1
  2. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +10 -5
  3. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +13 -9
  4. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +9 -4
  5. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/base.py +14 -1
  6. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/metatables/core.py +48 -65
  7. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/models_foundry.py +0 -29
  8. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7/mainsequence.egg-info}/PKG-INFO +1 -1
  9. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence.egg-info/SOURCES.txt +1 -0
  10. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/pyproject.toml +1 -1
  11. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_canonical_api_route_contract.py +18 -1
  12. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_code_repository_branch_contract.py +6 -2
  13. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_code_repository_documentation_contract.py +53 -4
  14. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_code_repository_runtime_context.py +7 -3
  15. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_environment_response_contracts.py +5 -5
  16. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_filter_normalization.py +63 -32
  17. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_observability_client.py +6 -5
  18. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_source_table_configuration.py +14 -8
  19. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_time_index_table_update_configuration_client.py +6 -3
  20. mainsequence-8.1.20.dev7/tests/test_tolerant_response_reading.py +137 -0
  21. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_update_uid_guards.py +0 -1
  22. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/LICENSE +0 -0
  23. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/MANIFEST.in +0 -0
  24. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/README.md +0 -0
  25. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/AGENTS.md +0 -0
  26. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/a2a_sdk_execution/SKILL.md +0 -0
  27. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
  28. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
  29. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/data_publishing/time_index_table_updates/SKILL.md +0 -0
  30. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
  31. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/maintenance/code_repository_maintenance/SKILL.md +0 -0
  32. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
  33. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/agent_scaffold/skills/sdk_code_repository_execution/SKILL.md +0 -0
  34. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/__init__.py +0 -0
  35. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/__main__.py +0 -0
  36. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/bootstrap.py +0 -0
  37. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/__init__.py +0 -0
  38. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/api.py +0 -0
  39. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/browser_auth.py +0 -0
  40. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/cli.py +0 -0
  41. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/code_repository_status.py +0 -0
  42. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/config.py +0 -0
  43. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/docker_utils.py +0 -0
  44. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/doctor.py +0 -0
  45. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/local_ops.py +0 -0
  46. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/migrations.py +0 -0
  47. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/model_filters.py +0 -0
  48. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/pydantic_cli.py +0 -0
  49. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/sdk_utils.py +0 -0
  50. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/ssh_utils.py +0 -0
  51. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/cli/ui.py +0 -0
  52. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/__init__.py +0 -0
  53. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/agent_runtime_models.py +0 -0
  54. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/client.py +0 -0
  55. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/compute_validation.py +0 -0
  56. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
  57. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
  58. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
  59. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
  60. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/dtype_codec.py +0 -0
  61. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/exceptions.py +0 -0
  62. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/github_issues.py +0 -0
  63. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/metatables/__init__.py +0 -0
  64. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/models_helpers.py +0 -0
  65. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/models_user.py +0 -0
  66. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/observability.py +0 -0
  67. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/client/utils.py +0 -0
  68. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/code_repository_context.py +0 -0
  69. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/code_repository_skills.py +0 -0
  70. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/defaults.py +0 -0
  71. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/instrumentation/__init__.py +0 -0
  72. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/instrumentation/utils.py +0 -0
  73. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/logconf.py +0 -0
  74. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/__init__.py +0 -0
  75. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/__main__.py +0 -0
  76. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
  77. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
  78. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/future_registry.py +0 -0
  79. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/hashing.py +0 -0
  80. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/__init__.py +0 -0
  81. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/alembic.py +0 -0
  82. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/env.py +0 -0
  83. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/provider.py +0 -0
  84. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/registry.py +0 -0
  85. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/scaffold.py +0 -0
  86. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/templates/__init__.py +0 -0
  87. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/templates/env.py.mako +0 -0
  88. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/migrations/templates/script.py.mako +0 -0
  89. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
  90. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/schema_names.py +0 -0
  91. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
  92. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_refs.py +0 -0
  93. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_updates/__init__.py +0 -0
  94. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_updates/configuration.py +0 -0
  95. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_updates/dependencies.py +0 -0
  96. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_updates/managers.py +0 -0
  97. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_updates/namespacing.py +0 -0
  98. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_updates/runner.py +0 -0
  99. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_updates/updaters.py +0 -0
  100. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/meta_tables/time_index_table_updates/utils.py +0 -0
  101. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/repository_identity_security.py +0 -0
  102. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/runtime_flags.py +0 -0
  103. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence/scaffold_skills.py +0 -0
  104. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence.egg-info/dependency_links.txt +0 -0
  105. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence.egg-info/entry_points.txt +0 -0
  106. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence.egg-info/requires.txt +0 -0
  107. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/mainsequence.egg-info/top_level.txt +0 -0
  108. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/setup.cfg +0 -0
  109. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/fixtures/time_index_table_update_hash_v2_golden.json +0 -0
  110. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_auth_precedence.py +0 -0
  111. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_cli.py +0 -0
  112. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_cli_browser_auth.py +0 -0
  113. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_cli_migrations.py +0 -0
  114. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_client.py +0 -0
  115. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_code_repository_batch_jobs_from_file.py +0 -0
  116. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_code_repository_skills.py +0 -0
  117. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_dependency_extras.py +0 -0
  118. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_dev_release_version.py +0 -0
  119. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_duckdb_interface_dimensions.py +0 -0
  120. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_environment_resource_context.py +0 -0
  121. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_github_issues_client.py +0 -0
  122. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_instrumentation.py +0 -0
  123. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_local_ops.py +0 -0
  124. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_logconf.py +0 -0
  125. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_meta_table_migrations.py +0 -0
  126. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_meta_tables_client_models.py +0 -0
  127. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_meta_tables_sqlalchemy_contracts.py +0 -0
  128. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_models_user_request_bound_auth.py +0 -0
  129. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_notification_uid_contract.py +0 -0
  130. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_pod_project_resolution.py +0 -0
  131. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_scaffold_skills.py +0 -0
  132. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_schema_names.py +0 -0
  133. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_secret_client_model.py +0 -0
  134. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_sqlite_interface_dimensions.py +0 -0
  135. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_ssh_utils.py +0 -0
  136. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_time_index_table_access_dimension_audit.py +0 -0
  137. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_time_index_table_dimension_queries.py +0 -0
  138. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_time_index_table_update_configuration.py +0 -0
  139. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_time_index_table_update_flow.py +0 -0
  140. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_time_index_table_update_hard_cut.py +0 -0
  141. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_update_runner_uid_runtime.py +0 -0
  142. {mainsequence-8.1.20.dev3 → mainsequence-8.1.20.dev7}/tests/test_update_statistics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence
3
- Version: 8.1.20.dev3
3
+ Version: 8.1.20.dev7
4
4
  Summary: Main Sequence SDK
5
5
  Author-email: Main Sequence GmbH <dev@main-sequence.io>
6
6
  License-Expression: LicenseRef-MainSequence-Proprietary
@@ -17,11 +17,16 @@ platform-managed application tables outside the migration workflow.
17
17
 
18
18
  ## Read First
19
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`
20
+ 1. `docs/knowledge/meta_tables/migrations.md`
21
+ 2. `docs/knowledge/meta_tables/api.md`
22
+ 3. `docs/adr/0020-metatable-migration-artifact-registry.md`
23
+ 4. `docs/adr/0026-sdk-owned-migration-scaffolding.md`
24
+
25
+ `docs/knowledge/meta_tables/migrations.md` is the authoritative SDK reference for
26
+ provider behavior and migration contracts. The runnable beginner migration
27
+ walkthrough is maintained in the separate canonical tutorial CodeRepository at
28
+ <https://github.com/mainsequence-projects/mainsequence-sdk-tutorial>; read it
29
+ only when a runnable end-to-end example is needed.
25
30
 
26
31
  ## Required Decisions
27
32
 
@@ -49,15 +49,19 @@ If the user is still in the discovery process and does not yet know what data ex
49
49
 
50
50
  ## Read First
51
51
 
52
- 1. `docs/tutorial/working_with_meta_tables.md`
53
- 2. For migration work, use
52
+ 1. `docs/knowledge/meta_tables/index.md`
53
+ 2. `docs/knowledge/meta_tables/sqlalchemy.md`
54
+ 3. `docs/knowledge/meta_tables/compiled_sql.md`
55
+ 4. `docs/knowledge/meta_tables/migrations.md`
56
+ 5. `docs/knowledge/meta_tables/api.md`
57
+ 6. For migration work, use
54
58
  `.agents/skills/mainsequence/data_publishing/meta_table_migrations/SKILL.md`
55
- and `docs/tutorial/metatable_migrations.md`
56
- 3. `docs/knowledge/meta_tables/index.md`
57
- 4. `docs/knowledge/meta_tables/sqlalchemy.md`
58
- 5. `docs/knowledge/meta_tables/compiled_sql.md`
59
- 6. `docs/knowledge/meta_tables/migrations.md`
60
- 7. `docs/knowledge/meta_tables/api.md`
59
+
60
+ The knowledge pages above are the authoritative SDK reference for MetaTables.
61
+ The runnable beginner walkthrough is maintained in the separate canonical
62
+ tutorial CodeRepository at
63
+ <https://github.com/mainsequence-projects/mainsequence-sdk-tutorial>; read it
64
+ only when a runnable end-to-end example is needed.
61
65
 
62
66
  ## Inputs This Skill Needs
63
67
 
@@ -310,7 +314,7 @@ asset_meta_table = MetaTable.register(asset_request)
310
314
 
311
315
  When doing migration work, use
312
316
  `.agents/skills/mainsequence/data_publishing/meta_table_migrations/SKILL.md`
313
- and read `docs/tutorial/metatable_migrations.md`. The migration skill owns the
317
+ and read `docs/knowledge/meta_tables/migrations.md`. The migration skill owns the
314
318
  provider-based Alembic lifecycle.
315
319
 
316
320
  Do not apply in-place contract changes by changing a `PlatformManagedMetaTable`
@@ -61,11 +61,16 @@ This skill only reasons about access to deployed resources such as `ResourceRele
61
61
 
62
62
  ## Read First
63
63
 
64
- 1. `docs/tutorial/role_based_access_control.md`
65
- 2. `docs/knowledge/infrastructure/users_and_access.md`
66
- 3. `docs/knowledge/infrastructure/constants_and_secrets.md`
64
+ 1. `docs/knowledge/infrastructure/users_and_access.md`
65
+ 2. `docs/knowledge/infrastructure/constants_and_secrets.md`
67
66
 
68
- If the task is specifically about a resource type, also read the corresponding knowledge or tutorial page for that resource.
67
+ If the task is specifically about a resource type, also read the corresponding knowledge or CLI page for that resource.
68
+
69
+ The knowledge pages above are the authoritative SDK reference for access control
70
+ and sharing. The runnable beginner walkthrough is maintained in the separate
71
+ canonical tutorial CodeRepository at
72
+ <https://github.com/mainsequence-projects/mainsequence-sdk-tutorial>; read it
73
+ only when a runnable end-to-end example is needed.
69
74
 
70
75
  ## Inputs This Skill Needs
71
76
 
@@ -58,7 +58,9 @@ class HtmlSaveException(Exception):
58
58
 
59
59
 
60
60
  class BasePydanticModel(BaseModel):
61
- model_config = ConfigDict(extra="forbid") # Forbid extra fields in v2
61
+ # Tolerant reading (ADR 0032): a backend response that carries a field this
62
+ # SDK release does not declare parses, and the undeclared field is dropped.
63
+ model_config = ConfigDict(extra="ignore")
62
64
  orm_class: str = None # This will be set to the class that inherits
63
65
 
64
66
  @classmethod
@@ -780,10 +782,21 @@ class BaseObjectOrm:
780
782
 
781
783
  return raw_key
782
784
 
785
+ def _declares_field(obj, field_name: str) -> bool:
786
+ if not isinstance(obj, BaseModel):
787
+ return True
788
+ if field_name in type(obj).model_fields:
789
+ return True
790
+ # Tolerant reading (ADR 0032): a model that keeps undeclared keys can
791
+ # take them; every other model drops them, as parsing does.
792
+ return type(obj).model_config.get("extra") == "allow"
793
+
783
794
  def recursive_update(obj, update_dict, path=()):
784
795
  for k, v in update_dict.items():
785
796
  current_path = (*path, k)
786
797
  field_name = _resolve_model_field_name(obj, k)
798
+ if not _declares_field(obj, field_name):
799
+ continue
787
800
  # Get the existing nested object, defaulting to None if it doesn't exist
788
801
  nested_obj = getattr(obj, field_name, None)
789
802
 
@@ -1945,54 +1945,6 @@ class MetaTable(
1945
1945
  raise_for_response(response, payload=error_payload)
1946
1946
  return response.json()
1947
1947
 
1948
- @classmethod
1949
- def description_search(
1950
- cls,
1951
- q: str,
1952
- *,
1953
- q_embedding: Sequence[float] | None = None,
1954
- trigram_k: int = 200,
1955
- embed_k: int = 200,
1956
- w_trgm: float = 0.65,
1957
- w_emb: float = 0.35,
1958
- embedding_model: str = "default",
1959
- **filters,
1960
- ):
1961
- q = (q or "").strip()
1962
- if not q:
1963
- raise ValueError("q is required")
1964
- operation = f"{cls.__name__}.description_search"
1965
- cls._reject_sdk_context_overrides(filters, operation=operation)
1966
-
1967
- body = {
1968
- "q": q,
1969
- "trigram_k": trigram_k,
1970
- "embed_k": embed_k,
1971
- "w_trgm": w_trgm,
1972
- "w_emb": w_emb,
1973
- "embedding_model": embedding_model,
1974
- }
1975
-
1976
- if q_embedding is not None:
1977
- body["q_embedding"] = [float(x) for x in q_embedding]
1978
-
1979
- if filters:
1980
- body.update(filters)
1981
- body.update(cls._sdk_owned_query_context(operation))
1982
-
1983
- payload = {"params": serialize_to_json(body)}
1984
- response = make_request(
1985
- s=cls.build_session(),
1986
- loaders=cls.LOADERS,
1987
- r_type="GET",
1988
- url=f"{cls.get_object_url().rstrip('/')}/description-search/",
1989
- payload=payload,
1990
- )
1991
- if response.status_code != 200:
1992
- raise_for_response(response, payload=payload)
1993
-
1994
- return cls._deserialize_search_response(response.json())
1995
-
1996
1948
  @classmethod
1997
1949
  def column_search(cls, q: str, **filters):
1998
1950
  q = (q or "").strip()
@@ -2768,23 +2720,6 @@ class TimeIndexTableUpdate(TableUpdateNode, BaseObjectOrm):
2768
2720
  return None
2769
2721
  return r.json()
2770
2722
 
2771
- def verify_if_direct_dependencies_are_updated(self) -> dict:
2772
- """
2773
- Response({
2774
- "error_on_update_dependencies": False,
2775
- "updated": all_success,
2776
- })
2777
- """
2778
- s = self.build_session()
2779
- url = (
2780
- self.get_object_url()
2781
- + f"/{self._public_uid()}/verify-if-direct-dependencies-are-updated/"
2782
- )
2783
- r = make_request(s=s, loaders=None, r_type="GET", url=url)
2784
- if r.status_code != 200:
2785
- raise Exception(f"Error in request: {r.text}")
2786
- return r.json()
2787
-
2788
2723
  def get_data_between_dates_from_api(self, *args, **kwargs):
2789
2724
  return self.output_table.get_data_between_dates_from_api(*args, **kwargs)
2790
2725
 
@@ -3259,6 +3194,54 @@ class TimeIndexMetaTable(MetaTable):
3259
3194
  )
3260
3195
  return self
3261
3196
 
3197
+ @classmethod
3198
+ def description_search(
3199
+ cls,
3200
+ q: str,
3201
+ *,
3202
+ q_embedding: Sequence[float] | None = None,
3203
+ trigram_k: int = 200,
3204
+ embed_k: int = 200,
3205
+ w_trgm: float = 0.65,
3206
+ w_emb: float = 0.35,
3207
+ embedding_model: str = "default",
3208
+ **filters,
3209
+ ):
3210
+ q = (q or "").strip()
3211
+ if not q:
3212
+ raise ValueError("q is required")
3213
+ operation = f"{cls.__name__}.description_search"
3214
+ cls._reject_sdk_context_overrides(filters, operation=operation)
3215
+
3216
+ body = {
3217
+ "q": q,
3218
+ "trigram_k": trigram_k,
3219
+ "embed_k": embed_k,
3220
+ "w_trgm": w_trgm,
3221
+ "w_emb": w_emb,
3222
+ "embedding_model": embedding_model,
3223
+ }
3224
+
3225
+ if q_embedding is not None:
3226
+ body["q_embedding"] = [float(x) for x in q_embedding]
3227
+
3228
+ if filters:
3229
+ body.update(filters)
3230
+ body.update(cls._sdk_owned_query_context(operation))
3231
+
3232
+ payload = {"params": serialize_to_json(body)}
3233
+ response = make_request(
3234
+ s=cls.build_session(),
3235
+ loaders=cls.LOADERS,
3236
+ r_type="GET",
3237
+ url=f"{cls.get_object_url().rstrip('/')}/description-search/",
3238
+ payload=payload,
3239
+ )
3240
+ if response.status_code != 200:
3241
+ raise_for_response(response, payload=payload)
3242
+
3243
+ return cls._deserialize_search_response(response.json())
3244
+
3262
3245
  def _time_indexed_storage_layout(self) -> dict[str, Any]:
3263
3246
  profile = self.time_indexed_profile
3264
3247
  if profile is not None and isinstance(profile.storage_layout, Mapping):
@@ -697,13 +697,6 @@ class GitHubRepositoryBranchList(BasePydanticModel):
697
697
  results: list[GitHubRepositoryBranch]
698
698
 
699
699
 
700
- class GitHubRepositoryBranchImportResult(BasePydanticModel):
701
- repository_uid: str
702
- code_repository_branch_uid: str
703
- repository_branch: str
704
- is_initialized: bool
705
-
706
-
707
700
  class GitHubRepositoryBinding(BasePydanticModel, BaseObjectOrm):
708
701
  FILTERSET_FIELDS: ClassVar[dict[str, list[str]]] = {
709
702
  "uid": ["in", "exact"],
@@ -731,28 +724,6 @@ class GitHubRepositoryBinding(BasePydanticModel, BaseObjectOrm):
731
724
  raise_for_response(r)
732
725
  return GitHubRepositoryBranchList.model_validate(r.json())
733
726
 
734
- def import_branch(
735
- self,
736
- *,
737
- repository_branch: str,
738
- metatables_data_source_uid: str | None = None,
739
- timeout=None,
740
- ) -> GitHubRepositoryBranchImportResult:
741
- body: dict[str, Any] = {"repository_branch": repository_branch}
742
- if metatables_data_source_uid is not None:
743
- body["metatables_data_source_uid"] = str(metatables_data_source_uid)
744
- url = f"{type(self).get_object_url()}/{self._public_detail_reference()}/import-branch/"
745
- r = make_request(
746
- s=type(self).build_session(),
747
- loaders=type(self).LOADERS,
748
- r_type="POST",
749
- url=url,
750
- payload={"json": body},
751
- time_out=timeout,
752
- )
753
- raise_for_response(r)
754
- return GitHubRepositoryBranchImportResult.model_validate(r.json())
755
-
756
727
 
757
728
  class CodeRepositoryImageSourceProvenance(BasePydanticModel):
758
729
  verification_state: Literal["verified", "unverified", "building", "failed"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence
3
- Version: 8.1.20.dev3
3
+ Version: 8.1.20.dev7
4
4
  Summary: Main Sequence SDK
5
5
  Author-email: Main Sequence GmbH <dev@main-sequence.io>
6
6
  License-Expression: LicenseRef-MainSequence-Proprietary
@@ -133,6 +133,7 @@ tests/test_time_index_table_update_configuration.py
133
133
  tests/test_time_index_table_update_configuration_client.py
134
134
  tests/test_time_index_table_update_flow.py
135
135
  tests/test_time_index_table_update_hard_cut.py
136
+ tests/test_tolerant_response_reading.py
136
137
  tests/test_update_runner_uid_runtime.py
137
138
  tests/test_update_statistics.py
138
139
  tests/test_update_uid_guards.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mainsequence"
7
- version = "8.1.20.dev3"
7
+ version = "8.1.20.dev7"
8
8
  description = "Main Sequence SDK "
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -129,11 +129,18 @@ def test_client_auth_provider_routes_match_backend_contract(monkeypatch):
129
129
 
130
130
  def test_removed_backend_actions_are_not_exposed_by_client_models():
131
131
  from mainsequence.client.metatables import DataSource, TimeIndexTableUpdate
132
+ from mainsequence.client.models_foundry import GitHubRepositoryBinding
132
133
  from mainsequence.client.models_helpers import Job
133
134
 
134
135
  removed_actions = {
135
136
  DataSource: ("get_or_create_sqlite", "create_sqlite"),
136
- TimeIndexTableUpdate: ("add_tags", "filter_by_hash_id", "get_upstream_nodes"),
137
+ TimeIndexTableUpdate: (
138
+ "add_tags",
139
+ "filter_by_hash_id",
140
+ "get_upstream_nodes",
141
+ "verify_if_direct_dependencies_are_updated",
142
+ ),
143
+ GitHubRepositoryBinding: ("import_branch",),
137
144
  Job: ("bulk_get_or_create", "create_from_configuration", "sync_jobs"),
138
145
  }
139
146
  violations = [
@@ -146,6 +153,16 @@ def test_removed_backend_actions_are_not_exposed_by_client_models():
146
153
  assert violations == []
147
154
 
148
155
 
156
+ def test_description_search_is_defined_only_where_the_backend_serves_it():
157
+ """`description-search/` is served for time-index-meta-tables only."""
158
+ from mainsequence.client.metatables import MetaTable, TimeIndexMetaTable
159
+
160
+ assert "description_search" not in vars(MetaTable)
161
+ assert not hasattr(MetaTable, "description_search")
162
+ assert "description_search" in vars(TimeIndexMetaTable)
163
+ assert TimeIndexMetaTable.get_object_url().endswith("/time-index-meta-tables")
164
+
165
+
149
166
  def test_cli_does_not_reintroduce_legacy_numeric_detail_routes_or_agent_runs():
150
167
  from mainsequence.cli import api
151
168
  from mainsequence.client import agent_runtime_models
@@ -82,11 +82,15 @@ def test_code_repository_is_only_the_logical_aggregate_contract():
82
82
  assert not hasattr(code_repository.branches[0], "code_repository_type")
83
83
  assert not hasattr(code_repository, "repository_branch")
84
84
 
85
- with pytest.raises(ValidationError):
85
+ # Tolerant reading (ADR 0032): the retired field is dropped, not declared.
86
+ assert "repository_branch" not in models_foundry.CodeRepository.model_fields
87
+ assert not hasattr(
86
88
  models_foundry.CodeRepository(
87
89
  **logical_code_repository_payload(),
88
90
  repository_branch="main",
89
- )
91
+ ),
92
+ "repository_branch",
93
+ )
90
94
 
91
95
 
92
96
  def test_code_repository_requires_canonical_type_and_derived_technology():
@@ -23,6 +23,14 @@ STREAMLIT_REMOVAL_LINK_PATHS = {
23
23
  Path("docs/SUMMARY.md"),
24
24
  Path("docs/index.md"),
25
25
  }
26
+ SKILL_ROOT = REPOSITORY_ROOT / "agent_scaffold" / "skills"
27
+ # Skills ship inside the wheel but reference repository documentation by its
28
+ # repository-relative path, so every referenced path must exist in the tree that
29
+ # produced the release.
30
+ SKILL_DOCUMENTATION_REFERENCE = re.compile(r"`(docs/[A-Za-z0-9_./-]+\.md)`")
31
+ # Skills are copied into a CodeRepository under `.agents/skills/<namespace>/`, so
32
+ # a cross-skill reference maps back to a shipped `agent_scaffold/skills` path.
33
+ SKILL_CROSS_REFERENCE = re.compile(r"`\.agents/skills/[A-Za-z0-9_]+/([A-Za-z0-9_./-]+/SKILL\.md)`")
26
34
  RETIRED_PUBLIC_IDENTIFIERS = {
27
35
  "project_context": re.compile(r"(?<![A-Za-z0-9_])project_context(?![A-Za-z0-9_])"),
28
36
  "project-context": re.compile(r"(?<![A-Za-z0-9_])project-context(?![A-Za-z0-9_])"),
@@ -46,6 +54,10 @@ RETIRED_PUBLIC_IDENTIFIERS = {
46
54
  }
47
55
 
48
56
 
57
+ def _skill_files() -> tuple[Path, ...]:
58
+ return tuple(sorted(SKILL_ROOT.rglob("SKILL.md")))
59
+
60
+
49
61
  def _documentation_files() -> tuple[Path, ...]:
50
62
  files = {REPOSITORY_ROOT / "README.md", REPOSITORY_ROOT / "CHANGELOG.md"}
51
63
  for root in DOCUMENTATION_ROOTS:
@@ -74,10 +86,7 @@ def test_current_documentation_excludes_retired_project_identifiers(path: Path)
74
86
 
75
87
  def test_code_repository_context_adr_describes_the_current_cutover() -> None:
76
88
  adr = (
77
- REPOSITORY_ROOT
78
- / "docs"
79
- / "adr"
80
- / "0031-process-lifetime-code-repository-branch-context.md"
89
+ REPOSITORY_ROOT / "docs" / "adr" / "0031-process-lifetime-code-repository-branch-context.md"
81
90
  ).read_text(encoding="utf-8")
82
91
 
83
92
  assert "get_code_repository_context()" in adr
@@ -121,3 +130,43 @@ def test_current_documentation_does_not_advertise_streamlit_support(path: Path)
121
130
  assert "streamlit" not in text.lower()
122
131
  assert "create_dashboard" not in text
123
132
  assert "delete_dashboard" not in text
133
+
134
+
135
+ @pytest.mark.parametrize(
136
+ "path",
137
+ _skill_files(),
138
+ ids=lambda path: str(path.relative_to(REPOSITORY_ROOT)),
139
+ )
140
+ def test_skill_documentation_references_resolve(path: Path) -> None:
141
+ relative_path = path.relative_to(REPOSITORY_ROOT)
142
+ text = path.read_text(encoding="utf-8")
143
+
144
+ missing = sorted(
145
+ {
146
+ reference
147
+ for reference in SKILL_DOCUMENTATION_REFERENCE.findall(text)
148
+ if not (REPOSITORY_ROOT / reference).is_file()
149
+ }
150
+ )
151
+
152
+ assert not missing, f"{relative_path} references documentation that does not exist: {missing}"
153
+
154
+
155
+ @pytest.mark.parametrize(
156
+ "path",
157
+ _skill_files(),
158
+ ids=lambda path: str(path.relative_to(REPOSITORY_ROOT)),
159
+ )
160
+ def test_skill_cross_references_resolve(path: Path) -> None:
161
+ relative_path = path.relative_to(REPOSITORY_ROOT)
162
+ text = path.read_text(encoding="utf-8")
163
+
164
+ missing = sorted(
165
+ {
166
+ reference
167
+ for reference in SKILL_CROSS_REFERENCE.findall(text)
168
+ if not (SKILL_ROOT / reference).is_file()
169
+ }
170
+ )
171
+
172
+ assert not missing, f"{relative_path} references skills that are not shipped: {missing}"
@@ -722,7 +722,7 @@ def test_metatable_request_always_submits_git_resolved_context(monkeypatch):
722
722
  }
723
723
 
724
724
 
725
- def test_code_repository_model_rejects_removed_default_data_source_fields():
725
+ def test_code_repository_model_drops_removed_default_data_source_fields():
726
726
  payload = {
727
727
  "uid": CODE_REPOSITORY_UID,
728
728
  "code_repository_name": "Example CodeRepository",
@@ -737,5 +737,9 @@ def test_code_repository_model_rejects_removed_default_data_source_fields():
737
737
  "default_metatables_data_source_uid": DATA_SOURCE_UID,
738
738
  }
739
739
 
740
- with pytest.raises(ValueError, match="default_metatables_data_source_uid"):
741
- models_foundry.CodeRepository.model_validate(payload)
740
+ # Tolerant reading (ADR 0032): the retired field is dropped, not declared.
741
+ assert "default_metatables_data_source_uid" not in models_foundry.CodeRepository.model_fields
742
+ assert not hasattr(
743
+ models_foundry.CodeRepository.model_validate(payload),
744
+ "default_metatables_data_source_uid",
745
+ )
@@ -87,13 +87,13 @@ RUNTIME_UPDATE_FIELD = "runtime_update"
87
87
  ),
88
88
  ],
89
89
  )
90
- def test_backend_environment_response_contract_is_declared_by_strict_sdk_model(
90
+ def test_backend_environment_response_contract_is_declared_by_sdk_model(
91
91
  serializer_names,
92
92
  model,
93
93
  expected_fields,
94
94
  ):
95
95
  """Keep SDK response models aligned with ADR-0036/ADR-0037 projections."""
96
- assert model.model_config.get("extra") == "forbid", serializer_names
96
+ assert model.model_config.get("extra") == "ignore", serializer_names
97
97
  assert expected_fields <= set(model.model_fields), serializer_names
98
98
 
99
99
 
@@ -106,13 +106,13 @@ def test_backend_environment_response_contract_is_declared_by_strict_sdk_model(
106
106
  helper_models.ResourceRelease,
107
107
  ],
108
108
  )
109
- def test_owner_observability_code_repositoryion_is_declared_by_strict_sdk_model(model):
110
- assert model.model_config.get("extra") == "forbid"
109
+ def test_owner_observability_code_repositoryion_is_declared_by_sdk_model(model):
110
+ assert model.model_config.get("extra") == "ignore"
111
111
  assert "observability" in model.model_fields
112
112
 
113
113
 
114
114
  def test_agent_session_runtime_capabilities_code_repositoryion_is_declared_and_typed():
115
- assert agent_models.AgentSession.model_config.get("extra") == "forbid"
115
+ assert agent_models.AgentSession.model_config.get("extra") == "ignore"
116
116
  assert (
117
117
  agent_models.AgentSession.model_fields["runtime_capabilities"].annotation == dict[str, str]
118
118
  )