mainsequence-metatable 0.1.8.dev15__tar.gz → 0.1.8.dev17__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 (524) hide show
  1. {mainsequence_metatable-0.1.8.dev15/src/mainsequence_metatable.egg-info → mainsequence_metatable-0.1.8.dev17}/PKG-INFO +1 -1
  2. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0001-unified-api-storage-and-local-sqlite.md +10 -1
  3. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0007-database-enforced-table-access.md +15 -4
  4. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/api/data-sources.md +14 -2
  5. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/operations/catalog-migrations.md +1 -1
  6. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/pyproject.toml +1 -1
  7. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17/src/mainsequence_metatable.egg-info}/PKG-INFO +1 -1
  8. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/bootstrap.py +25 -0
  9. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/access.py +4 -0
  10. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/postgresql_access.py +88 -59
  11. mainsequence_metatable-0.1.8.dev17/tests/auth/test_data_source_identity.py +190 -0
  12. mainsequence_metatable-0.1.8.dev15/tests/auth/test_data_source_identity.py +0 -85
  13. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/.agents/skills/client/metatables-local-development/SKILL.md +0 -0
  14. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/.agents/skills/client/metatables-meta-tables/SKILL.md +0 -0
  15. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/.agents/skills/client/metatables-migrations/SKILL.md +0 -0
  16. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/.agents/skills/client/metatables-time-index-table-updates/SKILL.md +0 -0
  17. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/.agents/skills/client/metatables-upgrade-legacy-app/SKILL.md +0 -0
  18. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/.mainsequence/workflows/metatables-api.yaml +0 -0
  19. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/LICENSE +0 -0
  20. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/MANIFEST.in +0 -0
  21. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/README.md +0 -0
  22. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/alembic.ini +0 -0
  23. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/api/metatables/main.py +0 -0
  24. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/compose.database-tests.yml +0 -0
  25. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0002-application-administration-and-table-ownership.md +0 -0
  26. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0004-approved-application-migrations.md +0 -0
  27. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0005-run-logs-and-local-file-capture.md +0 -0
  28. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0006-historical-run-graphs.md +0 -0
  29. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0007-database-roles-and-privileges.svg +0 -0
  30. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0007-query-enforcement-path.svg +0 -0
  31. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0008-mysql-mssql-table-workflows.md +0 -0
  32. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0009-shared-credential-store.md +0 -0
  33. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0010-import-external-tables-and-views.md +0 -0
  34. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0012-bounded-data-transfer-and-safe-retries.md +0 -0
  35. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0013-application-owned-migrations.md +0 -0
  36. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/api/0014-main-sequence-release-jobs-and-production-migrations.md +0 -0
  37. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/client/0003-api-endpoint-resolution.md +0 -0
  38. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/client/0011-cli-local-development-with-managed-admin.md +0 -0
  39. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/adr/index.md +0 -0
  40. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/api/authentication-and-errors.md +0 -0
  41. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/api/openapi.json +0 -0
  42. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/api/overview.md +0 -0
  43. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/api/reference.md +0 -0
  44. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/api/tables-and-migrations.md +0 -0
  45. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/api/time-index-and-updates.md +0 -0
  46. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/assets/branding/metatables.svg +0 -0
  47. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/assets/diagrams/local-client-experience.svg +0 -0
  48. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/bounded-transfers.md +0 -0
  49. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/build-an-updater.md +0 -0
  50. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/define-and-migrate-tables.md +0 -0
  51. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/installation-and-connection.md +0 -0
  52. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/local-storage.md +0 -0
  53. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/query-and-mutate.md +0 -0
  54. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/quickstart.md +0 -0
  55. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/read-existing-time-index-tables.md +0 -0
  56. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/register-existing-tables.md +0 -0
  57. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/tutorial.md +0 -0
  58. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/client/upgrade-legacy-app.md +0 -0
  59. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/concepts/architecture.md +0 -0
  60. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/concepts/data-sources.md +0 -0
  61. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/concepts/identity-and-scope.md +0 -0
  62. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/concepts/permissions-namespaces-labels.md +0 -0
  63. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/concepts/runs-and-execution-graphs.md +0 -0
  64. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/concepts/table-contracts-and-lifecycle.md +0 -0
  65. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/concepts/time-index-tables-and-updates.md +0 -0
  66. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/contributing/architecture-and-boundaries.md +0 -0
  67. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/contributing/database-backends.md +0 -0
  68. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/contributing/documentation.md +0 -0
  69. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/contributing/releasing.md +0 -0
  70. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/contributing/testing.md +0 -0
  71. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/README.md +0 -0
  72. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/__init__.py +0 -0
  73. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/bounded_reader.py +0 -0
  74. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/data_sources/README.md +0 -0
  75. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/data_sources/mssql.json +0 -0
  76. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/data_sources/mysql.json +0 -0
  77. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/data_sources/postgresql.json +0 -0
  78. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/data_sources/register.py +0 -0
  79. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/external_table.py +0 -0
  80. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/local_app/README.md +0 -0
  81. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/local_app/__init__.py +0 -0
  82. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/local_app/__main__.py +0 -0
  83. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/local_app/migrations/__init__.py +0 -0
  84. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/local_app/migrations/env.py +0 -0
  85. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/local_app/migrations/script.py.mako +0 -0
  86. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/local_app/migrations/versions/metatables_local_example/0001.py +0 -0
  87. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/local_app/tables.py +0 -0
  88. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/query.py +0 -0
  89. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/quickstart.py +0 -0
  90. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/reader.py +0 -0
  91. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/scripts/__init__.py +0 -0
  92. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/scripts/setup_metatables.py +0 -0
  93. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tables.py +0 -0
  94. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/README.md +0 -0
  95. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/__init__.py +0 -0
  96. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/__main__.py +0 -0
  97. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/data/README.md +0 -0
  98. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/data/yahoo_spy_qqq_iwm_2026-06-15_2026-07-17.csv +0 -0
  99. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/frames.py +0 -0
  100. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/migrations/__init__.py +0 -0
  101. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/migrations/env.py +0 -0
  102. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/migrations/registry.py +0 -0
  103. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/migrations/script.py.mako +0 -0
  104. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/migrations/versions/__init__.py +0 -0
  105. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/0001_create_market_tutorial_tables.py +0 -0
  106. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/0002_create_rolling_volatility.py +0 -0
  107. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/__init__.py +0 -0
  108. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/operations.py +0 -0
  109. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/tables.py +0 -0
  110. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/tutorial/updaters.py +0 -0
  111. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/examples/updater.py +0 -0
  112. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/index.md +0 -0
  113. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/operations/configuration.md +0 -0
  114. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/operations/hosted-runtime.md +0 -0
  115. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/operations/local-runtime.md +0 -0
  116. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/operations/recovery-and-observability.md +0 -0
  117. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/operations/run-history.md +0 -0
  118. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/operations/run-logs.md +0 -0
  119. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/reference/capabilities.md +0 -0
  120. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/reference/cli.md +0 -0
  121. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/reference/python.md +0 -0
  122. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/security/index.md +0 -0
  123. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/security/ownership-and-sharing.md +0 -0
  124. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/docs/security/permissions.md +0 -0
  125. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/mkdocs.yml +0 -0
  126. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/__init__.py +0 -0
  127. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/build_reference.py +0 -0
  128. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/check_boundaries.py +0 -0
  129. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/check_client_api_coverage.py +0 -0
  130. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/check_distribution_sources.py +0 -0
  131. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/check_docs.py +0 -0
  132. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/check_examples_debug.py +0 -0
  133. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/check_project.py +0 -0
  134. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/dev_release_version.py +0 -0
  135. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/test_databases.py +0 -0
  136. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/scripts/test_postgresql.py +0 -0
  137. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/setup.cfg +0 -0
  138. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/mainsequence_metatable.egg-info/SOURCES.txt +0 -0
  139. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/mainsequence_metatable.egg-info/dependency_links.txt +0 -0
  140. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/mainsequence_metatable.egg-info/entry_points.txt +0 -0
  141. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/mainsequence_metatable.egg-info/requires.txt +0 -0
  142. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/mainsequence_metatable.egg-info/top_level.txt +0 -0
  143. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/__init__.py +0 -0
  144. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/_admin_source.json +0 -0
  145. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/_build.py +0 -0
  146. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/_skill_bundle.py +0 -0
  147. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/__init__.py +0 -0
  148. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/__init__.py +0 -0
  149. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/auth/__init__.py +0 -0
  150. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/auth/boundary.py +0 -0
  151. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/auth/caller_assertions.py +0 -0
  152. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/auth/local_actor.py +0 -0
  153. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/configuration.py +0 -0
  154. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/credential_admin.py +0 -0
  155. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/development.py +0 -0
  156. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/development_client.py +0 -0
  157. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/main.py +0 -0
  158. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/platform_cache.py +0 -0
  159. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/__init__.py +0 -0
  160. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/column_search.py +0 -0
  161. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/contract_validation.py +0 -0
  162. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/data_sources.py +0 -0
  163. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/managed_finalize.py +0 -0
  164. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/migration_connection.py +0 -0
  165. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/namespaces.py +0 -0
  166. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/run_logs.py +0 -0
  167. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/runtime_context.py +0 -0
  168. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/schema_graph.py +0 -0
  169. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/security.py +0 -0
  170. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_cascade.py +0 -0
  171. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_crud.py +0 -0
  172. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_delete.py +0 -0
  173. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_filter.py +0 -0
  174. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_import.py +0 -0
  175. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_introspection.py +0 -0
  176. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_patch.py +0 -0
  177. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_registration.py +0 -0
  178. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_response.py +0 -0
  179. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_search_document.py +0 -0
  180. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_sql.py +0 -0
  181. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/table_update_pipeline.py +0 -0
  182. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/time_index_delete.py +0 -0
  183. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/time_index_reads.py +0 -0
  184. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/time_index_stats.py +0 -0
  185. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_batch.py +0 -0
  186. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_chunk_insert.py +0 -0
  187. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_constants.py +0 -0
  188. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_crud.py +0 -0
  189. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_details.py +0 -0
  190. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_graph.py +0 -0
  191. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_index_statistics.py +0 -0
  192. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_registration.py +0 -0
  193. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_runs.py +0 -0
  194. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/routes/update_statistics.py +0 -0
  195. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/runtime.py +0 -0
  196. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/runtime_control.py +0 -0
  197. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/source_passwords.py +0 -0
  198. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/source_registrations.py +0 -0
  199. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/app/transfer.py +0 -0
  200. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/__init__.py +0 -0
  201. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/__init__.py +0 -0
  202. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/__init__.py +0 -0
  203. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/maintenance/__init__.py +0 -0
  204. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/maintenance/postgresql.py +0 -0
  205. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/maintenance/runtime.py +0 -0
  206. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/maintenance/temporal.py +0 -0
  207. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/maintenance/timescaledb.py +0 -0
  208. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/maintenance/validation.py +0 -0
  209. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_cascade_delete.py +0 -0
  210. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_connection.py +0 -0
  211. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_introspection.py +0 -0
  212. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_table_delete.py +0 -0
  213. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_tables.py +0 -0
  214. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_time_index.py +0 -0
  215. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_time_index_delete.py +0 -0
  216. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_time_index_queries.py +0 -0
  217. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_time_index_stats.py +0 -0
  218. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/postgresql_time_index_write.py +0 -0
  219. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/source_validation.py +0 -0
  220. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/sqlite_connection.py +0 -0
  221. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/sqlite_introspection.py +0 -0
  222. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/adapters/table_cursor.py +0 -0
  223. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/catalog.py +0 -0
  224. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/catalog_ddl.py +0 -0
  225. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/catalog_types.py +0 -0
  226. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/contracts.py +0 -0
  227. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/hosted.py +0 -0
  228. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/hosted_access.py +0 -0
  229. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/migration_connection.py +0 -0
  230. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/native.py +0 -0
  231. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/operations.py +0 -0
  232. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/pages.py +0 -0
  233. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/registry.py +0 -0
  234. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/relation_tables.py +0 -0
  235. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/relational.py +0 -0
  236. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/restricted_sql.py +0 -0
  237. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/sqlite_access.py +0 -0
  238. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/backends/streaming.py +0 -0
  239. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/contracts/__init__.py +0 -0
  240. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/contracts/relation_import.py +0 -0
  241. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/contracts/storage_layouts.py +0 -0
  242. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/contracts/table_contracts.py +0 -0
  243. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/contracts/values.py +0 -0
  244. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/domain/__init__.py +0 -0
  245. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/domain/catalog_rules.py +0 -0
  246. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/domain/data_source_rules.py +0 -0
  247. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/domain/index_statistics.py +0 -0
  248. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/domain/label_rules.py +0 -0
  249. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/domain/permission_rules.py +0 -0
  250. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/domain/update_constants.py +0 -0
  251. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/__init__.py +0 -0
  252. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/catalog_data_sources.py +0 -0
  253. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/credential_keys.py +0 -0
  254. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/credential_store.py +0 -0
  255. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/data_source_provider.py +0 -0
  256. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/local_credentials.py +0 -0
  257. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/local_workspace.py +0 -0
  258. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/platform_principals.py +0 -0
  259. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/run_logs.py +0 -0
  260. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/runtime_binding.py +0 -0
  261. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/runtime_data_sources.py +0 -0
  262. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/integrations/source_validation.py +0 -0
  263. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/__init__.py +0 -0
  264. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/env.py +0 -0
  265. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/script.py.mako +0 -0
  266. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/0001_initial.py +0 -0
  267. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/0002_security_model.py +0 -0
  268. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/0003_run_log_capture.py +0 -0
  269. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/0004_historical_run_graphs.py +0 -0
  270. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/0005_database_access.py +0 -0
  271. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/0006_local_credentials.py +0 -0
  272. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/0007_external_relation_names.py +0 -0
  273. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/0008_upload_receipts.py +0 -0
  274. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/migrations/versions/__init__.py +0 -0
  275. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/__init__.py +0 -0
  276. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/bootstrap_migrations.py +0 -0
  277. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/catalog_schema.py +0 -0
  278. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/create_table.py +0 -0
  279. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/finalize_managed.py +0 -0
  280. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/import_relations.py +0 -0
  281. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/introspect_table.py +0 -0
  282. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/read_time_index.py +0 -0
  283. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/register_catalog.py +0 -0
  284. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/operations/search_documents.py +0 -0
  285. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/__init__.py +0 -0
  286. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/cascade.py +0 -0
  287. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/catalog.py +0 -0
  288. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/database.py +0 -0
  289. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/grants.py +0 -0
  290. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/labels.py +0 -0
  291. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/locking.py +0 -0
  292. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/models.py +0 -0
  293. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/physical_operations.py +0 -0
  294. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/projections.py +0 -0
  295. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/run_graphs.py +0 -0
  296. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/schema_graph.py +0 -0
  297. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/sqlite_types.py +0 -0
  298. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/table_body_filter.py +0 -0
  299. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/table_queries.py +0 -0
  300. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/table_response.py +0 -0
  301. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/update_graph.py +0 -0
  302. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/update_pipeline.py +0 -0
  303. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/updates.py +0 -0
  304. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/persistence/upload_receipts.py +0 -0
  305. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/backend/presentation/data_source_summary.py +0 -0
  306. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/metatables/__init__.py +0 -0
  307. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/metatables/configuration.yaml +0 -0
  308. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/api/metatables/main.py +0 -0
  309. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/cli/__init__.py +0 -0
  310. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/cli/admin_install.py +0 -0
  311. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/cli/app.py +0 -0
  312. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/cli/filters.py +0 -0
  313. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/cli/local.py +0 -0
  314. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/cli/migrations.py +0 -0
  315. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/cli/project.py +0 -0
  316. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/cli/skills.py +0 -0
  317. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/compiled_sql/__init__.py +0 -0
  318. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/compiled_sql/mssql.py +0 -0
  319. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/compiled_sql/v1.py +0 -0
  320. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/dtype_codec.py +0 -0
  321. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/endpoint.py +0 -0
  322. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/README.md +0 -0
  323. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/__init__.py +0 -0
  324. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/bounded_reader.py +0 -0
  325. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/data_sources/README.md +0 -0
  326. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/data_sources/mssql.json +0 -0
  327. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/data_sources/mysql.json +0 -0
  328. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/data_sources/postgresql.json +0 -0
  329. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/data_sources/register.py +0 -0
  330. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/external_table.py +0 -0
  331. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/local_app/README.md +0 -0
  332. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/local_app/__init__.py +0 -0
  333. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/local_app/__main__.py +0 -0
  334. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/local_app/migrations/__init__.py +0 -0
  335. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/local_app/migrations/env.py +0 -0
  336. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/local_app/migrations/script.py.mako +0 -0
  337. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/local_app/migrations/versions/metatables_local_example/0001.py +0 -0
  338. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/local_app/tables.py +0 -0
  339. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/query.py +0 -0
  340. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/quickstart.py +0 -0
  341. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/reader.py +0 -0
  342. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/scripts/__init__.py +0 -0
  343. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/scripts/setup_metatables.py +0 -0
  344. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tables.py +0 -0
  345. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/README.md +0 -0
  346. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/__init__.py +0 -0
  347. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/__main__.py +0 -0
  348. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/data/README.md +0 -0
  349. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/data/yahoo_spy_qqq_iwm_2026-06-15_2026-07-17.csv +0 -0
  350. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/frames.py +0 -0
  351. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/migrations/__init__.py +0 -0
  352. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/migrations/env.py +0 -0
  353. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/migrations/registry.py +0 -0
  354. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/migrations/script.py.mako +0 -0
  355. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/migrations/versions/__init__.py +0 -0
  356. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/0001_create_market_tutorial_tables.py +0 -0
  357. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/0002_create_rolling_volatility.py +0 -0
  358. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/__init__.py +0 -0
  359. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/operations.py +0 -0
  360. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/tables.py +0 -0
  361. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/tutorial/updaters.py +0 -0
  362. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/examples/updater.py +0 -0
  363. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/future_registry.py +0 -0
  364. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/hashing.py +0 -0
  365. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/instrumentation.py +0 -0
  366. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/local_connection.py +0 -0
  367. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/local_files.py +0 -0
  368. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/local_run_logs.py +0 -0
  369. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/log_contract.py +0 -0
  370. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/__init__.py +0 -0
  371. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/alembic.py +0 -0
  372. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/connection.py +0 -0
  373. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/env.py +0 -0
  374. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/provider.py +0 -0
  375. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/registry.py +0 -0
  376. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/runner.py +0 -0
  377. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/scaffold.py +0 -0
  378. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/templates/__init__.py +0 -0
  379. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/templates/env.py.mako +0 -0
  380. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/templates/script.py.mako +0 -0
  381. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/migrations/tls.py +0 -0
  382. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/models.py +0 -0
  383. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/pydantic_metadata.py +0 -0
  384. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/run_logging.py +0 -0
  385. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/runtime.py +0 -0
  386. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/runtime_context.py +0 -0
  387. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/runtime_contract.py +0 -0
  388. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/schema_names.py +0 -0
  389. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/sdk_compat.py +0 -0
  390. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/sqlalchemy_contracts.py +0 -0
  391. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/time_index_table_refs.py +0 -0
  392. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/transfer.py +0 -0
  393. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/transfer_contract.py +0 -0
  394. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/transport.py +0 -0
  395. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/update_configuration_contract.py +0 -0
  396. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/updaters/__init__.py +0 -0
  397. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/updaters/configuration.py +0 -0
  398. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/updaters/dependencies.py +0 -0
  399. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/updaters/managers.py +0 -0
  400. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/updaters/namespacing.py +0 -0
  401. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/updaters/runner.py +0 -0
  402. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/updaters/updaters.py +0 -0
  403. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/updaters/utils.py +0 -0
  404. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/src/metatables/upload.py +0 -0
  405. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_caller_assertions.py +0 -0
  406. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_development_client.py +0 -0
  407. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_hosted_environment_target.py +0 -0
  408. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_local_mode.py +0 -0
  409. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_platform_fact_cache.py +0 -0
  410. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_runtime_bootstrap.py +0 -0
  411. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_runtime_scaffold.py +0 -0
  412. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_runtime_selection.py +0 -0
  413. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_runtime_storage_binding.py +0 -0
  414. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/auth/test_source_passwords.py +0 -0
  415. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/catalog/test_catalog_foundation.py +0 -0
  416. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/catalog/test_contract_projection.py +0 -0
  417. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/catalog/test_database_config.py +0 -0
  418. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/catalog/test_index_statistics.py +0 -0
  419. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/catalog/test_migration.py +0 -0
  420. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/conftest.py +0 -0
  421. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/capabilities.json +0 -0
  422. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/client_signatures.json +0 -0
  423. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/database_operations.json +0 -0
  424. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/test_bounded_transfer.py +0 -0
  425. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/test_compiler_runtime_source.py +0 -0
  426. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/test_relation_batching.py +0 -0
  427. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/test_relation_import.py +0 -0
  428. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/test_storage_layouts.py +0 -0
  429. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/contracts/test_table_contracts.py +0 -0
  430. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/Dockerfile +0 -0
  431. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/Dockerfile.dockerignore +0 -0
  432. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/__init__.py +0 -0
  433. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/conftest.py +0 -0
  434. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/provider/__init__.py +0 -0
  435. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/provider/env.py +0 -0
  436. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/provider/versions/0001_measurement.py +0 -0
  437. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_api_contract.py +0 -0
  438. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_application_migration.py +0 -0
  439. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_bootstrap_recovery.py +0 -0
  440. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_catalog_contract.py +0 -0
  441. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_credential_catalog.py +0 -0
  442. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_physical_contract.py +0 -0
  443. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_relation_import.py +0 -0
  444. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_runtime_bootstrap.py +0 -0
  445. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_sql_security.py +0 -0
  446. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_backend/test_update_client.py +0 -0
  447. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_operations/test_physical_operations.py +0 -0
  448. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_operations/test_postgresql_operations.py +0 -0
  449. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/database_operations/test_runtime_and_temporal.py +0 -0
  450. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/documentation/test_project_checks.py +0 -0
  451. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_admin_installation.py +0 -0
  452. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_api_endpoint.py +0 -0
  453. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_application_owned_migrations.py +0 -0
  454. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_catalog_outage.py +0 -0
  455. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_client_api_contract.py +0 -0
  456. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_client_api_coverage.py +0 -0
  457. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_client_migration_scaffold.py +0 -0
  458. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_client_migration_tls.py +0 -0
  459. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_client_package.py +0 -0
  460. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_client_signatures.py +0 -0
  461. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_client_value_behaviors.py +0 -0
  462. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_data_source_registry.py +0 -0
  463. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_local_actor_client_api.py +0 -0
  464. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_local_cli_workflow.py +0 -0
  465. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_local_client_selection.py +0 -0
  466. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_managed_finalize_client_api.py +0 -0
  467. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_namespaces_admin_http.py +0 -0
  468. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_public_imports.py +0 -0
  469. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_remaining_client_routes.py +0 -0
  470. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_run_graphs.py +0 -0
  471. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_run_logs.py +0 -0
  472. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_runtime_transition.py +0 -0
  473. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_runtime_upgrade.py +0 -0
  474. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_sdk_local_startup.py +0 -0
  475. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_sqlite_runtime.py +0 -0
  476. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_table_delete_client_api.py +0 -0
  477. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_table_filter_client_api.py +0 -0
  478. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_table_introspection_client_api.py +0 -0
  479. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_table_patch_client_api.py +0 -0
  480. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_table_search_document_api.py +0 -0
  481. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_table_stats_api.py +0 -0
  482. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_table_update_pipeline.py +0 -0
  483. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_table_updates_http.py +0 -0
  484. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_time_index_delete_client_api.py +0 -0
  485. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_time_index_reads_client_api.py +0 -0
  486. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_update_batch_client_api.py +0 -0
  487. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_update_chunk_insert_client_api.py +0 -0
  488. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_update_dependency_priority_client_api.py +0 -0
  489. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_update_index_statistics_client_api.py +0 -0
  490. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/e2e/test_update_registration_client_api.py +0 -0
  491. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/examples/test_documented_examples.py +0 -0
  492. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/examples/test_postgresql_examples.py +0 -0
  493. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/examples/test_setup_launch.py +0 -0
  494. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/examples/test_tutorial.py +0 -0
  495. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_credential_store.py +0 -0
  496. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_data_source_rules.py +0 -0
  497. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_local_data_sources.py +0 -0
  498. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_local_run_logs.py +0 -0
  499. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_postgresql_connection.py +0 -0
  500. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_postgresql_sql.py +0 -0
  501. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_postgresql_tables.py +0 -0
  502. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_postgresql_time_index_queries.py +0 -0
  503. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_source_validation.py +0 -0
  504. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/integrations/test_sqlite_operations.py +0 -0
  505. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/labels/test_labels.py +0 -0
  506. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/operations/test_create_table_operation.py +0 -0
  507. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/operations/test_create_table_postgres.py +0 -0
  508. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/operations/test_physical_operation_journal.py +0 -0
  509. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/operations/test_register_catalog.py +0 -0
  510. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/operations/test_search_documents.py +0 -0
  511. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/packaging/test_client_skills.py +0 -0
  512. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/packaging/test_dev_release_version.py +0 -0
  513. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/packaging/test_distribution_sources.py +0 -0
  514. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/packaging/test_editable_build.py +0 -0
  515. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/packaging/test_installed_distribution.py +0 -0
  516. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/permissions/test_governed_sql_scope.py +0 -0
  517. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/permissions/test_local_actor_membership.py +0 -0
  518. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/permissions/test_migration_boundary.py +0 -0
  519. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/permissions/test_namespace_grants.py +0 -0
  520. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/permissions/test_security_api.py +0 -0
  521. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/permissions/test_table_body_filter.py +0 -0
  522. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/permissions/test_table_grants.py +0 -0
  523. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/tests/permissions/test_table_queries.py +0 -0
  524. {mainsequence_metatable-0.1.8.dev15 → mainsequence_metatable-0.1.8.dev17}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence-metatable
