mainsequence-metatable 0.1.28.dev48__tar.gz → 0.1.28.dev50__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/PKG-INFO +1 -1
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0007-database-enforced-table-access.md +23 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0022-concurrent-requests-and-connection-reuse.md +4 -3
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/index.md +1 -1
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/pyproject.toml +1 -1
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/mainsequence_metatable.egg-info/PKG-INFO +1 -1
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/mainsequence_metatable.egg-info/SOURCES.txt +1 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/access.py +159 -14
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/hosted_access.py +2 -2
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/postgresql_access.py +133 -68
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/sqlite_access.py +3 -1
- mainsequence_metatable-0.1.28.dev50/tests/permissions/test_incremental_security.py +198 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/analyze-with-sql/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/client/metatables-local-development/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/client/metatables-meta-tables/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/client/metatables-migrations/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/client/metatables-table-discovery/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/client/metatables-time-index-table-updates/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/client/metatables-upgrade-legacy-app/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/discover-tables/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/ms_tau_sdk/PINNED_FROM.txt +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/ms_tau_sdk/tau_a2a_runtime_adapter/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/ms_tau_sdk/tau_local_development/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/ms_tau_sdk/tau_project_customization/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/ms_tau_sdk/tau_repository_integration/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.agents/skills/ms_tau_sdk/tau_security_and_access/SKILL.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/.mainsequence/workflows/metatables-api.yaml +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/LICENSE +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/MANIFEST.in +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/alembic.ini +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/api/metatables/main.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/compose.database-tests.yml +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/agent/0019-metatables-analyst-agent.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/agent/0020-analyst-reads-as-its-requester.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/agent/0021-api-serves-the-analyst-tools-over-mcp.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0001-unified-api-storage-and-local-sqlite.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0002-application-administration-and-table-ownership.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0004-approved-application-migrations.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0005-run-logs-and-local-file-capture.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0006-historical-run-graphs.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0007-database-roles-and-privileges.svg +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0007-query-enforcement-path.svg +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0008-mysql-mssql-table-workflows.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0009-shared-credential-store.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0010-import-external-tables-and-views.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0012-bounded-data-transfer-and-safe-retries.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0013-application-owned-migrations.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0014-main-sequence-release-jobs-and-production-migrations.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0015-timescale-compression-and-retention-policies.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0016-impact-preflight.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0017-hosted-request-identity.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0018-search-document-pipeline.svg +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/api/0018-table-search.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/client/0003-api-endpoint-resolution.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/client/0011-cli-local-development-with-managed-admin.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/api/authentication-and-errors.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/api/data-sources.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/api/openapi.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/api/overview.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/api/reference.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/api/tables-and-migrations.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/api/time-index-and-updates.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/assets/branding/metatables.svg +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/assets/diagrams/local-client-experience.svg +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/assets/diagrams/namespace-access.svg +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/bounded-transfers.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/build-an-updater.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/define-and-migrate-tables.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/deploy-application-migrations.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/installation-and-connection.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/local-storage.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/query-and-mutate.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/quickstart.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/read-existing-time-index-tables.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/register-existing-tables.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/tutorial.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/client/upgrade-legacy-app.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/concepts/architecture.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/concepts/data-sources.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/concepts/identity-and-scope.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/concepts/permissions-namespaces-labels.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/concepts/runs-and-execution-graphs.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/concepts/table-contracts-and-lifecycle.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/concepts/time-index-tables-and-updates.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/contributing/architecture-and-boundaries.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/contributing/database-backends.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/contributing/documentation.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/contributing/releasing.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/contributing/testing.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/bounded_reader.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/data_sources/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/data_sources/mssql.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/data_sources/mysql.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/data_sources/postgresql.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/data_sources/register.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/external_table.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/local_app/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/local_app/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/local_app/__main__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/local_app/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/local_app/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/local_app/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/local_app/migrations/versions/metatables_local_example/0001.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/local_app/tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/query.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/quickstart.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/reader.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/scripts/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/scripts/setup_metatables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/__main__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/data/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/data/yahoo_spy_qqq_iwm_2026-06-15_2026-07-17.csv +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/frames.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/migrations/registry.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/migrations/versions/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/0001_create_market_tutorial_tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/0002_create_rolling_volatility.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/operations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/tutorial/updaters.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/examples/updater.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/index.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/operations/catalog-migrations.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/operations/configuration.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/operations/hosted-runtime.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/operations/local-runtime.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/operations/recovery-and-observability.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/operations/run-history.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/operations/run-logs.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/reference/capabilities.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/reference/cli.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/reference/python.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/security/index.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/security/ownership-and-sharing.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/security/permissions.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/mkdocs.yml +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/build_reference.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/check_boundaries.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/check_client_api_coverage.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/check_distribution_sources.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/check_docs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/check_examples_debug.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/check_project.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/dev_release_version.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/test_databases.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/scripts/test_postgresql.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/setup.cfg +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/mainsequence_metatable.egg-info/dependency_links.txt +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/mainsequence_metatable.egg-info/entry_points.txt +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/mainsequence_metatable.egg-info/requires.txt +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/mainsequence_metatable.egg-info/top_level.txt +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/_admin_source.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/_build.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/_skill_bundle.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/analysis.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/analyst/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/auth/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/auth/boundary.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/auth/local_actor.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/bootstrap.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/configuration.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/connection_count.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/credential_admin.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/development.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/development_client.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/error_logging.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/main.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/mcp.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/platform_cache.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/access_map.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/caller.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/column_search.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/contract_validation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/data_sources.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/managed_finalize.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/migration_connection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/namespaces.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/run_logs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/runtime_context.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/schema_graph.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/security.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_cascade.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_crud.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_delete.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_filter.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_import.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_introspection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_patch.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_registration.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_response.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_search.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_search_document.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_sql.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/table_update_pipeline.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/time_index_delete.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/time_index_reads.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/time_index_stats.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/timescale_policies.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_batch.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_chunk_insert.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_constants.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_crud.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_details.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_graph.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_index_statistics.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_registration.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_runs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/routes/update_statistics.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/runtime.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/runtime_control.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/runtime_database.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/source_passwords.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/app/transfer.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/maintenance/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/maintenance/postgresql.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/maintenance/runtime.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/maintenance/temporal.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/maintenance/timescaledb.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/maintenance/validation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_cascade_delete.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_connection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_introspection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_table_delete.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_time_index.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_time_index_delete.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_time_index_queries.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_time_index_stats.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/postgresql_time_index_write.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/source_validation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/sqlite_connection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/sqlite_introspection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/adapters/table_cursor.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/catalog.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/catalog_ddl.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/catalog_types.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/connection_pool.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/contracts.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/hosted.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/migration_connection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/native.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/operations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/pages.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/registry.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/relation_tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/relational.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/restricted_sql.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/streaming.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/backends/timescale.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/contracts/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/contracts/relation_import.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/contracts/storage_layouts.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/contracts/table_contracts.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/contracts/values.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/domain/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/domain/catalog_rules.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/domain/data_source_rules.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/domain/index_statistics.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/domain/label_rules.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/domain/permission_rules.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/domain/update_constants.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/catalog_data_sources.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/credential_keys.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/credential_store.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/data_source_provider.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/local_credentials.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/local_workspace.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/platform_principals.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/run_logs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/runtime_binding.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/runtime_data_sources.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/integrations/source_validation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0001_initial.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0002_security_model.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0003_run_log_capture.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0004_historical_run_graphs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0005_database_access.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0006_local_credentials.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0007_external_relation_names.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0008_upload_receipts.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0009_timescale_policies.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0010_cascade_targets.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0011_table_search.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/0012_table_creator.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/migrations/versions/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/bootstrap_migrations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/catalog_schema.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/create_table.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/finalize_managed.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/import_relations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/introspect_table.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/read_time_index.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/operations/register_catalog.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/cascade.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/catalog.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/database.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/grants.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/impact.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/labels.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/locking.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/models.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/physical_operations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/projections.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/run_graphs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/schema_graph.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/sqlite_types.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/table_body_filter.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/table_queries.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/table_response.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/update_graph.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/update_pipeline.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/updates.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/persistence/upload_receipts.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/presentation/data_source_summary.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/search/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/search/documents.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/search/embeddings.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/search/index.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/search/ranking.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/search/text.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/backend/search/worker.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/metatables/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/metatables/configuration.yaml +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/metatables/main.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/api/request_timing.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/cli/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/cli/admin_install.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/cli/app.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/cli/filters.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/cli/local.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/cli/migrations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/cli/project.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/cli/skills.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/compiled_sql/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/compiled_sql/mssql.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/compiled_sql/v1.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/dtype_codec.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/endpoint.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/bounded_reader.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/data_sources/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/data_sources/mssql.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/data_sources/mysql.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/data_sources/postgresql.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/data_sources/register.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/external_table.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/local_app/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/local_app/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/local_app/__main__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/local_app/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/local_app/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/local_app/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/local_app/migrations/versions/metatables_local_example/0001.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/local_app/tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/query.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/quickstart.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/reader.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/scripts/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/scripts/setup_metatables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/__main__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/data/README.md +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/data/yahoo_spy_qqq_iwm_2026-06-15_2026-07-17.csv +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/frames.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/migrations/registry.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/migrations/versions/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/0001_create_market_tutorial_tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/0002_create_rolling_volatility.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/operations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/tutorial/updaters.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/examples/updater.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/future_registry.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/hashing.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/instrumentation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/local_connection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/local_files.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/local_run_logs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/log_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/alembic.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/connection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/provider.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/registry.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/runner.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/scaffold.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/sqlite.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/templates/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/templates/env.py.mako +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/templates/script.py.mako +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/migrations/tls.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/models.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/pydantic_metadata.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/run_logging.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/runtime.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/runtime_context.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/runtime_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/schema_names.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/sdk_compat.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/sqlalchemy_contracts.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/storage_layout_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/time_index_table_refs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/transfer.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/transfer_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/transport.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/update_configuration_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/updaters/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/updaters/configuration.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/updaters/dependencies.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/updaters/managers.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/updaters/namespacing.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/updaters/runner.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/updaters/updaters.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/updaters/utils.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/src/metatables/upload.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/analyst/test_agent_surface.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/analyst/test_api_search.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/analyst/test_mcp.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/analyst/test_tools.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_bootstrap_failure_cause.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_caller_endpoint.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_data_source_identity.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_development_client.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_hosted_agent.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_hosted_environment_target.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_local_mode.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_platform_fact_cache.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_request_identity.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_runtime_bootstrap.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_runtime_database.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_runtime_scaffold.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_runtime_selection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_runtime_storage_binding.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/auth/test_source_passwords.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/catalog/test_catalog_foundation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/catalog/test_contract_projection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/catalog/test_database_config.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/catalog/test_index_statistics.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/catalog/test_migration.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/conftest.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/capabilities.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/client_signatures.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/database_operations.json +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/test_bounded_transfer.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/test_compiler_runtime_source.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/test_relation_batching.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/test_relation_import.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/test_runtime_contract_compat.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/test_storage_layouts.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/contracts/test_table_contracts.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/Dockerfile +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/Dockerfile.dockerignore +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/conftest.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/provider/__init__.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/provider/env.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/provider/versions/0001_measurement.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_api_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_application_migration.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_bootstrap_recovery.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_catalog_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_credential_catalog.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_physical_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_relation_import.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_runtime_bootstrap.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_sql_security.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_backend/test_update_client.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_operations/test_physical_operations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_operations/test_postgresql_operations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/database_operations/test_runtime_and_temporal.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/documentation/test_project_checks.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_admin_installation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_api_endpoint.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_application_owned_migrations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_catalog_outage.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_client_api_contract.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_client_api_coverage.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_client_migration_scaffold.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_client_migration_tls.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_client_package.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_client_signatures.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_client_value_behaviors.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_data_source_registry.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_local_actor_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_local_cli_workflow.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_local_client_selection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_managed_finalize_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_namespaces_admin_http.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_public_imports.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_remaining_client_routes.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_run_graphs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_run_logs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_runtime_upgrade.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_sdk_local_startup.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_sqlite_runtime.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_delete_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_filter_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_introspection_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_patch_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_search_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_search_document_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_search_scale.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_stats_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_update_pipeline.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_table_updates_http.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_time_index_delete_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_time_index_reads_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_timescale_policies_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_update_batch_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_update_chunk_insert_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_update_dependency_priority_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_update_index_statistics_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/e2e/test_update_registration_client_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/examples/test_documented_examples.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/examples/test_postgresql_examples.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/examples/test_setup_launch.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/examples/test_tutorial.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_connection_reuse.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_credential_store.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_data_source_rules.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_local_data_sources.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_local_run_logs.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_postgresql_connection.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_postgresql_sql.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_postgresql_tables.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_postgresql_time_index_queries.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_request_timing.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_serving_policy.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_source_validation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/integrations/test_sqlite_operations.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/labels/test_labels.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/operations/test_create_table_operation.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/operations/test_create_table_postgres.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/operations/test_physical_operation_journal.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/operations/test_register_catalog.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/operations/test_search_documents.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/operations/test_timescale_policies.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/packaging/test_client_skills.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/packaging/test_dev_release_version.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/packaging/test_distribution_sources.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/packaging/test_editable_build.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/packaging/test_installed_distribution.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_access_map.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_governed_sql_scope.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_local_actor_membership.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_migration_boundary.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_namespace_grants.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_security_api.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_table_body_filter.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_table_grants.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_table_queries.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/tests/permissions/test_workload_principals.py +0 -0
- {mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/uv.lock +0 -0
|
@@ -32,6 +32,29 @@
|
|
|
32
32
|
> Reconciliation still records each table's cascade targets, but only so the
|
|
33
33
|
> [impact pre-flight](0016-impact-preflight.md) can show their effects.
|
|
34
34
|
|
|
35
|
+
> Amendment (2026-10-09): On PostgreSQL and TimescaleDB, a catalog change applies
|
|
36
|
+
> only what it changed. Reconciliation used to rebuild every role, re-inspect every
|
|
37
|
+
> table and re-secure every routine on each change, all under the catalog lock, so
|
|
38
|
+
> one registration could hold the lock for minutes and stop every other request.
|
|
39
|
+
> Now a change:
|
|
40
|
+
>
|
|
41
|
+
> - re-inspects the policies of the tables it changed, plus the tables whose
|
|
42
|
+
> recorded cascade targets they affect;
|
|
43
|
+
> - rebuilds only roles that are new or whose definition changed, and grants or
|
|
44
|
+
> revokes only the memberships and privileges that differ from the applied
|
|
45
|
+
> manifest;
|
|
46
|
+
> - re-secures routines only when the owned schemas, routines or `PUBLIC` grants
|
|
47
|
+
> changed since the last sweep.
|
|
48
|
+
>
|
|
49
|
+
> The full sweep still runs when the runtime DataSource changes, at initialization
|
|
50
|
+
> (the migration Job of every deployment) and from the admin repair action. Those
|
|
51
|
+
> are when grants changed outside MetaTables are repaired, not on every catalog
|
|
52
|
+
> change. MySQL and SQL Server keep the full sweep on every change.
|
|
53
|
+
|
|
54
|
+
> Amendment (2026-10-09): [ADR 0022](0022-concurrent-requests-and-connection-reuse.md)
|
|
55
|
+
> reuses login-role connections within a pod, only by the login role that opened them
|
|
56
|
+
> and never through `SET ROLE`; no session state carries over from one use to the next.
|
|
57
|
+
|
|
35
58
|
|
|
36
59
|
Date: 2026-09-29
|
|
37
60
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# ADR 0022: Concurrent requests per pod and reused database connections
|
|
2
2
|
|
|
3
|
-
Status:
|
|
3
|
+
Status: Accepted.
|
|
4
4
|
|
|
5
|
-
Implementation status: implemented on development
|
|
6
|
-
the container
|
|
5
|
+
Implementation status: implemented on development. Unit tests pass; deployment
|
|
6
|
+
verification, the MySQL and SQL Server container suites and the load test against the
|
|
7
|
+
development deployment are pending.
|
|
7
8
|
|
|
8
9
|
Owner: this repository.
|
|
9
10
|
|
{mainsequence_metatable-0.1.28.dev48 → mainsequence_metatable-0.1.28.dev50}/docs/adr/index.md
RENAMED
|
@@ -39,7 +39,7 @@ decisions belong in the SDK repository and are linked as dependencies.
|
|
|
39
39
|
| [0016: Impact pre-flight for cascades and deletes](api/0016-impact-preflight.md) | Accepted; implemented; container engine verification pending | `get_impact` returns what a row delete, key update or table drop reaches, every blocker and whether the caller may write each table, from the planner the confirmed delete runs; cascade effects never block. Projects render it in their own UIs. |
|
|
40
40
|
| [0017: Hosted caller identity through the SDK request identity](api/0017-hosted-request-identity.md) | Accepted; implemented for 0.1.21; hosted rollout verification pending | The hosted API installs the SDK request identity that the platform launcher requires; the SDK verifies each caller assertion once and admission reads `User.get_logged_user()`, including the caller's signed Teams and admin flag. Local keeps its loopback token admission. |
|
|
41
41
|
| [0018: Table search by meaning and columns](api/0018-table-search.md) | Accepted; implemented; container engine verification pending | One route ranks visible tables by BM25 keywords and a local English embedding model over a per-table document that includes columns, merges the rankings and returns `matched_columns`; the index refreshes on every metadata write. |
|
|
42
|
-
| [0022: Concurrent requests per pod and reused database connections](api/0022-concurrent-requests-and-connection-reuse.md) |
|
|
42
|
+
| [0022: Concurrent requests per pod and reused database connections](api/0022-concurrent-requests-and-connection-reuse.md) | Accepted; implemented on development; deployment and load verification pending | One number per pod sizes its threads, data-request admission, catalog pool and login-role connections; connections are reused only by the role that opened them, and maximum pods × 3T stays within the database's connection limit. |
|
|
43
43
|
|
|
44
44
|
## Agents
|
|
45
45
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mainsequence-metatable"
|
|
7
|
-
version = "0.1.28.
|
|
7
|
+
version = "0.1.28.dev50"
|
|
8
8
|
description = "Main Sequence MetaTables Python client and standalone API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13"
|
|
@@ -572,6 +572,7 @@ tests/packaging/test_editable_build.py
|
|
|
572
572
|
tests/packaging/test_installed_distribution.py
|
|
573
573
|
tests/permissions/test_access_map.py
|
|
574
574
|
tests/permissions/test_governed_sql_scope.py
|
|
575
|
+
tests/permissions/test_incremental_security.py
|
|
575
576
|
tests/permissions/test_local_actor_membership.py
|
|
576
577
|
tests/permissions/test_migration_boundary.py
|
|
577
578
|
tests/permissions/test_namespace_grants.py
|
|
@@ -33,9 +33,73 @@ class ExecutionIdentity:
|
|
|
33
33
|
writable: frozenset[tuple[str, str]]
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
@dataclass(frozen=True)
|
|
37
|
+
class ManifestChanges:
|
|
38
|
+
"""The statements that move the database from one applied manifest to the next.
|
|
39
|
+
|
|
40
|
+
``reset`` roles are new or changed: each is rebuilt completely, so every one of
|
|
41
|
+
its memberships and privileges is granted again. ``retired`` roles are rebuilt
|
|
42
|
+
with nothing. Other roles change only by the memberships and privileges that
|
|
43
|
+
differ.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
reset: frozenset
|
|
47
|
+
retired: frozenset
|
|
48
|
+
revoke_memberships: tuple
|
|
49
|
+
revoke_privileges: tuple
|
|
50
|
+
revoke_schemas: tuple
|
|
51
|
+
grant_memberships: tuple
|
|
52
|
+
grant_privileges: tuple
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def manifest_changes(previous, desired):
|
|
56
|
+
"""Diff two manifests; None when ``previous`` is not a complete applied manifest."""
|
|
57
|
+
if not (
|
|
58
|
+
isinstance(previous, dict)
|
|
59
|
+
and isinstance(previous.get("roles"), dict)
|
|
60
|
+
and isinstance(previous.get("memberships"), list)
|
|
61
|
+
and isinstance(previous.get("privileges"), list)
|
|
62
|
+
):
|
|
63
|
+
return None
|
|
64
|
+
before, roles = previous["roles"], desired["roles"]
|
|
65
|
+
reset = frozenset(name for name, definition in roles.items() if before.get(name) != definition)
|
|
66
|
+
retired = frozenset(set(before) - set(roles))
|
|
67
|
+
rebuilt = reset | retired
|
|
68
|
+
old_memberships = {tuple(row) for row in previous["memberships"]}
|
|
69
|
+
new_memberships = {tuple(row) for row in desired["memberships"]}
|
|
70
|
+
old_privileges = {(n, s, t, bool(w)) for n, s, t, w in previous["privileges"]}
|
|
71
|
+
new_privileges = {(n, s, t, bool(w)) for n, s, t, w in desired["privileges"]}
|
|
72
|
+
revoke_privileges = tuple(sorted(
|
|
73
|
+
row for row in old_privileges - new_privileges if row[0] not in rebuilt
|
|
74
|
+
))
|
|
75
|
+
kept_schemas = {(name, schema) for name, schema, _, _ in new_privileges}
|
|
76
|
+
return ManifestChanges(
|
|
77
|
+
reset=reset,
|
|
78
|
+
retired=retired,
|
|
79
|
+
# Rebuilding a role already revokes every membership it holds.
|
|
80
|
+
revoke_memberships=tuple(sorted(
|
|
81
|
+
row for row in old_memberships - new_memberships if row[0] not in rebuilt
|
|
82
|
+
)),
|
|
83
|
+
revoke_privileges=revoke_privileges,
|
|
84
|
+
revoke_schemas=tuple(sorted(
|
|
85
|
+
{(name, schema) for name, schema, _, _ in revoke_privileges} - kept_schemas
|
|
86
|
+
)),
|
|
87
|
+
grant_memberships=tuple(sorted(
|
|
88
|
+
row for row in new_memberships if row[0] in reset or row not in old_memberships
|
|
89
|
+
)),
|
|
90
|
+
grant_privileges=tuple(sorted(
|
|
91
|
+
row for row in new_privileges if row[0] in reset or row not in old_privileges
|
|
92
|
+
)),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
36
96
|
class DatabaseAccess:
|
|
37
97
|
"""Backend facet for setup, mirroring and restricted session admission."""
|
|
38
98
|
|
|
99
|
+
# A catalog change applies only what it changed; the full sweep stays for
|
|
100
|
+
# initialization and repair (ADR 0007, amended 2026-10-09).
|
|
101
|
+
incremental = False
|
|
102
|
+
|
|
39
103
|
def __init__(self, backend):
|
|
40
104
|
self.backend = backend
|
|
41
105
|
self.source = backend.source
|
|
@@ -87,16 +151,20 @@ class DatabaseAccess:
|
|
|
87
151
|
deleted or their keys updated, as (schema, table, on_delete, on_update)."""
|
|
88
152
|
raise NotImplementedError
|
|
89
153
|
|
|
90
|
-
def refresh_policies(self, session):
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
)
|
|
154
|
+
def refresh_policies(self, session, tables=None):
|
|
155
|
+
"""Inspect every table's policy, or only those of the table UIDs in ``tables``."""
|
|
156
|
+
query = (
|
|
157
|
+
select(MetaTable)
|
|
158
|
+
.where(MetaTable.data_source_uid == self.source.uid)
|
|
159
|
+
.execution_options(populate_existing=True)
|
|
97
160
|
)
|
|
161
|
+
policies = select(SQLTablePolicy)
|
|
162
|
+
if tables is not None:
|
|
163
|
+
query = query.where(MetaTable.uid.in_(tables))
|
|
164
|
+
policies = policies.where(SQLTablePolicy.table_uid.in_(tables))
|
|
165
|
+
tables = list(session.scalars(query))
|
|
98
166
|
current = {t.uid for t in tables}
|
|
99
|
-
for old in session.scalars(
|
|
167
|
+
for old in session.scalars(policies):
|
|
100
168
|
if old.table_uid not in current:
|
|
101
169
|
session.delete(old)
|
|
102
170
|
for table in tables:
|
|
@@ -129,6 +197,59 @@ class DatabaseAccess:
|
|
|
129
197
|
]
|
|
130
198
|
session.flush()
|
|
131
199
|
|
|
200
|
+
def policy_scope(self, session, changed):
|
|
201
|
+
"""The tables whose policies a change to ``changed`` can affect.
|
|
202
|
+
|
|
203
|
+
A policy records its table's cascade targets, the tables whose foreign keys
|
|
204
|
+
act on its rows, so the scope adds the tables the changed ones reference and
|
|
205
|
+
the tables whose recorded targets name them. Returns None, meaning every
|
|
206
|
+
table, when a reference cannot be read.
|
|
207
|
+
"""
|
|
208
|
+
import sqlalchemy as sa
|
|
209
|
+
|
|
210
|
+
changed = set(changed)
|
|
211
|
+
tables = {
|
|
212
|
+
t.uid: t
|
|
213
|
+
for t in session.scalars(
|
|
214
|
+
select(MetaTable).where(MetaTable.data_source_uid == self.source.uid)
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
def key(schema, name):
|
|
219
|
+
return self.backend.catalog.registration_schema(self.source, schema), name
|
|
220
|
+
|
|
221
|
+
by_name = {key(t.physical_schema, t.physical_table_name): uid for uid, t in tables.items()}
|
|
222
|
+
names = {key(t.physical_schema, t.physical_table_name) for uid, t in tables.items() if uid in changed}
|
|
223
|
+
names |= {
|
|
224
|
+
(policy.schema_name, policy.table_name)
|
|
225
|
+
for policy in session.scalars(
|
|
226
|
+
select(SQLTablePolicy).where(SQLTablePolicy.table_uid.in_(changed))
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
scope = set(changed)
|
|
230
|
+
inspector = sa.inspect(session.connection())
|
|
231
|
+
for uid in sorted(changed & set(tables), key=str):
|
|
232
|
+
table = tables[uid]
|
|
233
|
+
if table.provisioning_status != "active":
|
|
234
|
+
continue
|
|
235
|
+
try:
|
|
236
|
+
references = inspector.get_foreign_keys(
|
|
237
|
+
table.physical_table_name, schema=table.physical_schema
|
|
238
|
+
)
|
|
239
|
+
except Exception:
|
|
240
|
+
return None
|
|
241
|
+
for reference in references:
|
|
242
|
+
schema = reference.get("referred_schema") or table.physical_schema
|
|
243
|
+
scope.add(by_name.get(key(schema, reference["referred_table"])))
|
|
244
|
+
for policy in session.scalars(select(SQLTablePolicy)):
|
|
245
|
+
if any(
|
|
246
|
+
key(target.get("schema"), target.get("table")) in names
|
|
247
|
+
for target in policy.cascade_targets or ()
|
|
248
|
+
):
|
|
249
|
+
scope.add(policy.table_uid)
|
|
250
|
+
scope.discard(None)
|
|
251
|
+
return scope
|
|
252
|
+
|
|
132
253
|
def plan(self, session):
|
|
133
254
|
"""Read only catalog facts. No submitted statement or physical inspection."""
|
|
134
255
|
roles, memberships, privileges = {}, set(), set()
|
|
@@ -190,18 +311,33 @@ class DatabaseAccess:
|
|
|
190
311
|
memberships.add((login, role("team", team, write)))
|
|
191
312
|
return dict(roles=roles, memberships=sorted(memberships), privileges=sorted(privileges))
|
|
192
313
|
|
|
193
|
-
def reconcile(self, session, *, inspect_objects=False):
|
|
314
|
+
def reconcile(self, session, *, inspect_objects=False, tables=None):
|
|
315
|
+
"""Mirror the catalog into database grants.
|
|
316
|
+
|
|
317
|
+
``inspect_objects`` is the full sweep: every policy is inspected and every
|
|
318
|
+
role rebuilt, which also repairs grants changed outside MetaTables.
|
|
319
|
+
Otherwise only the policies ``tables`` can affect are inspected, and an
|
|
320
|
+
incremental backend applies only the grants that changed.
|
|
321
|
+
"""
|
|
194
322
|
state = session.get(SQLSecurityState, 1)
|
|
195
323
|
if state is None or not state.ready:
|
|
196
324
|
raise SQLExecutionError(code="sql_security_not_initialized")
|
|
197
325
|
if inspect_objects:
|
|
198
326
|
self.refresh_policies(session)
|
|
327
|
+
elif tables:
|
|
328
|
+
self.refresh_policies(session, tables=self.policy_scope(session, tables))
|
|
199
329
|
desired = self.plan(session)
|
|
200
|
-
self.apply(session, desired, state.manifest)
|
|
330
|
+
self.apply(session, desired, state.manifest, full=inspect_objects)
|
|
201
331
|
state.manifest, state.pending = desired, False
|
|
202
332
|
session.flush()
|
|
203
333
|
|
|
204
|
-
def
|
|
334
|
+
def reconcile_change(self, session, *, tables, full=False):
|
|
335
|
+
"""Reconcile one catalog unit of work just before it commits."""
|
|
336
|
+
if full or not self.incremental:
|
|
337
|
+
return self.reconcile(session, inspect_objects=True)
|
|
338
|
+
return self.reconcile(session, tables=tables)
|
|
339
|
+
|
|
340
|
+
def apply(self, session, desired, previous, *, full=True):
|
|
205
341
|
raise NotImplementedError
|
|
206
342
|
|
|
207
343
|
def admit(self, session, actor, *, write, reconcile=True):
|
|
@@ -318,6 +454,13 @@ def _changed(session, *_):
|
|
|
318
454
|
|
|
319
455
|
with session.no_autoflush:
|
|
320
456
|
for row in session.new | session.dirty | session.deleted:
|
|
457
|
+
if isinstance(row, MetaTable) and row.data_source_uid == source_uid:
|
|
458
|
+
# Rows, not UIDs: a new row has its UID only once it is flushed.
|
|
459
|
+
session.info.setdefault("sql_security_tables", []).append(row)
|
|
460
|
+
elif isinstance(row, DataSource) and (row.is_runtime or row.is_default):
|
|
461
|
+
session.info["sql_security_full"] = True
|
|
462
|
+
elif session.info.get("sql_security_changed"):
|
|
463
|
+
continue
|
|
321
464
|
relevant = (
|
|
322
465
|
isinstance(row, MetaTable)
|
|
323
466
|
and row.data_source_uid == source_uid
|
|
@@ -347,7 +490,6 @@ def _changed(session, *_):
|
|
|
347
490
|
)
|
|
348
491
|
if relevant:
|
|
349
492
|
session.info["sql_security_changed"] = True
|
|
350
|
-
break
|
|
351
493
|
|
|
352
494
|
|
|
353
495
|
def _before_commit(session):
|
|
@@ -361,14 +503,15 @@ def _before_commit(session):
|
|
|
361
503
|
):
|
|
362
504
|
return
|
|
363
505
|
session.flush()
|
|
506
|
+
tables = {row.uid for row in session.info.pop("sql_security_tables", ())}
|
|
507
|
+
full = session.info.pop("sql_security_full", False)
|
|
364
508
|
if not session.info.pop("sql_security_changed", False):
|
|
365
509
|
return
|
|
366
510
|
session.info["sql_security_syncing"] = True
|
|
367
511
|
try:
|
|
368
512
|
backend = resolver()
|
|
369
513
|
backend.catalog.lock(session)
|
|
370
|
-
access =
|
|
371
|
-
access.reconcile(session, inspect_objects=True)
|
|
514
|
+
backend.access.reconcile_change(session, tables=tables, full=full)
|
|
372
515
|
finally:
|
|
373
516
|
session.info.pop("sql_security_syncing", None)
|
|
374
517
|
|
|
@@ -391,6 +534,8 @@ def _after_transaction_end(session, transaction):
|
|
|
391
534
|
committed = session.info.pop("sql_commit_finished", False)
|
|
392
535
|
access = session.info.pop("sql_deferred_access", None)
|
|
393
536
|
session.info.pop("sql_security_changed", None)
|
|
537
|
+
session.info.pop("sql_security_tables", None)
|
|
538
|
+
session.info.pop("sql_security_full", None)
|
|
394
539
|
session.info.pop("sql_admission_uncommitted", None)
|
|
395
540
|
if committed and access is not None:
|
|
396
541
|
try:
|
|
@@ -164,7 +164,7 @@ class MySQLAccess(HostedAccess):
|
|
|
164
164
|
state.pending = False
|
|
165
165
|
session.commit()
|
|
166
166
|
|
|
167
|
-
def apply(self, session, desired, previous):
|
|
167
|
+
def apply(self, session, desired, previous, *, full=True):
|
|
168
168
|
q = mysql_identifier
|
|
169
169
|
with ExitStack() as resources:
|
|
170
170
|
engine = self.backend.catalog.open_engine(self.source, resources)
|
|
@@ -288,7 +288,7 @@ class MSSQLAccess(HostedAccess):
|
|
|
288
288
|
)
|
|
289
289
|
return {(schema, name, referential_action(delete), referential_action(update)) for schema, name, delete, update in rows}
|
|
290
290
|
|
|
291
|
-
def apply(self, session, desired, previous):
|
|
291
|
+
def apply(self, session, desired, previous, *, full=True):
|
|
292
292
|
connection = session.connection()
|
|
293
293
|
connection.engine.hide_parameters = True
|
|
294
294
|
q = ms_identifier
|
|
@@ -5,7 +5,7 @@ from contextlib import contextmanager
|
|
|
5
5
|
|
|
6
6
|
from sqlalchemy import text
|
|
7
7
|
|
|
8
|
-
from metatables.api.backend.backends.access import DatabaseAccess
|
|
8
|
+
from metatables.api.backend.backends.access import DatabaseAccess, manifest_changes
|
|
9
9
|
from metatables.api.backend.backends.contracts import SQLExecutionError
|
|
10
10
|
from metatables.api.backend.persistence.models import SQLSecurityState
|
|
11
11
|
|
|
@@ -24,6 +24,8 @@ USER_SCHEMA = "{schema} !~ '^pg_' AND {schema} <> 'information_schema'"
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class PostgreSQLAccess(DatabaseAccess):
|
|
27
|
+
incremental = True
|
|
28
|
+
|
|
27
29
|
def prerequisite_problems(self, connection):
|
|
28
30
|
schema = getattr(self.source.connection, "default_schema", None) or "public"
|
|
29
31
|
login, database, creates_roles, creates_schemas, catalog_owner, tables = connection.execute(text(
|
|
@@ -229,82 +231,84 @@ class PostgreSQLAccess(DatabaseAccess):
|
|
|
229
231
|
targets.add((*hypertable, delete, update))
|
|
230
232
|
return targets
|
|
231
233
|
|
|
232
|
-
def
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
return
|
|
234
|
+
def object_fingerprint(self, connection):
|
|
235
|
+
"""What the routine sweep secures: owned schemas and routines, and PUBLIC grants.
|
|
236
|
+
|
|
237
|
+
A change to any of them, such as a migration that adds a routine or grants
|
|
238
|
+
to PUBLIC, makes the next reconciliation sweep them again.
|
|
239
|
+
"""
|
|
240
|
+
schemas = USER_SCHEMA.format(schema="n.nspname")
|
|
241
|
+
return connection.execute(text(
|
|
242
|
+
"SELECT md5(concat_ws('|', "
|
|
243
|
+
"(SELECT string_agg(n.oid::text, ',' ORDER BY n.oid) FROM pg_namespace n WHERE "
|
|
244
|
+
+ schemas + " AND " + OWNED.format(owner="n.nspowner") + "), "
|
|
245
|
+
"(SELECT string_agg(p.oid::text || ':' || p.prosecdef::text, ',' ORDER BY p.oid) "
|
|
246
|
+
"FROM pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace WHERE "
|
|
247
|
+
+ schemas + " AND " + OWNED.format(owner="p.proowner") + "), "
|
|
248
|
+
"(SELECT count(*)::text FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace "
|
|
249
|
+
"CROSS JOIN LATERAL aclexplode(c.relacl) acl WHERE acl.grantee=0 AND "
|
|
250
|
+
+ schemas + " AND " + OWNED.format(owner="c.relowner") + "), "
|
|
251
|
+
"(SELECT count(*)::text FROM pg_attribute a JOIN pg_class c ON c.oid=a.attrelid "
|
|
252
|
+
"JOIN pg_namespace n ON n.oid=c.relnamespace CROSS JOIN LATERAL aclexplode(a.attacl) acl "
|
|
253
|
+
"WHERE acl.grantee=0 AND n.nspname !~ '^pg_' AND " + OWNED.format(owner="c.relowner") + ")"
|
|
254
|
+
"))"
|
|
255
|
+
)).scalar()
|
|
256
|
+
|
|
257
|
+
def reconcile(self, session, *, inspect_objects=False, tables=None):
|
|
258
|
+
state = session.get(SQLSecurityState, 1)
|
|
259
|
+
manifest = (state.manifest if state else None) or {}
|
|
260
|
+
connection = session.connection()
|
|
261
|
+
objects = self.object_fingerprint(connection)
|
|
262
|
+
if inspect_objects or manifest.get("objects") != objects:
|
|
263
|
+
roles = set(self.plan(session)["roles"]) | set(manifest.get("roles", {}))
|
|
264
|
+
self.secure_routines(connection, roles)
|
|
265
|
+
objects = self.object_fingerprint(connection)
|
|
266
|
+
super().reconcile(session, inspect_objects=inspect_objects, tables=tables)
|
|
267
|
+
state = session.get(SQLSecurityState, 1)
|
|
268
|
+
state.manifest = {**state.manifest, "objects": objects}
|
|
269
|
+
session.flush()
|
|
240
270
|
|
|
241
|
-
def apply(self, session, desired, previous):
|
|
271
|
+
def apply(self, session, desired, previous, *, full=True):
|
|
242
272
|
connection = session.connection()
|
|
243
273
|
connection.engine.hide_parameters = True
|
|
244
|
-
roles = desired["roles"]
|
|
245
274
|
invoker = self.role("invoker", "routines")
|
|
246
|
-
self._role(connection, invoker)
|
|
247
275
|
database = connection.exec_driver_sql("SELECT current_database()").scalar()
|
|
276
|
+
changes = None if full else manifest_changes(previous, desired)
|
|
277
|
+
if changes is None:
|
|
278
|
+
return self._apply_all(connection, desired, previous, database=database, invoker=invoker)
|
|
279
|
+
roles = desired["roles"]
|
|
280
|
+
for name in sorted(changes.reset):
|
|
281
|
+
self._role(connection, name, self.password(name) if roles[name]["login"] else None)
|
|
282
|
+
for name in sorted(changes.reset | changes.retired):
|
|
283
|
+
login = name in roles and bool(roles[name]["login"])
|
|
284
|
+
self._reset_role(connection, name, login=login, database=database, invoker=invoker)
|
|
285
|
+
for member, parent in changes.revoke_memberships:
|
|
286
|
+
connection.exec_driver_sql(f"REVOKE {quote(parent)} FROM {quote(member)}")
|
|
287
|
+
for name, schema, table, _ in changes.revoke_privileges:
|
|
288
|
+
relation = f"{quote(schema)}.{quote(table)}"
|
|
289
|
+
# A dropped table took its grants with it.
|
|
290
|
+
if connection.execute(text("SELECT to_regclass(:relation) IS NOT NULL"), {"relation": relation}).scalar():
|
|
291
|
+
connection.exec_driver_sql(f"REVOKE ALL ON TABLE {relation} FROM {quote(name)}")
|
|
292
|
+
for name, schema in changes.revoke_schemas:
|
|
293
|
+
if connection.execute(text("SELECT to_regnamespace(:schema) IS NOT NULL"), {"schema": quote(schema)}).scalar():
|
|
294
|
+
connection.exec_driver_sql(f"REVOKE USAGE ON SCHEMA {quote(schema)} FROM {quote(name)}")
|
|
295
|
+
for member, parent in changes.grant_memberships:
|
|
296
|
+
connection.exec_driver_sql(f"GRANT {quote(parent)} TO {quote(member)}")
|
|
297
|
+
for schema in sorted({schema for _, schema, _, _ in changes.grant_privileges} - {"metatables"}):
|
|
298
|
+
connection.exec_driver_sql(f"GRANT USAGE ON SCHEMA {quote(schema)} TO {quote(invoker)}")
|
|
299
|
+
self._grant_privileges(connection, changes.grant_privileges)
|
|
300
|
+
|
|
301
|
+
def _apply_all(self, connection, desired, previous, *, database, invoker):
|
|
302
|
+
"""The full rebuild: every role is reset and granted again, repairing drift."""
|
|
303
|
+
roles = desired["roles"]
|
|
304
|
+
self._role(connection, invoker)
|
|
248
305
|
for name, definition in roles.items():
|
|
249
306
|
self._role(connection, name, self.password(name) if definition["login"] else None)
|
|
250
307
|
names = set(roles) | set(previous.get("roles", {})) | {invoker}
|
|
251
308
|
schemas = self.owned_schemas(connection)
|
|
252
309
|
for name in sorted(names):
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"SELECT 1 FROM pg_class WHERE relowner=(SELECT oid FROM pg_roles WHERE rolname=:name) UNION ALL SELECT 1 FROM pg_namespace WHERE nspowner=(SELECT oid FROM pg_roles WHERE rolname=:name) UNION ALL SELECT 1 FROM pg_proc WHERE proowner=(SELECT oid FROM pg_roles WHERE rolname=:name) UNION ALL SELECT 1 FROM pg_database WHERE datdba=(SELECT oid FROM pg_roles WHERE rolname=:name)"
|
|
256
|
-
),
|
|
257
|
-
{"name": name},
|
|
258
|
-
).first()
|
|
259
|
-
if owned:
|
|
260
|
-
raise SQLExecutionError(code="sql_principal_permission_drift")
|
|
261
|
-
# Repair inherited drift as well as direct table privileges.
|
|
262
|
-
parents = (
|
|
263
|
-
connection.execute(
|
|
264
|
-
text(
|
|
265
|
-
"SELECT parent.rolname FROM pg_auth_members m JOIN pg_roles child ON child.oid=m.member JOIN pg_roles parent ON parent.oid=m.roleid WHERE child.rolname=:name"
|
|
266
|
-
),
|
|
267
|
-
{"name": name},
|
|
268
|
-
)
|
|
269
|
-
.scalars()
|
|
270
|
-
.all()
|
|
271
|
-
)
|
|
272
|
-
for parent in parents:
|
|
273
|
-
connection.exec_driver_sql(f"REVOKE {quote(parent)} FROM {quote(name)}")
|
|
274
|
-
connection.exec_driver_sql(
|
|
275
|
-
f"REVOKE ALL ON DATABASE {quote(database)} FROM {quote(name)}"
|
|
276
|
-
)
|
|
277
|
-
# Revoke this role's grants on owned objects; other owners' grants are theirs.
|
|
278
|
-
granted = connection.execute(
|
|
279
|
-
text(
|
|
280
|
-
"SELECT 'SCHEMA', quote_ident(n.nspname) FROM pg_namespace n CROSS JOIN LATERAL aclexplode(n.nspacl) acl "
|
|
281
|
-
"JOIN pg_roles r ON r.oid=acl.grantee WHERE r.rolname=:name AND " + OWNED.format(owner="n.nspowner")
|
|
282
|
-
+ " UNION SELECT CASE WHEN c.relkind='S' THEN 'SEQUENCE' ELSE 'TABLE' END, "
|
|
283
|
-
"quote_ident(n.nspname) || '.' || quote_ident(c.relname) FROM pg_class c "
|
|
284
|
-
"JOIN pg_namespace n ON n.oid=c.relnamespace CROSS JOIN LATERAL aclexplode(c.relacl) acl "
|
|
285
|
-
"JOIN pg_roles r ON r.oid=acl.grantee WHERE r.rolname=:name AND " + OWNED.format(owner="c.relowner")
|
|
286
|
-
),
|
|
287
|
-
{"name": name},
|
|
288
|
-
).all()
|
|
289
|
-
for kind, target in granted:
|
|
290
|
-
connection.exec_driver_sql(f"REVOKE ALL ON {kind} {target} FROM {quote(name)}")
|
|
291
|
-
# Table-level REVOKE does not remove separately granted column ACLs.
|
|
292
|
-
columns = connection.execute(
|
|
293
|
-
text(
|
|
294
|
-
"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 "
|
|
295
|
-
+ OWNED.format(owner="c.relowner")
|
|
296
|
-
),
|
|
297
|
-
{"name": name},
|
|
298
|
-
).all()
|
|
299
|
-
for schema, table, column in columns:
|
|
300
|
-
connection.exec_driver_sql(
|
|
301
|
-
f"REVOKE ALL ({quote(column)}) ON TABLE {quote(schema)}.{quote(table)} FROM {quote(name)}"
|
|
302
|
-
)
|
|
303
|
-
if name in roles and roles[name]["login"]:
|
|
304
|
-
connection.exec_driver_sql(
|
|
305
|
-
f"GRANT CONNECT ON DATABASE {quote(database)} TO {quote(name)}"
|
|
306
|
-
)
|
|
307
|
-
connection.exec_driver_sql(f"GRANT {quote(invoker)} TO {quote(name)}")
|
|
310
|
+
login = name in roles and bool(roles[name]["login"])
|
|
311
|
+
self._reset_role(connection, name, login=login, database=database, invoker=invoker)
|
|
308
312
|
for schema in schemas:
|
|
309
313
|
if schema != "metatables":
|
|
310
314
|
connection.exec_driver_sql(
|
|
@@ -312,13 +316,74 @@ class PostgreSQLAccess(DatabaseAccess):
|
|
|
312
316
|
)
|
|
313
317
|
for member, parent in desired["memberships"]:
|
|
314
318
|
connection.exec_driver_sql(f"GRANT {quote(parent)} TO {quote(member)}")
|
|
315
|
-
|
|
319
|
+
self._grant_privileges(connection, desired["privileges"])
|
|
320
|
+
|
|
321
|
+
def _grant_privileges(self, connection, privileges):
|
|
322
|
+
for name, schema, table, write in privileges:
|
|
316
323
|
connection.exec_driver_sql(f"GRANT USAGE ON SCHEMA {quote(schema)} TO {quote(name)}")
|
|
317
324
|
permissions = "SELECT, INSERT, UPDATE, DELETE" if write else "SELECT"
|
|
318
325
|
connection.exec_driver_sql(
|
|
319
326
|
f"GRANT {permissions} ON TABLE {quote(schema)}.{quote(table)} TO {quote(name)}"
|
|
320
327
|
)
|
|
321
328
|
|
|
329
|
+
def _reset_role(self, connection, name, *, login, database, invoker):
|
|
330
|
+
"""Leave ``name`` with only CONNECT and the routine invoker, if it logs in."""
|
|
331
|
+
owned = connection.execute(
|
|
332
|
+
text(
|
|
333
|
+
"SELECT 1 FROM pg_class WHERE relowner=(SELECT oid FROM pg_roles WHERE rolname=:name) UNION ALL SELECT 1 FROM pg_namespace WHERE nspowner=(SELECT oid FROM pg_roles WHERE rolname=:name) UNION ALL SELECT 1 FROM pg_proc WHERE proowner=(SELECT oid FROM pg_roles WHERE rolname=:name) UNION ALL SELECT 1 FROM pg_database WHERE datdba=(SELECT oid FROM pg_roles WHERE rolname=:name)"
|
|
334
|
+
),
|
|
335
|
+
{"name": name},
|
|
336
|
+
).first()
|
|
337
|
+
if owned:
|
|
338
|
+
raise SQLExecutionError(code="sql_principal_permission_drift")
|
|
339
|
+
# Repair inherited drift as well as direct table privileges.
|
|
340
|
+
parents = (
|
|
341
|
+
connection.execute(
|
|
342
|
+
text(
|
|
343
|
+
"SELECT parent.rolname FROM pg_auth_members m JOIN pg_roles child ON child.oid=m.member JOIN pg_roles parent ON parent.oid=m.roleid WHERE child.rolname=:name"
|
|
344
|
+
),
|
|
345
|
+
{"name": name},
|
|
346
|
+
)
|
|
347
|
+
.scalars()
|
|
348
|
+
.all()
|
|
349
|
+
)
|
|
350
|
+
for parent in parents:
|
|
351
|
+
connection.exec_driver_sql(f"REVOKE {quote(parent)} FROM {quote(name)}")
|
|
352
|
+
connection.exec_driver_sql(
|
|
353
|
+
f"REVOKE ALL ON DATABASE {quote(database)} FROM {quote(name)}"
|
|
354
|
+
)
|
|
355
|
+
# Revoke this role's grants on owned objects; other owners' grants are theirs.
|
|
356
|
+
granted = connection.execute(
|
|
357
|
+
text(
|
|
358
|
+
"SELECT 'SCHEMA', quote_ident(n.nspname) FROM pg_namespace n CROSS JOIN LATERAL aclexplode(n.nspacl) acl "
|
|
359
|
+
"JOIN pg_roles r ON r.oid=acl.grantee WHERE r.rolname=:name AND " + OWNED.format(owner="n.nspowner")
|
|
360
|
+
+ " UNION SELECT CASE WHEN c.relkind='S' THEN 'SEQUENCE' ELSE 'TABLE' END, "
|
|
361
|
+
"quote_ident(n.nspname) || '.' || quote_ident(c.relname) FROM pg_class c "
|
|
362
|
+
"JOIN pg_namespace n ON n.oid=c.relnamespace CROSS JOIN LATERAL aclexplode(c.relacl) acl "
|
|
363
|
+
"JOIN pg_roles r ON r.oid=acl.grantee WHERE r.rolname=:name AND " + OWNED.format(owner="c.relowner")
|
|
364
|
+
),
|
|
365
|
+
{"name": name},
|
|
366
|
+
).all()
|
|
367
|
+
for kind, target in granted:
|
|
368
|
+
connection.exec_driver_sql(f"REVOKE ALL ON {kind} {target} FROM {quote(name)}")
|
|
369
|
+
# Table-level REVOKE does not remove separately granted column ACLs.
|
|
370
|
+
columns = connection.execute(
|
|
371
|
+
text(
|
|
372
|
+
"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 "
|
|
373
|
+
+ OWNED.format(owner="c.relowner")
|
|
374
|
+
),
|
|
375
|
+
{"name": name},
|
|
376
|
+
).all()
|
|
377
|
+
for schema, table, column in columns:
|
|
378
|
+
connection.exec_driver_sql(
|
|
379
|
+
f"REVOKE ALL ({quote(column)}) ON TABLE {quote(schema)}.{quote(table)} FROM {quote(name)}"
|
|
380
|
+
)
|
|
381
|
+
if login:
|
|
382
|
+
connection.exec_driver_sql(
|
|
383
|
+
f"GRANT CONNECT ON DATABASE {quote(database)} TO {quote(name)}"
|
|
384
|
+
)
|
|
385
|
+
connection.exec_driver_sql(f"GRANT {quote(invoker)} TO {quote(name)}")
|
|
386
|
+
|
|
322
387
|
@contextmanager
|
|
323
388
|
def connection(self, identity, *, write, timeout):
|
|
324
389
|
import psycopg
|
|
@@ -10,6 +10,8 @@ from metatables.api.backend.persistence.models import Base, SQLSecurityState
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class SQLiteAccess(DatabaseAccess):
|
|
13
|
+
incremental = True
|
|
14
|
+
|
|
13
15
|
def submit(self, cursor, statement, parameters):
|
|
14
16
|
cursor.execute(statement, parameters)
|
|
15
17
|
|
|
@@ -75,7 +77,7 @@ class SQLiteAccess(DatabaseAccess):
|
|
|
75
77
|
)
|
|
76
78
|
return targets
|
|
77
79
|
|
|
78
|
-
def apply(self, session, desired, previous):
|
|
80
|
+
def apply(self, session, desired, previous, *, full=True):
|
|
79
81
|
# The immutable grant snapshot is installed on each dedicated connection.
|
|
80
82
|
return None
|
|
81
83
|
|