3
- Version: 0.1.8.dev15
3
+ Version: 0.1.8.dev17
4
4
  Summary: Main Sequence MetaTables Python client and standalone API
5
5
  Author-email: Main Sequence GmbH <dev@main-sequence.io>
6
6
  License-Expression: MIT
@@ -28,7 +28,8 @@ does not cache this API's runtime context or select its runtime mode or DataSour
28
28
  Updated 2026-09-28: application Environment policy and relationships are removed.
29
29
  Amended 2026-09-29: one enforced runtime binding and explicit bootstrap select one
30
30
  database for system and user tables.
31
- Amended 2026-10-02: each runtime mode lists and selects only its own DataSources.
31
+ Amended 2026-10-02: each runtime mode lists and selects only its own DataSources,
32
+ and inspection checks the login's prerequisites before setup.
32
33
 
33
34
  Companion decision: [Main Sequence SDK ADR 0035: Independent Git source and platform execution context](https://github.com/mainsequence-sdk/mainsequence-sdk/blob/metatables_removal/docs/adr/0035-independent-git-source-and-platform-context.md).
34
35
  The SDK prerequisite is implemented on `metatables_removal`; the current local
@@ -172,6 +173,14 @@ configuration inserted as the runtime DataSource in that database. Failed work
172
173
  never activates a partially initialized runtime. A database already initialized
173
174
  and compatible can be selected without running migrations.
174
175
 
176
+ Amended 2026-10-02: before any runtime is registered, inspection also checks,
177
+ read-only, the login's prerequisites under
178
+ [ADR 0007](0007-database-enforced-table-access.md): `CREATEROLE`, and permission to
179
+ create the `metatables` schema and tables in the default schema. Unmet
180
+ prerequisites make the target incompatible, with each reason shown in Settings,
181
+ so setup never leaves a database half-initialized. A registered runtime is not
182
+ rechecked.
183
+
175
184
  Settings, runtime context, mode selection and bootstrap actions do not depend on
176
185
  catalog sessions or catalog memberships. They retain the existing request admission.
177
186
  The caller who configures a pending target controls its initialization; an existing
@@ -6,6 +6,14 @@
6
6
  > conflicting application-migration execution and credential restrictions;
7
7
  > governed API operations and MetaTables system migrations remain separate.
8
8
 
9
+ > Amendment (2026-10-02): MetaTables secures only what it owns: its `metatables`
10
+ > schema, the tables it manages and the roles it creates. Database-wide defaults
11
+ > and `PUBLIC` access to other owners' objects, including extensions and other
12
+ > applications sharing the database, are the database administrator's
13
+ > responsibility. The login needs `CREATEROLE` and permission to create the
14
+ > `metatables` schema and tables in the DataSource's default schema; it need not
15
+ > own the database.
16
+
9
17
 
10
18
  Date: 2026-09-29
11
19
 
@@ -160,12 +168,14 @@ client.
160
168
  - **Ownership.** Tables are owned by `mt_owner`, a role that cannot log in, because
161
169
  an owner holds every privilege. The API's own role manages grants and schema
162
170
  changes and never runs caller SQL.
163
- - **Defaults.** PostgreSQL's default `PUBLIC` privileges are revoked: connecting,
164
- creating objects and temporary tables, and executing new functions.
171
+ - **Defaults.** On objects MetaTables owns, PostgreSQL's default `PUBLIC`
172
+ privileges are revoked, including for future tables and routines. Database-wide
173
+ defaults (connecting, creating objects and temporary tables) and other owners'
174
+ objects belong to the database administrator.
165
175
  - **Privileged routines.** Restricted caller roles must not be able to execute
166
176
  application routines with elevated owner privileges, including
167
177
  `SECURITY DEFINER` routines. Initialization establishes this restriction for
168
- existing routines as well as future defaults, covering direct grants, inherited
178
+ the routines MetaTables owns, existing and future, covering direct grants, inherited
169
179
  roles and `PUBLIC`. Revoking a direct User grant alone is insufficient if
170
180
  another grant still permits execution. Schema changes and extension installation
171
181
  preserve the restriction before exposing new or changed routines to callers.
@@ -261,7 +271,8 @@ and [MySQL implicit commits](https://dev.mysql.com/doc/refman/8.4/en/implicit-co
261
271
 
262
272
  - The explorer can run any PostgreSQL query, and the API has no SQL parser left
263
273
  to get wrong.
264
- - The DataSource login needs `CREATEROLE`.
274
+ - The DataSource login needs `CREATEROLE` and the right to create the `metatables`
275
+ schema; it does not need to own the database.
265
276
  - Physical table names become visible to explorer users.
266
277
  - Cascading foreign keys are unavailable where the explorer is enabled.
267
278
  - Team membership reaches the database at the pace of the existing one-hour
@@ -173,14 +173,26 @@ uses the selected database as its SQL schema. SQL Server 2022 uses `dbo` for the
173
173
  system schema; application providers may use approved schemas in that database.
174
174
 
175
175
  The API database login manages native caller identities as well as schema. PostgreSQL
176
- requires `CREATEROLE`, ownership of the runtime database and management rights on
177
- `mt_owner` if it already exists. It stores the catalog in the private `metatables`
176
+ requires `CREATEROLE`, permission to create the `metatables` schema in the runtime
177
+ database and tables in its default schema, and management rights on `mt_owner` if
178
+ it already exists. It does not need to own the database. It stores the catalog in the private `metatables`
178
179
  schema. MySQL requires account/role administration, privilege disclosure and grant
179
180
  rights on the selected database, `TRIGGER` visibility, and permission to cancel
180
181
  other caller sessions. SQL Server requires login/user/role administration,
181
182
  `VIEW DEFINITION` and grant management. Managed database services must provide
182
183
  these capabilities; missing permissions leave caller SQL disabled.
183
184
 
185
+ Settings checks these PostgreSQL requirements as soon as you select a database
186
+ without a MetaTables runtime, before any migration runs. A missing one shows
187
+ **Needs attention** with the reason, for example `metatables_dev lacks CREATEROLE`;
188
+ **Run MetaTables migrations** stays unavailable and nothing is written.
189
+
190
+ The database may be shared with other applications. Setup revokes `PUBLIC` access
191
+ only on objects MetaTables owns: its `metatables` schema, the tables it manages and
192
+ the roles it creates. Database-wide defaults and other owners' objects, including
193
+ extensions such as TimescaleDB and pgvector, are the database administrator's
194
+ responsibility.
195
+
184
196
  Hosted sources require a password Secret to derive per-User database credentials.
185
197
  MySQL global mandatory roles are unsupported. Registration admits ordinary tables
186
198
  only; it does not transfer external ownership. Privileged routines and triggers
@@ -10,7 +10,7 @@ system tables, including `data_source`, alongside user tables. There is no separ
10
10
  catalog connection to configure. Local and hosted use the same initialization flow.
11
11
 
12
12
  1. For Hosted mode, register a PostgreSQL, TimescaleDB, MySQL or MSSQL connection under **MetaTables → Data Sources**. This registration is available before the hosted catalog is initialized.
13
- 2. Open **Settings**, choose Hosted runtime mode, and select that registered DataSource from the list. Local mode prefills the single local SQLite runtime file, shared across Git branches, and uses **Check DataSource**. Choosing a hosted DataSource and switching modes are separate actions.
13
+ 2. Open **Settings**, choose Hosted runtime mode, and select that registered DataSource from the list. Local mode prefills the single local SQLite runtime file, shared across Git branches, and uses **Check DataSource**. Choosing a hosted DataSource and switching modes are separate actions. For a database without a MetaTables runtime, selection also checks that the login can secure it; **Needs attention** lists what is missing ([database privileges](../api/data-sources.md#database-privileges-and-sql-behavior)) and no migration can run until another database is selected.
14
14
  3. For an empty or outdated database, click **Run MetaTables migrations**. This
15
15
  explicitly runs the packaged Alembic history. After success, the API saves the
16
16
  proposal as the runtime DataSource inside the newly initialized registry.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mainsequence-metatable"
7
- version = "0.1.8.dev15"
7
+ version = "0.1.8.dev17"
8
8
  description = "Main Sequence MetaTables Python client and standalone API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mainsequence-metatable
3
- Version: 0.1.8.dev15
3
+ Version: 0.1.8.dev17
4
4
  Summary: Main Sequence MetaTables Python client and standalone API
5
5
  Author-email: Main Sequence GmbH <dev@main-sequence.io>
6
6
  License-Expression: MIT
@@ -58,6 +58,14 @@ class BootstrapError(RuntimeError):
58
58
  pass
59
59
 
60
60
 
61
+ def insufficient_privilege(exc):
62
+ """The database's own message for a missing privilege, never SQL text or parameters."""
63
+ orig = getattr(exc, "orig", None)
64
+ code = getattr(orig, "pgcode", None) or getattr(orig, "sqlstate", None)
65
+ message = getattr(getattr(orig, "diag", None), "message_primary", None)
66
+ return message if code == "42501" and message else None
67
+
68
+
61
69
  class DestroyLocalInput(BaseModel):
62
70
  model_config = ConfigDict(extra="forbid")
63
71
  path: str
@@ -254,6 +262,8 @@ class RuntimeBootstrap:
254
262
  return
255
263
  if set(self.current) != set(self.expected):
256
264
  self.status = "migration_required"
265
+ if not self.current:
266
+ self.require_prerequisites(connection)
257
267
  return
258
268
  from metatables.api.backend.operations.catalog_schema import validate_system_schema
259
269
  validate_system_schema(connection, self.backend.catalog)
@@ -261,6 +271,8 @@ class RuntimeBootstrap:
261
271
  row = session.scalar(select(DataSource).where(DataSource.is_runtime.__eq__(True)))
262
272
  if row is None:
263
273
  self.status = "registration_required"
274
+ with engine.connect() as connection:
275
+ self.require_prerequisites(connection)
264
276
  elif not self.matches(row):
265
277
  self.status = "incompatible"
266
278
  self.error = "The stored runtime DataSource does not match this connection."
@@ -286,6 +298,15 @@ class RuntimeBootstrap:
286
298
  self.status = "unavailable"
287
299
  self.error = "Cannot verify the selected database or its Alembic history. Check configuration, Secret access and the API's migration version."
288
300
 
301
+ def require_prerequisites(self, connection):
302
+ # Before any setup DDL: a database the login cannot secure must never be
303
+ # half-initialized. A registered runtime may hold external objects.
304
+ problems = self.backend.access.prerequisite_problems(connection)
305
+ if problems:
306
+ self.status = "incompatible"
307
+ self.error = ("MetaTables cannot secure this database: " + "; ".join(problems) + ". Select a database "
308
+ "owned by the DataSource login, as described in DataSource database privileges.")
309
+
289
310
  def matches(self, row):
290
311
  return (row.class_type == self.candidate["class_type"]
291
312
  and row.configuration == self.candidate["configuration"]
@@ -347,6 +368,10 @@ class RuntimeBootstrap:
347
368
  if isinstance(exc, SQLExecutionError):
348
369
  self.error = f"Database access setup failed ({exc.code}). Check the DataSource password Secret and database permissions, then retry setup."
349
370
  raise BootstrapError(self.error) from None
371
+ if privilege_error := insufficient_privilege(exc):
372
+ self.error = (f"Database setup failed: {privilege_error}. The DataSource login must own the runtime "
373
+ "database and every object in it; see the DataSource database privileges.")
374
+ raise BootstrapError(self.error) from None
350
375
  self.error = "MetaTables migration or registration failed. The runtime was not activated; inspect the database before retrying."
351
376
  raise BootstrapError(self.error) from None
352
377
 
@@ -60,6 +60,10 @@ class DatabaseAccess:
60
60
  ).hexdigest()
61
61
  )
62
62
 
63
+ def prerequisite_problems(self, connection):
64
+ """Read-only reasons this login cannot secure the database; checked before setup."""
65
+ return []
66
+
63
67
  def initialize(self, session):
64
68
  raise NotImplementedError
65
69
 
@@ -13,18 +13,47 @@ def quote(value):
13
13
  return '"' + str(value).replace('"', '""') + '"'
14
14
 
15
15
 
16
+ # MetaTables secures only objects this login owns, directly or through
17
+ # membership (mt_owner). PUBLIC access to anything else in the database is its
18
+ # administrator's responsibility (ADR 0007, amended 2026-10-02).
19
+ OWNED = "pg_has_role(current_user, {owner}, 'MEMBER')"
20
+ USER_SCHEMA = "{schema} !~ '^pg_' AND {schema} <> 'information_schema'"
21
+
22
+
16
23
  class PostgreSQLAccess(DatabaseAccess):
24
+ def prerequisite_problems(self, connection):
25
+ schema = getattr(self.source.connection, "default_schema", None) or "public"
26
+ login, database, creates_roles, creates_schemas, catalog_owner, tables = connection.execute(text(
27
+ "SELECT current_user, current_database(), r.rolcreaterole OR r.rolsuper, "
28
+ "has_database_privilege(current_database(), 'CREATE'), "
29
+ "(SELECT pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = 'metatables' "
30
+ "AND NOT pg_has_role(current_user, nspowner, 'MEMBER')), "
31
+ "(SELECT has_schema_privilege(oid, 'USAGE') AND has_schema_privilege(oid, 'CREATE') "
32
+ "FROM pg_namespace WHERE nspname = :schema) "
33
+ "FROM pg_roles r WHERE r.rolname = current_user"
34
+ ), {"schema": schema}).one()
35
+ problems = []
36
+ if not creates_roles:
37
+ problems.append(f"{login} lacks CREATEROLE")
38
+ if catalog_owner:
39
+ problems.append(f'schema "metatables" belongs to {catalog_owner}')
40
+ elif not creates_schemas:
41
+ problems.append(f'{login} cannot create schemas in database "{database}"')
42
+ if not tables:
43
+ problems.append(f'{login} cannot create tables in schema "{schema}"')
44
+ return problems
45
+
17
46
  def initialize(self, session):
18
47
  self.identity_secret()
19
48
  connection = session.connection()
20
49
  self._role(connection, "mt_owner")
21
50
  api = connection.exec_driver_sql("SELECT current_user").scalar()
22
51
  connection.exec_driver_sql(f"GRANT mt_owner TO {quote(api)}")
23
- database = connection.exec_driver_sql("SELECT current_database()").scalar()
24
- connection.exec_driver_sql("GRANT USAGE, CREATE ON SCHEMA public TO mt_owner")
25
- connection.exec_driver_sql(f"REVOKE ALL ON DATABASE {quote(database)} FROM PUBLIC")
52
+ if connection.exec_driver_sql(
53
+ "SELECT has_schema_privilege(oid, 'CREATE WITH GRANT OPTION') FROM pg_namespace WHERE nspname='public'"
54
+ ).scalar():
55
+ connection.exec_driver_sql("GRANT USAGE, CREATE ON SCHEMA public TO mt_owner")
26
56
  connection.exec_driver_sql("REVOKE ALL ON SCHEMA metatables FROM PUBLIC")
27
- connection.exec_driver_sql("REVOKE CREATE ON SCHEMA public FROM PUBLIC")
28
57
  state = session.get(SQLSecurityState, 1)
29
58
  if state is None:
30
59
  state = SQLSecurityState(id=1, ready=True, pending=True, manifest={})
@@ -59,39 +88,46 @@ class PostgreSQLAccess(DatabaseAccess):
59
88
  else:
60
89
  connection.exec_driver_sql(f"ALTER ROLE {quote(name)} NOLOGIN")
61
90
 
91
+ def owned_schemas(self, connection):
92
+ return connection.exec_driver_sql(
93
+ "SELECT nspname FROM pg_namespace WHERE " + USER_SCHEMA.format(schema="nspname")
94
+ + " AND " + OWNED.format(owner="nspowner")
95
+ ).scalars().all()
96
+
62
97
  def secure_routines(self, connection, managed_roles):
63
- """Inspect only at initialization/schema changes/reconciliation."""
98
+ """Inspect only at initialization/schema changes/reconciliation.
99
+
100
+ Covers the objects this login owns; other owners' objects are left to
101
+ the database administrator.
102
+ """
64
103
  invoker = self.role("invoker", "routines")
65
104
  self._role(connection, invoker)
66
- schemas = (
67
- connection.exec_driver_sql(
68
- "SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_' AND nspname <> 'information_schema'"
69
- )
70
- .scalars()
71
- .all()
72
- )
73
- for schema in schemas:
74
- connection.exec_driver_sql(
75
- f"REVOKE ALL ON ALL TABLES IN SCHEMA {quote(schema)} FROM PUBLIC"
76
- )
105
+ for schema in self.owned_schemas(connection):
77
106
  if schema != "metatables":
78
107
  connection.exec_driver_sql(
79
108
  f"GRANT USAGE ON SCHEMA {quote(schema)} TO {quote(invoker)}"
80
109
  )
110
+ public_tables = connection.exec_driver_sql(
111
+ "SELECT DISTINCT n.nspname, c.relname FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace "
112
+ "CROSS JOIN LATERAL aclexplode(c.relacl) acl WHERE acl.grantee=0 AND c.relkind IN ('r','p','v','m','f') AND "
113
+ + USER_SCHEMA.format(schema="n.nspname") + " AND " + OWNED.format(owner="c.relowner")
114
+ ).all()
115
+ for schema, table in public_tables:
116
+ connection.exec_driver_sql(f"REVOKE ALL ON TABLE {quote(schema)}.{quote(table)} FROM PUBLIC")
81
117
  public_columns = connection.exec_driver_sql(
82
- "SELECT n.nspname, c.relname, a.attname FROM pg_attribute a JOIN pg_class c ON c.oid=a.attrelid JOIN pg_namespace n ON n.oid=c.relnamespace CROSS JOIN LATERAL aclexplode(a.attacl) acl WHERE acl.grantee=0 AND n.nspname !~ '^pg_'"
118
+ "SELECT n.nspname, c.relname, a.attname FROM pg_attribute a JOIN pg_class c ON c.oid=a.attrelid "
119
+ "JOIN pg_namespace n ON n.oid=c.relnamespace CROSS JOIN LATERAL aclexplode(a.attacl) acl "
120
+ "WHERE acl.grantee=0 AND n.nspname !~ '^pg_' AND " + OWNED.format(owner="c.relowner")
83
121
  ).all()
84
122
  for schema, table, column in public_columns:
85
123
  connection.exec_driver_sql(
86
124
  f"REVOKE ALL ({quote(column)}) ON TABLE {quote(schema)}.{quote(table)} FROM PUBLIC"
87
125
  )
88
- owners = (
89
- connection.exec_driver_sql(
90
- "SELECT DISTINCT r.rolname FROM pg_proc p JOIN pg_roles r ON r.oid=p.proowner JOIN pg_namespace n ON n.oid=p.pronamespace WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'"
91
- )
92
- .scalars()
93
- .all()
94
- )
126
+ owners = connection.exec_driver_sql(
127
+ "SELECT DISTINCT r.rolname FROM pg_proc p JOIN pg_roles r ON r.oid=p.proowner "
128
+ "JOIN pg_namespace n ON n.oid=p.pronamespace WHERE " + USER_SCHEMA.format(schema="n.nspname")
129
+ + " AND " + OWNED.format(owner="p.proowner")
130
+ ).scalars().all()
95
131
  owners = set(owners) | {
96
132
  "mt_owner",
97
133
  connection.exec_driver_sql("SELECT current_user").scalar(),
@@ -108,24 +144,17 @@ class PostgreSQLAccess(DatabaseAccess):
108
144
  grantees = "PUBLIC, " + ", ".join(
109
145
  quote(role) for role in sorted((set(managed_roles) | {invoker}) & existing)
110
146
  )
111
- for schema in schemas:
112
- for noun in ("FUNCTIONS", "PROCEDURES"):
113
- connection.exec_driver_sql(
114
- f"REVOKE ALL ON ALL {noun} IN SCHEMA {quote(schema)} FROM {grantees}"
115
- )
116
- if schema != "metatables":
117
- connection.exec_driver_sql(
118
- f"GRANT EXECUTE ON ALL {noun} IN SCHEMA {quote(schema)} TO {quote(invoker)}"
119
- )
120
- # Revoke elevated routines within the same transaction before publishing
121
- # permissions. Batch schema grants avoid an objects-by-principals loop.
147
+ # Restricted callers never execute routines with elevated owner privileges.
122
148
  routines = connection.exec_driver_sql(
123
- "SELECT n.nspname, p.proname, pg_get_function_identity_arguments(p.oid), p.prokind FROM pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace WHERE p.prosecdef AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'"
149
+ "SELECT n.nspname, p.proname, pg_get_function_identity_arguments(p.oid), p.prosecdef "
150
+ "FROM pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace WHERE "
151
+ + USER_SCHEMA.format(schema="n.nspname") + " AND " + OWNED.format(owner="p.proowner")
124
152
  ).all()
125
- for schema, name, arguments, kind in routines:
126
- noun = "PROCEDURE" if kind == "p" else "FUNCTION"
153
+ for schema, name, arguments, elevated in routines:
127
154
  target = f"{quote(schema)}.{quote(name)}({arguments})"
128
- connection.exec_driver_sql(f"REVOKE ALL ON {noun} {target} FROM {quote(invoker)}")
155
+ connection.exec_driver_sql(f"REVOKE ALL ON ROUTINE {target} FROM {grantees}")
156
+ if schema != "metatables" and not elevated:
157
+ connection.exec_driver_sql(f"GRANT EXECUTE ON ROUTINE {target} TO {quote(invoker)}")
129
158
 
130
159
  def validate_table(self, connection, table):
131
160
  schema = table.physical_schema or "public"
@@ -135,7 +164,7 @@ class PostgreSQLAccess(DatabaseAccess):
135
164
  raise SQLExecutionError(code="catalog_table_registration_denied")
136
165
  relation = f"{quote(schema)}.{quote(table.physical_table_name)}"
137
166
  row = connection.execute(
138
- text("SELECT oid, relkind FROM pg_class WHERE oid=to_regclass(:relation)"),
167
+ text("SELECT oid, relkind, " + OWNED.format(owner="relowner") + " AS owned FROM pg_class WHERE oid=to_regclass(:relation)"),
139
168
  {"relation": relation},
140
169
  ).first()
141
170
  if row is not None and row.relkind == "v":
@@ -159,7 +188,8 @@ class PostgreSQLAccess(DatabaseAccess):
159
188
  ),
160
189
  {"oid": row.oid},
161
190
  ).first()
162
- connection.exec_driver_sql(f"REVOKE ALL ON TABLE {relation} FROM PUBLIC")
191
+ if row.owned:
192
+ connection.exec_driver_sql(f"REVOKE ALL ON TABLE {relation} FROM PUBLIC")
163
193
  if table.management_mode == "platform_managed":
164
194
  connection.exec_driver_sql(f"ALTER TABLE {relation} OWNER TO mt_owner")
165
195
  return trigger is None
@@ -183,13 +213,7 @@ class PostgreSQLAccess(DatabaseAccess):
183
213
  for name, definition in roles.items():
184
214
  self._role(connection, name, self.password(name) if definition["login"] else None)
185
215
  names = set(roles) | set(previous.get("roles", {})) | {invoker}
186
- schemas = (
187
- connection.exec_driver_sql(
188
- "SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_' AND nspname <> 'information_schema'"
189
- )
190
- .scalars()
191
- .all()
192
- )
216
+ schemas = self.owned_schemas(connection)
193
217
  for name in sorted(names):
194
218
  owned = connection.execute(
195
219
  text(
@@ -215,20 +239,25 @@ class PostgreSQLAccess(DatabaseAccess):
215
239
  connection.exec_driver_sql(
216
240
  f"REVOKE ALL ON DATABASE {quote(database)} FROM {quote(name)}"
217
241
  )
218
- for schema in schemas:
219
- connection.exec_driver_sql(
220
- f"REVOKE ALL ON SCHEMA {quote(schema)} FROM {quote(name)}"
221
- )
222
- connection.exec_driver_sql(
223
- f"REVOKE ALL ON ALL SEQUENCES IN SCHEMA {quote(schema)} FROM {quote(name)}"
224
- )
225
- connection.exec_driver_sql(
226
- f"REVOKE ALL ON ALL TABLES IN SCHEMA {quote(schema)} FROM {quote(name)}"
227
- )
242
+ # Revoke this role's grants on owned objects; other owners' grants are theirs.
243
+ granted = connection.execute(
244
+ text(
245
+ "SELECT 'SCHEMA', quote_ident(n.nspname) FROM pg_namespace n CROSS JOIN LATERAL aclexplode(n.nspacl) acl "
246
+ "JOIN pg_roles r ON r.oid=acl.grantee WHERE r.rolname=:name AND " + OWNED.format(owner="n.nspowner")
247
+ + " UNION SELECT CASE WHEN c.relkind='S' THEN 'SEQUENCE' ELSE 'TABLE' END, "
248
+ "quote_ident(n.nspname) || '.' || quote_ident(c.relname) FROM pg_class c "
249
+ "JOIN pg_namespace n ON n.oid=c.relnamespace CROSS JOIN LATERAL aclexplode(c.relacl) acl "
250
+ "JOIN pg_roles r ON r.oid=acl.grantee WHERE r.rolname=:name AND " + OWNED.format(owner="c.relowner")
251
+ ),
252
+ {"name": name},
253
+ ).all()
254
+ for kind, target in granted:
255
+ connection.exec_driver_sql(f"REVOKE ALL ON {kind} {target} FROM {quote(name)}")
228
256
  # Table-level REVOKE does not remove separately granted column ACLs.
229
257
  columns = connection.execute(
230
258
  text(
231
- "SELECT n.nspname, c.relname, a.attname FROM pg_attribute a JOIN pg_class c ON c.oid=a.attrelid JOIN pg_namespace n ON n.oid=c.relnamespace CROSS JOIN LATERAL aclexplode(a.attacl) acl JOIN pg_roles r ON r.oid=acl.grantee WHERE r.rolname=:name AND n.nspname !~ '^pg_'"
259
+ "SELECT n.nspname, c.relname, a.attname FROM pg_attribute a JOIN pg_class c ON c.oid=a.attrelid JOIN pg_namespace n ON n.oid=c.relnamespace CROSS JOIN LATERAL aclexplode(a.attacl) acl JOIN pg_roles r ON r.oid=acl.grantee WHERE r.rolname=:name AND n.nspname !~ '^pg_' AND "
260
+ + OWNED.format(owner="c.relowner")
232
261
  ),
233
262
  {"name": name},
234
263
  ).all()
@@ -0,0 +1,190 @@
1
+ """A DataSource keeps its registration identity when its catalog is initialized."""
2
+ from contextlib import nullcontext
3
+ from dataclasses import dataclass
4
+ from types import SimpleNamespace
5
+ from uuid import UUID, uuid4
6
+
7
+ from sqlalchemy import select
8
+ from sqlalchemy.orm import sessionmaker
9
+
10
+ from metatables.api.app.bootstrap import RuntimeBootstrap
11
+ from metatables.api.app.runtime import RuntimeConfig
12
+ from metatables.api.app.runtime_control import write_state
13
+ from metatables.api.app.source_registrations import read_registry, reconcile_runtime
14
+ from metatables.api.backend.persistence.database import create_catalog_engine, upgrade_catalog
15
+ from metatables.api.backend.persistence.models import DataSource
16
+
17
+
18
+ def test_hosted_bootstrap_preserves_registered_datasource_uid(tmp_path, monkeypatch):
19
+ configuration = tmp_path / "configuration.yaml"
20
+ bootstrap = RuntimeBootstrap(RuntimeConfig(local_mode=False, configuration_path=configuration), None)
21
+ uid, user = uuid4(), uuid4()
22
+ bootstrap.selected_source_uid = str(uid)
23
+ bootstrap.candidate = dict(display_name="Hosted", class_type="postgresql", configuration={
24
+ "host": "db.example.invalid", "database_name": "tables", "database_user": "tables"})
25
+ engine = create_catalog_engine(f"sqlite:///{tmp_path / 'catalog.sqlite'}", allow_sqlite=True)
26
+ upgrade_catalog(engine)
27
+ bootstrap.engine = engine
28
+ bootstrap.factory = sessionmaker(engine, expire_on_commit=False)
29
+
30
+ @dataclass
31
+ class Source:
32
+ uid: UUID | None = None
33
+
34
+ bootstrap.backend = SimpleNamespace(source=Source())
35
+ # Keep the actual migration/registration transaction; isolate hosted driver
36
+ # and schema-access setup, which the engine contract tests cover separately.
37
+ monkeypatch.setattr(bootstrap, "migration_lock", nullcontext)
38
+ monkeypatch.setattr("metatables.api.backend.backends.registry.backend_for", lambda source:
39
+ SimpleNamespace(access=SimpleNamespace(initialize=lambda session: None)))
40
+
41
+ def inspect_registration():
42
+ with bootstrap.factory() as session:
43
+ row = session.scalar(select(DataSource).where(DataSource.is_runtime.is_(True)))
44
+ bootstrap.status = "ready" if row else "registration_required"
45
+ bootstrap.uid = row.uid if row else None
46
+ monkeypatch.setattr(bootstrap, "inspect", inspect_registration)
47
+ try:
48
+ bootstrap.migrate(user)
49
+ with bootstrap.factory() as session:
50
+ rows = session.scalars(select(DataSource)).all()
51
+ assert len(rows) == 1
52
+ assert rows[0].uid == uid
53
+ assert rows[0].is_runtime and rows[0].is_default
54
+ assert bootstrap.uid == uid
55
+ bootstrap.migrate(user)
56
+ with bootstrap.factory() as session:
57
+ assert session.scalar(select(DataSource.uid)) == uid
58
+ finally:
59
+ bootstrap.close()
60
+
61
+
62
+ def test_legacy_runtime_alias_is_reconciled_without_losing_other_sources(tmp_path):
63
+ bootstrap = RuntimeBootstrap(RuntimeConfig(local_mode=False,
64
+ configuration_path=tmp_path / "configuration.yaml"), None)
65
+ alias, canonical, other = uuid4(), uuid4(), uuid4()
66
+ config = {"host": "db.example.invalid", "database_name": "tables", "database_user": "tables"}
67
+ bootstrap.candidate = dict(display_name="Hosted", class_type="postgresql", configuration=config)
68
+ bootstrap.selected_source_uid = str(alias)
69
+ from datetime import datetime, timezone
70
+ row = DataSource(uid=canonical, display_name="Hosted", class_type="postgresql", configuration=config,
71
+ status="AVAILABLE", storage_access_mode="read_write", created_at=datetime.now(timezone.utc))
72
+ path = bootstrap.saved_path.with_name("runtime-source-candidates.json")
73
+ path.parent.mkdir(parents=True)
74
+ original = {"uid": str(alias), **bootstrap.candidate}
75
+ untouched = {"uid": str(other), "display_name": "Another source"}
76
+ write_state(path, {str(alias): original, str(other): untouched})
77
+ reconcile_runtime(bootstrap, row, persist=False)
78
+ saved = read_registry(path)
79
+ assert set(saved) == {str(canonical), str(other)}
80
+ assert saved[str(other)] == untouched
81
+ assert saved[str(canonical)]["configuration"] == config
82
+ assert bootstrap.selected_source_uid == str(canonical)
83
+ restarted = RuntimeBootstrap(bootstrap.config, None)
84
+ assert restarted.initial_candidate() == bootstrap.candidate
85
+ assert restarted.selected_source_uid == str(canonical)
86
+
87
+
88
+ def test_setup_reports_the_database_privilege_error_without_sql_or_parameters(tmp_path, monkeypatch):
89
+ import pytest
90
+ from sqlalchemy.exc import ProgrammingError
91
+
92
+ from metatables.api.app.bootstrap import BootstrapError
93
+
94
+ bootstrap = RuntimeBootstrap(RuntimeConfig(local_mode=False,
95
+ configuration_path=tmp_path / "configuration.yaml"), None)
96
+ bootstrap.selected_source_uid = str(uuid4())
97
+ bootstrap.candidate = dict(display_name="Hosted", class_type="timescale_db", configuration={
98
+ "host": "db.example.invalid", "database_name": "tables", "database_user": "tables"})
99
+ engine = create_catalog_engine(f"sqlite:///{tmp_path / 'catalog.sqlite'}", allow_sqlite=True)
100
+ bootstrap.engine = engine
101
+ bootstrap.factory = sessionmaker(engine, expire_on_commit=False)
102
+
103
+ @dataclass
104
+ class Source:
105
+ uid: UUID | None = None
106
+
107
+ bootstrap.backend = SimpleNamespace(source=Source())
108
+ monkeypatch.setattr(bootstrap, "migration_lock", nullcontext)
109
+ monkeypatch.setattr(bootstrap, "inspect", lambda: setattr(bootstrap, "status", "registration_required"))
110
+ # A TimescaleDB runtime whose extension objects belong to the superuser.
111
+ denied = SimpleNamespace(pgcode="42501", diag=SimpleNamespace(message_primary="permission denied for table job_errors"))
112
+
113
+ def initialize(session):
114
+ raise ProgrammingError('REVOKE ALL ON ALL TABLES IN SCHEMA "_timescaledb_internal" FROM PUBLIC',
115
+ {"password": "do-not-show"}, denied)
116
+
117
+ monkeypatch.setattr("metatables.api.backend.backends.registry.backend_for", lambda source:
118
+ SimpleNamespace(access=SimpleNamespace(initialize=initialize)))
119
+ try:
120
+ with pytest.raises(BootstrapError) as raised:
121
+ bootstrap.migrate(uuid4())
122
+ finally:
123
+ bootstrap.close()
124
+ message = str(raised.value)
125
+ assert "permission denied for table job_errors" in message
126
+ assert "must own the runtime database" in message
127
+ assert "REVOKE" not in message and "do-not-show" not in message
128
+ assert bootstrap.error == message
129
+
130
+
131
+ def _fresh_hosted_bootstrap(tmp_path, problems):
132
+ bootstrap = RuntimeBootstrap(RuntimeConfig(local_mode=False,
133
+ configuration_path=tmp_path / "configuration.yaml"), None)
134
+ bootstrap.candidate = dict(display_name="Development", class_type="timescale_db", configuration={
135
+ "host": "db.example.invalid", "database_name": "development", "database_user": "metatables_dev"})
136
+ engine = create_catalog_engine(f"sqlite:///{tmp_path / 'catalog.sqlite'}", allow_sqlite=True)
137
+ bootstrap.engine = engine
138
+ bootstrap.factory = sessionmaker(engine, expire_on_commit=False)
139
+ bootstrap.backend = SimpleNamespace(access=SimpleNamespace(prerequisite_problems=lambda connection: problems))
140
+ return bootstrap
141
+
142
+
143
+ def test_unsecurable_database_is_blocked_before_any_setup_ddl(tmp_path, monkeypatch):
144
+ import pytest
145
+
146
+ from metatables.api.app.bootstrap import BootstrapError
147
+
148
+ bootstrap = _fresh_hosted_bootstrap(tmp_path, [
149
+ 'metatables_dev does not own database "development"',
150
+ "312 object(s) are owned by postgres (extension timescaledb), e.g. schema _timescaledb_internal",
151
+ ])
152
+ monkeypatch.setattr("metatables.api.app.bootstrap.upgrade_catalog",
153
+ lambda engine: pytest.fail("Setup DDL ran on a database the login cannot secure"))
154
+ try:
155
+ bootstrap.inspect()
156
+ assert bootstrap.status == "incompatible"
157
+ assert 'metatables_dev does not own database "development"' in bootstrap.error
158
+ assert "extension timescaledb" in bootstrap.error
159
+ with pytest.raises(BootstrapError, match="cannot secure this database"):
160
+ bootstrap.migrate(uuid4())
161
+ finally:
162
+ bootstrap.close()
163
+
164
+
165
+ def test_securable_fresh_database_still_requires_migrations(tmp_path):
166
+ bootstrap = _fresh_hosted_bootstrap(tmp_path, [])
167
+ try:
168
+ bootstrap.inspect()
169
+ assert bootstrap.status == "migration_required" and bootstrap.error is None
170
+ finally:
171
+ bootstrap.close()
172
+
173
+
174
+ def test_postgresql_prerequisites_name_only_what_metatables_needs():
175
+ from metatables.api.backend.backends.postgresql_access import PostgreSQLAccess
176
+
177
+ def check(row, schema="public"):
178
+ access = PostgreSQLAccess.__new__(PostgreSQLAccess)
179
+ access.source = SimpleNamespace(connection=SimpleNamespace(default_schema=schema))
180
+ connection = SimpleNamespace(execute=lambda *args: SimpleNamespace(one=lambda: row))
181
+ return access.prerequisite_problems(connection)
182
+
183
+ # A shared database qualifies: the login need not own it or anyone else's objects.
184
+ assert check(("metatables_dev", "development", True, True, None, True)) == []
185
+ assert check(("app", "shared", False, False, None, False), schema="tables") == [
186
+ "app lacks CREATEROLE",
187
+ 'app cannot create schemas in database "shared"',
188
+ 'app cannot create tables in schema "tables"',
189
+ ]
190
+ assert check(("app", "shared", True, False, "someone", True)) == ['schema "metatables" belongs to someone']