mainsequence-metatable 0.1.51.dev80__tar.gz → 0.1.52__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.51.dev80 → mainsequence_metatable-0.1.52}/.mainsequence/workflows/metatables-api.yaml +13 -0
- {mainsequence_metatable-0.1.51.dev80/src/mainsequence_metatable.egg-info → mainsequence_metatable-0.1.52}/PKG-INFO +1 -1
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/deploy-application-migrations.md +3 -1
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/operations/recovery-and-observability.md +5 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/security/index.md +5 -1
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/pyproject.toml +1 -1
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52/src/mainsequence_metatable.egg-info}/PKG-INFO +1 -1
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/auth/team_membership.py +34 -8
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/platform_cache.py +2 -1
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/managed_finalize.py +92 -58
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_registration.py +6 -3
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/domain/permission_rules.py +16 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/finalize_managed.py +33 -10
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/register_catalog.py +10 -4
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/projections.py +25 -11
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_platform_fact_cache.py +1 -1
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_team_membership.py +42 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_application_owned_migrations.py +17 -10
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_managed_finalize_unchanged.py +69 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/operations/test_register_catalog.py +49 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/uv.lock +1 -1
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/analyze-with-sql/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/client/metatables-local-development/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/client/metatables-meta-tables/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/client/metatables-migrations/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/client/metatables-table-discovery/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/client/metatables-time-index-table-updates/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/discover-tables/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/ms_tau_sdk/PINNED_FROM.txt +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/ms_tau_sdk/tau_a2a_runtime_adapter/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/ms_tau_sdk/tau_local_development/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/ms_tau_sdk/tau_project_customization/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/ms_tau_sdk/tau_repository_integration/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/.agents/skills/ms_tau_sdk/tau_security_and_access/SKILL.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/LICENSE +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/MANIFEST.in +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/alembic.ini +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/api/metatables/main.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/compose.database-tests.yml +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/agent/0019-metatables-analyst-agent.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/agent/0020-analyst-reads-as-its-requester.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/agent/0021-api-serves-the-analyst-tools-over-mcp.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0001-unified-api-storage-and-local-sqlite.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0002-application-administration-and-table-ownership.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0004-approved-application-migrations.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0005-run-logs-and-local-file-capture.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0006-historical-run-graphs.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0007-database-enforced-table-access.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0007-database-roles-and-privileges.svg +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0007-query-enforcement-path.svg +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0008-mysql-mssql-table-workflows.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0009-shared-credential-store.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0010-import-external-tables-and-views.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0012-bounded-data-transfer-and-safe-retries.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0013-application-owned-migrations.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0014-main-sequence-release-jobs-and-production-migrations.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0015-timescale-compression-and-retention-policies.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0016-impact-preflight.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0017-hosted-request-identity.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0018-search-document-pipeline.svg +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0018-table-search.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0022-concurrent-requests-and-connection-reuse.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0023-daily-security-check.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/api/0024-namespace-and-table-access-roles.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/client/0003-api-endpoint-resolution.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/client/0011-cli-local-development-with-managed-admin.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/adr/index.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/api/authentication-and-errors.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/api/data-sources.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/api/openapi.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/api/overview.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/api/reference.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/api/tables-and-migrations.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/api/time-index-and-updates.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/assets/branding/metatables.svg +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/assets/diagrams/local-client-experience.svg +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/assets/diagrams/namespace-access.svg +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/bounded-transfers.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/build-an-updater.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/define-and-migrate-tables.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/installation-and-connection.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/local-storage.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/query-and-mutate.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/quickstart.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/read-existing-time-index-tables.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/register-existing-tables.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/tutorial.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/client/upgrade-legacy-app.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/concepts/architecture.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/concepts/data-sources.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/concepts/identity-and-scope.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/concepts/permissions-namespaces-labels.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/concepts/runs-and-execution-graphs.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/concepts/table-contracts-and-lifecycle.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/concepts/time-index-tables-and-updates.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/contributing/architecture-and-boundaries.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/contributing/database-backends.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/contributing/documentation.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/contributing/releasing.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/contributing/testing.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/bounded_reader.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/data_sources/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/data_sources/mssql.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/data_sources/mysql.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/data_sources/postgresql.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/data_sources/register.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/external_table.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/local_app/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/local_app/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/local_app/__main__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/local_app/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/local_app/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/local_app/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/local_app/migrations/versions/metatables_local_example/0001.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/local_app/tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/query.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/quickstart.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/reader.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/scripts/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/scripts/setup_metatables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/__main__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/data/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/data/yahoo_spy_qqq_iwm_2026-06-15_2026-07-17.csv +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/frames.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/migrations/registry.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/migrations/versions/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/0001_create_market_tutorial_tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/0002_create_rolling_volatility.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/migrations/versions/metatables_market_tutorial/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/operations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/tutorial/updaters.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/examples/updater.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/index.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/operations/catalog-migrations.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/operations/configuration.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/operations/hosted-runtime.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/operations/local-runtime.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/operations/run-history.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/operations/run-logs.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/reference/capabilities.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/reference/cli.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/reference/python.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/security/ownership-and-sharing.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/security/permissions.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/mkdocs.yml +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/build_reference.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/check_boundaries.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/check_client_api_coverage.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/check_distribution_sources.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/check_docs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/check_examples_debug.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/check_project.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/dev_release_version.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/test_databases.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/scripts/test_postgresql.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/setup.cfg +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/mainsequence_metatable.egg-info/SOURCES.txt +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/mainsequence_metatable.egg-info/dependency_links.txt +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/mainsequence_metatable.egg-info/entry_points.txt +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/mainsequence_metatable.egg-info/requires.txt +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/mainsequence_metatable.egg-info/top_level.txt +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/_admin_source.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/_build.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/_skill_bundle.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/analysis.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/analyst/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/auth/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/auth/boundary.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/auth/local_actor.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/bootstrap.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/configuration.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/connection_count.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/credential_admin.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/development.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/development_client.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/error_logging.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/main.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/mcp.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/access_map.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/caller.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/column_search.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/contract_validation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/data_sources.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/migration_connection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/namespaces.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/run_logs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/runtime_context.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/schema_graph.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/security.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_cascade.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_crud.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_delete.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_filter.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_import.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_introspection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_patch.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_response.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_search.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_search_document.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_sql.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/table_update_pipeline.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/time_index_delete.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/time_index_reads.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/time_index_stats.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/timescale_policies.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_batch.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_chunk_insert.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_constants.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_crud.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_details.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_graph.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_index_statistics.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_registration.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_runs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/routes/update_statistics.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/runtime.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/runtime_control.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/runtime_database.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/source_passwords.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/app/transfer.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/access.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/maintenance/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/maintenance/postgresql.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/maintenance/runtime.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/maintenance/temporal.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/maintenance/timescaledb.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/maintenance/validation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_cascade_delete.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_connection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_introspection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_table_delete.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_time_index.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_time_index_delete.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_time_index_queries.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_time_index_stats.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/postgresql_time_index_write.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/source_validation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/sqlite_connection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/sqlite_introspection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/adapters/table_cursor.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/batch_inspection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/catalog.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/catalog_ddl.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/catalog_types.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/connection_pool.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/contracts.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/hosted.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/hosted_access.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/migration_connection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/native.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/operations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/pages.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/postgresql_access.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/registry.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/relation_tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/relational.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/restricted_sql.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/sqlite_access.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/streaming.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/backends/timescale.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/contracts/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/contracts/relation_import.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/contracts/storage_layouts.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/contracts/table_contracts.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/contracts/values.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/domain/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/domain/access_roles.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/domain/catalog_rules.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/domain/data_source_rules.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/domain/index_statistics.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/domain/label_rules.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/domain/update_constants.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/catalog_data_sources.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/credential_keys.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/credential_store.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/data_source_provider.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/local_credentials.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/local_workspace.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/platform_principals.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/run_logs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/runtime_binding.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/runtime_data_sources.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/security_check_job.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/integrations/source_validation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0001_initial.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0002_security_model.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0003_run_log_capture.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0004_historical_run_graphs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0005_database_access.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0006_local_credentials.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0007_external_relation_names.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0008_upload_receipts.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0009_timescale_policies.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0010_cascade_targets.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0011_table_search.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0012_table_creator.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0013_security_check.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0014_access_roles.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/0015_namespace_creator.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/migrations/versions/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/bootstrap_migrations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/bootstrap_timing.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/catalog_schema.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/create_table.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/import_relations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/introspect_table.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/read_time_index.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/operations/security_check.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/cascade.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/catalog.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/database.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/grants.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/impact.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/labels.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/locking.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/models.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/physical_operations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/run_graphs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/schema_graph.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/sqlite_types.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/table_body_filter.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/table_queries.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/table_response.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/update_graph.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/update_pipeline.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/updates.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/persistence/upload_receipts.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/presentation/data_source_summary.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/search/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/search/documents.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/search/embeddings.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/search/index.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/search/ranking.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/search/text.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/backend/search/worker.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/metatables/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/metatables/configuration.yaml +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/metatables/main.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/api/request_timing.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/cli/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/cli/admin_install.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/cli/app.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/cli/filters.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/cli/local.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/cli/migrations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/cli/project.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/cli/skills.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/compiled_sql/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/compiled_sql/mssql.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/compiled_sql/v1.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/dtype_codec.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/endpoint.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/bounded_reader.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/data_sources/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/data_sources/mssql.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/data_sources/mysql.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/data_sources/postgresql.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/data_sources/register.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/external_table.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/local_app/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/local_app/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/local_app/__main__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/local_app/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/local_app/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/local_app/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/local_app/migrations/versions/metatables_local_example/0001.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/local_app/tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/query.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/quickstart.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/reader.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/scripts/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/scripts/setup_metatables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/__main__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/data/README.md +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/data/yahoo_spy_qqq_iwm_2026-06-15_2026-07-17.csv +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/frames.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/migrations/registry.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/migrations/script.py.mako +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/migrations/versions/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/0001_create_market_tutorial_tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/0002_create_rolling_volatility.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/migrations/versions/metatables_market_tutorial/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/operations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/tutorial/updaters.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/examples/updater.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/future_registry.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/hashing.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/instrumentation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/local_connection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/local_files.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/local_run_logs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/log_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/alembic.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/connection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/env.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/provider.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/registry.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/runner.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/scaffold.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/sqlite.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/templates/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/templates/env.py.mako +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/templates/script.py.mako +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/migrations/tls.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/models.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/pydantic_metadata.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/run_logging.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/runtime.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/runtime_context.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/runtime_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/schema_names.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/sdk_compat.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/sqlalchemy_contracts.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/storage_layout_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/time_index_table_refs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/transfer.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/transfer_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/transport.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/update_configuration_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/updaters/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/updaters/configuration.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/updaters/dependencies.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/updaters/managers.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/updaters/namespacing.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/updaters/runner.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/updaters/updaters.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/updaters/utils.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/src/metatables/upload.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/analyst/test_agent_surface.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/analyst/test_api_search.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/analyst/test_mcp.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/analyst/test_tools.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_bootstrap_failure_cause.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_caller_endpoint.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_data_source_identity.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_development_client.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_hosted_agent.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_hosted_environment_target.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_local_mode.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_request_identity.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_runtime_bootstrap.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_runtime_database.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_runtime_scaffold.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_runtime_selection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_runtime_storage_binding.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/auth/test_source_passwords.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/catalog/test_catalog_foundation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/catalog/test_contract_projection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/catalog/test_database_config.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/catalog/test_index_statistics.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/catalog/test_migration.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/catalog/test_schema_validation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/conftest.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/capabilities.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/client_signatures.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/database_operations.json +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/test_bounded_transfer.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/test_compiler_runtime_source.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/test_relation_batching.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/test_relation_import.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/test_runtime_contract_compat.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/test_storage_layouts.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/contracts/test_table_contracts.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/Dockerfile +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/Dockerfile.dockerignore +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/conftest.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/provider/__init__.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/provider/env.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/provider/versions/0001_measurement.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_api_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_application_migration.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_bootstrap_recovery.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_catalog_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_credential_catalog.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_physical_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_relation_import.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_runtime_bootstrap.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_sql_security.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_backend/test_update_client.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_operations/test_physical_operations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_operations/test_postgresql_operations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/database_operations/test_runtime_and_temporal.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/documentation/test_project_checks.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_admin_installation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_api_endpoint.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_catalog_outage.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_client_api_contract.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_client_api_coverage.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_client_migration_scaffold.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_client_migration_tls.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_client_package.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_client_signatures.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_client_value_behaviors.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_data_source_registry.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_local_actor_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_local_cli_workflow.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_local_client_selection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_managed_finalize_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_migration_metadata_and_downgrade.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_namespaces_admin_http.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_public_imports.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_remaining_client_routes.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_run_graphs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_run_logs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_runtime_upgrade.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_sdk_local_startup.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_sqlite_runtime.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_delete_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_filter_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_introspection_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_patch_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_search_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_search_document_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_search_scale.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_stats_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_update_pipeline.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_table_updates_http.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_time_index_delete_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_time_index_reads_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_timescale_policies_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_update_batch_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_update_chunk_insert_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_update_dependency_priority_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_update_index_statistics_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/e2e/test_update_registration_client_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/examples/test_documented_examples.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/examples/test_postgresql_examples.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/examples/test_setup_launch.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/examples/test_tutorial.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_batch_introspection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_connection_reuse.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_credential_store.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_data_source_rules.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_local_data_sources.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_local_run_logs.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_postgresql_connection.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_postgresql_sql.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_postgresql_tables.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_postgresql_time_index_queries.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_request_timing.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_serving_policy.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_source_validation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/integrations/test_sqlite_operations.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/labels/test_labels.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/operations/test_bootstrap_lock.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/operations/test_create_table_operation.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/operations/test_create_table_postgres.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/operations/test_physical_operation_journal.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/operations/test_search_documents.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/operations/test_timescale_policies.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/packaging/test_client_skills.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/packaging/test_dev_release_version.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/packaging/test_distribution_sources.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/packaging/test_editable_build.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/packaging/test_installed_distribution.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_access_map.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_deployment_security.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_governed_sql_scope.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_incremental_security.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_local_actor_membership.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_migration_boundary.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_namespace_grants.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_security_api.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_security_check.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_table_body_filter.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_table_grants.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_table_queries.py +0 -0
- {mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/tests/permissions/test_workload_principals.py +0 -0
|
@@ -40,6 +40,19 @@ resources:
|
|
|
40
40
|
kind: harness_agent
|
|
41
41
|
spec:
|
|
42
42
|
source_path: api/tau/main.py
|
|
43
|
+
command_center_icon:
|
|
44
|
+
path: assets/agents/grid/idle.png
|
|
45
|
+
rendering: color
|
|
46
|
+
image_rendering: pixelated
|
|
47
|
+
command_center_animations:
|
|
48
|
+
poses:
|
|
49
|
+
thinking: {path: assets/agents/grid/thinking.png}
|
|
50
|
+
working: {path: assets/agents/grid/working.png}
|
|
51
|
+
querying: {path: assets/agents/grid/querying.png}
|
|
52
|
+
error: {path: assets/agents/grid/error.png}
|
|
53
|
+
tools:
|
|
54
|
+
- application: metatables
|
|
55
|
+
pose: querying
|
|
43
56
|
llm_provider: openai-codex
|
|
44
57
|
llm_model: gpt-5.6-luna
|
|
45
58
|
llm_thinking: medium
|
|
@@ -207,7 +207,9 @@ the database.
|
|
|
207
207
|
- **`table_not_editable`**: the table already exists and the caller lacks
|
|
208
208
|
`tables.update` on it. An owner of the table or its namespace grants `editor`.
|
|
209
209
|
|
|
210
|
-
After the grant,
|
|
210
|
+
After the grant, or after adding the workload User to a Team that holds the role,
|
|
211
|
+
re-run the Job. A refusal is rechecked against current Team membership before it
|
|
212
|
+
stands, so the re-run needs no wait. Do not run the Job as an Organization admin
|
|
211
213
|
or change physical names to get around a refusal.
|
|
212
214
|
|
|
213
215
|
## What the Job guarantees
|
|
@@ -17,6 +17,11 @@ per-table finalization result, physical schema, provider identity, and registry
|
|
|
17
17
|
state. Reuse only a compatible registry resolved by physical identity. Preserve
|
|
18
18
|
Alembic's applied history; write new revisions for further changes.
|
|
19
19
|
|
|
20
|
+
The API logs each `finalize-managed` batch's phases: `physical inspection`,
|
|
21
|
+
`reconciling N tables (M with catalog writes)`, `commit and security refresh`, and
|
|
22
|
+
the total. An already-current run reads the catalog a fixed number of times per
|
|
23
|
+
batch, however many tables it holds, and writes nothing (`0 with catalog writes`).
|
|
24
|
+
|
|
20
25
|
## Failed security check
|
|
21
26
|
|
|
22
27
|
The daily security check ([ADR 0023](../adr/api/0023-daily-security-check.md)) records
|
{mainsequence_metatable-0.1.51.dev80 → mainsequence_metatable-0.1.52}/docs/security/index.md
RENAMED
|
@@ -117,7 +117,11 @@ to. Each pod reuses an answer for 24 hours, so a person removed from a Team can
|
|
|
117
117
|
keep reading through that Team's grants for up to a day. Writes act on an answer
|
|
118
118
|
at most a minute old. Migration credentials, table deletion, finalization and
|
|
119
119
|
permission changes always ask the platform at once, and a login's database role
|
|
120
|
-
memberships change only on such a fresh answer. A
|
|
120
|
+
memberships change only on such a fresh answer. A table registration that would be
|
|
121
|
+
refused asks the platform at once before it refuses, so a workload just added to a
|
|
122
|
+
Team is accepted on its next run. A fresh answer also rereads which Teams the
|
|
123
|
+
grants name, so a Team granted through another API pod counts at once; otherwise a
|
|
124
|
+
pod learns of it within a minute. A failed check fails the request;
|
|
121
125
|
it never counts as "not a member". Local admission resolves facts for the running SDK user,
|
|
122
126
|
whose platform User response must supply `is_organization_admin` and
|
|
123
127
|
`active_team_uids`.
|
|
@@ -9,7 +9,11 @@ request does:
|
|
|
9
9
|
can keep reading through that team's grants for up to 24 hours;
|
|
10
10
|
- data and SQL writes accept an answer at most a minute old;
|
|
11
11
|
- issuing migration credentials, deleting tables, finalizing and changing
|
|
12
|
-
permissions always ask the platform now
|
|
12
|
+
permissions always ask the platform now;
|
|
13
|
+
- a registration that would be refused asks the platform now before it refuses (#80).
|
|
14
|
+
|
|
15
|
+
Asking now also rereads which teams the grants name, so a team granted on another
|
|
16
|
+
API pod counts at once (#81).
|
|
13
17
|
"""
|
|
14
18
|
|
|
15
19
|
from __future__ import annotations
|
|
@@ -57,8 +61,12 @@ event.listen(Session, "after_commit", _grants_committed)
|
|
|
57
61
|
event.listen(Session, "after_rollback", lambda session: session.info.pop("grant_teams_changed", None))
|
|
58
62
|
|
|
59
63
|
|
|
60
|
-
def grant_teams(request: Request) -> frozenset[str]:
|
|
61
|
-
"""The teams this catalog's grants name; none before a catalog is active.
|
|
64
|
+
def grant_teams(request: Request, *, fresh: bool = False) -> frozenset[str]:
|
|
65
|
+
"""The teams this catalog's grants name; none before a catalog is active.
|
|
66
|
+
|
|
67
|
+
``fresh`` rereads them from the catalog and refreshes this pod's copy: another
|
|
68
|
+
pod may have granted a team since this one cached its set (#81).
|
|
69
|
+
"""
|
|
62
70
|
from metatables.api.app.auth.local_actor import active_catalog_factory
|
|
63
71
|
|
|
64
72
|
factory = active_catalog_factory(request.app)
|
|
@@ -73,21 +81,28 @@ def grant_teams(request: Request) -> frozenset[str]:
|
|
|
73
81
|
with factory() as session:
|
|
74
82
|
return frozenset(str(uid) for uid in session.scalars(query))
|
|
75
83
|
|
|
84
|
+
cache, generation = request.app.state.runtime.grant_teams, _grant_generation
|
|
76
85
|
try:
|
|
77
|
-
|
|
86
|
+
if not fresh:
|
|
87
|
+
return cache.get(generation, load)
|
|
88
|
+
teams = load()
|
|
78
89
|
except Exception as exc:
|
|
79
90
|
raise HTTPException(503, "MetaTables catalog is unavailable.") from exc
|
|
91
|
+
cache.seed(generation, teams, expires_at=cache.clock() + cache.ttl)
|
|
92
|
+
return teams
|
|
80
93
|
|
|
81
94
|
|
|
82
95
|
def team_checker(request: Request, person) -> Callable[[float | None], frozenset[UUID]]:
|
|
83
96
|
"""Ask which of the grant teams ``person`` belongs to, no older than ``max_age``.
|
|
84
97
|
|
|
85
|
-
``None`` reuses the day-long answer
|
|
86
|
-
|
|
98
|
+
``None`` reuses the day-long answer. ``0`` asks the platform now, at most once per
|
|
99
|
+
request, about the teams the catalog's grants name now. Failures fail the request
|
|
100
|
+
and are never read as "not a member".
|
|
87
101
|
"""
|
|
88
|
-
teams =
|
|
102
|
+
teams: frozenset[str] | None = None
|
|
103
|
+
fresh: frozenset[UUID] | None = None
|
|
89
104
|
|
|
90
|
-
def
|
|
105
|
+
def ask(max_age: float | None) -> frozenset[UUID]:
|
|
91
106
|
if not teams:
|
|
92
107
|
return frozenset()
|
|
93
108
|
try:
|
|
@@ -96,6 +111,17 @@ def team_checker(request: Request, person) -> Callable[[float | None], frozenset
|
|
|
96
111
|
raise HTTPException(503, "Team membership is unavailable.") from exc
|
|
97
112
|
return frozenset(UUID(uid) for uid in members)
|
|
98
113
|
|
|
114
|
+
def check(max_age: float | None) -> frozenset[UUID]:
|
|
115
|
+
nonlocal teams, fresh
|
|
116
|
+
if max_age == 0:
|
|
117
|
+
if fresh is None:
|
|
118
|
+
teams = grant_teams(request, fresh=True)
|
|
119
|
+
fresh = ask(0)
|
|
120
|
+
return fresh
|
|
121
|
+
if teams is None:
|
|
122
|
+
teams = grant_teams(request)
|
|
123
|
+
return ask(max_age)
|
|
124
|
+
|
|
99
125
|
return check
|
|
100
126
|
|
|
101
127
|
|
|
@@ -7,7 +7,8 @@ from threading import Lock
|
|
|
7
7
|
from time import monotonic
|
|
8
8
|
|
|
9
9
|
PLATFORM_FACTS_TTL_SECONDS = 60 * 60
|
|
10
|
-
# Other pods see a new team grant within this time; the pod that wrote it
|
|
10
|
+
# Other pods see a new team grant within this time; the pod that wrote it, and any
|
|
11
|
+
# pod checking membership fresh, at once.
|
|
11
12
|
GRANT_TEAMS_SECONDS = 60
|
|
12
13
|
|
|
13
14
|
|
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
+
from collections import defaultdict
|
|
6
7
|
from collections.abc import Callable
|
|
8
|
+
from contextlib import nullcontext
|
|
7
9
|
from time import perf_counter
|
|
8
10
|
from typing import Any
|
|
9
11
|
from uuid import UUID
|
|
10
12
|
|
|
11
13
|
from fastapi import APIRouter, Depends, HTTPException, Response
|
|
12
14
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
13
|
-
from sqlalchemy import delete
|
|
15
|
+
from sqlalchemy import delete, select
|
|
14
16
|
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
|
|
15
17
|
from sqlalchemy.orm import Session
|
|
16
18
|
|
|
@@ -35,7 +37,10 @@ from metatables.api.backend.domain.label_rules import LabelInvariantError, norma
|
|
|
35
37
|
from metatables.api.backend.domain.permission_rules import TrustedActorFacts
|
|
36
38
|
from metatables.api.backend.integrations.data_source_provider import DataSourceProvider
|
|
37
39
|
from metatables.api.backend.integrations.runtime_data_sources import DataSourceIntegrationError
|
|
38
|
-
from metatables.api.backend.operations.finalize_managed import
|
|
40
|
+
from metatables.api.backend.operations.finalize_managed import (
|
|
41
|
+
contract_from_physical_snapshot,
|
|
42
|
+
foreign_key_target_names,
|
|
43
|
+
)
|
|
39
44
|
from metatables.api.backend.operations.register_catalog import time_index_spec_from_contract
|
|
40
45
|
from metatables.api.backend.persistence.grants import GrantRepository
|
|
41
46
|
from metatables.api.backend.persistence.labels import LabelRepository
|
|
@@ -178,15 +183,21 @@ def finalize_managed(
|
|
|
178
183
|
rows = []
|
|
179
184
|
eligible = []
|
|
180
185
|
source_uid = None
|
|
186
|
+
# One query each for the whole batch, never one per table: an unchanged
|
|
187
|
+
# provider pays a round trip per statement (MetaTables #63).
|
|
188
|
+
tables = {table.uid: table for table in session.scalars(
|
|
189
|
+
select(MetaTable).where(MetaTable.uid.in_(requested)).order_by(MetaTable.uid).with_for_update())}
|
|
190
|
+
migratable = set(session.scalars(select(MetaTable.uid).where(
|
|
191
|
+
MetaTable.uid.in_(list(tables)), GrantRepository.table_access_predicate(actor, "tables.migrate"))))
|
|
192
|
+
specializations = {row.meta_table_uid: row for row in session.scalars(
|
|
193
|
+
select(TimeIndexTable).where(TimeIndexTable.meta_table_uid.in_(list(tables))))}
|
|
181
194
|
for uid in requested:
|
|
182
|
-
table =
|
|
183
|
-
if
|
|
184
|
-
table is None or not GrantRepository(session).may_access_table(table_uid=uid, actor=actor, action="tables.migrate")
|
|
185
|
-
):
|
|
195
|
+
table = tables.get(uid)
|
|
196
|
+
if table is None or uid not in migratable:
|
|
186
197
|
rows.append(_row(None, uid, error={"code": "meta_table_not_found", "detail": "MetaTable was not found."}))
|
|
187
198
|
continue
|
|
188
199
|
previous = table.provisioning_status
|
|
189
|
-
specialization =
|
|
200
|
+
specialization = specializations.get(uid)
|
|
190
201
|
if source_uid is None:
|
|
191
202
|
source_uid = table.data_source_uid
|
|
192
203
|
if source_uid != table.data_source_uid or (
|
|
@@ -226,6 +237,16 @@ def finalize_managed(
|
|
|
226
237
|
logger.info("Managed finalization: physical inspection of %s tables took %.3fs",
|
|
227
238
|
len(eligible), perf_counter() - inspection_started)
|
|
228
239
|
projections = load_contract_projections(session, [uid for uid, *_ in eligible])
|
|
240
|
+
# Foreign-key targets and their key columns are read once for the batch (#63).
|
|
241
|
+
registered = defaultdict(list)
|
|
242
|
+
names = set().union(*(foreign_key_target_names(snapshot) for snapshot in snapshots.values()
|
|
243
|
+
if isinstance(snapshot, dict)))
|
|
244
|
+
if names:
|
|
245
|
+
for target in session.scalars(select(MetaTable).where(
|
|
246
|
+
MetaTable.data_source_uid == source_uid, MetaTable.physical_table_name.in_(names))):
|
|
247
|
+
registered[target.physical_table_name].append(target)
|
|
248
|
+
shapes = {}
|
|
249
|
+
reconcile_started, written = perf_counter(), 0
|
|
229
250
|
for uid, table, previous, specialization in eligible:
|
|
230
251
|
try:
|
|
231
252
|
snapshot = snapshots[(table.physical_schema, table.physical_table_name)]
|
|
@@ -258,65 +279,72 @@ def finalize_managed(
|
|
|
258
279
|
"detail": "The table's owner is a role the MetaTables login can't use."}))
|
|
259
280
|
continue
|
|
260
281
|
try:
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
282
|
+
authored = (payload.authored_metadata or {}).get(uid)
|
|
283
|
+
contract = contract_from_physical_snapshot(
|
|
284
|
+
session=session, table=table, snapshot=snapshot,
|
|
285
|
+
authored_metadata=authored.model_dump() if authored else None, registered=registered,
|
|
286
|
+
)
|
|
287
|
+
targets = resolved_foreign_key_targets(
|
|
288
|
+
session, data_source_uid=table.data_source_uid, contract=contract,
|
|
289
|
+
source_table_uid=uid, shapes=shapes,
|
|
290
|
+
)
|
|
291
|
+
replace_projection = not contract_projection_matches(projections[uid], contract, targets)
|
|
292
|
+
updates = {
|
|
293
|
+
"contract_version": contract["version"],
|
|
294
|
+
"physical_schema": contract["physical"]["schema"] or table.physical_schema,
|
|
295
|
+
"provisioning_status": "active",
|
|
296
|
+
"protect_from_deletion": True,
|
|
297
|
+
}
|
|
298
|
+
if authored is not None and authored.description and authored.description.strip():
|
|
299
|
+
updates["description"] = authored.description
|
|
300
|
+
if not same_contract_state(table.table_contract, contract):
|
|
301
|
+
updates["table_contract"] = contract
|
|
302
|
+
if not same_contract_state(table.introspection_snapshot, snapshot):
|
|
303
|
+
updates["introspection_snapshot"] = snapshot
|
|
304
|
+
authoring = contract.get("authoring") or {}
|
|
305
|
+
has_time_profile = (
|
|
306
|
+
contract.get("table_kind") == "time_indexed"
|
|
307
|
+
or isinstance(authoring, dict) and isinstance(authoring.get("time_indexed"), dict)
|
|
308
|
+
)
|
|
309
|
+
new_specialization = None
|
|
310
|
+
if specialization is None and has_time_profile:
|
|
311
|
+
spec = time_index_spec_from_contract({}, contract)
|
|
312
|
+
new_specialization = TimeIndexTable(
|
|
313
|
+
meta_table_uid=uid,
|
|
314
|
+
time_index_name=spec.time_index_name,
|
|
315
|
+
index_names=list(spec.index_names),
|
|
316
|
+
storage_layout=spec.normalized_layout(),
|
|
317
|
+
cadence=spec.cadence,
|
|
270
318
|
)
|
|
271
|
-
|
|
319
|
+
updates["kind"] = "time_index"
|
|
320
|
+
if "alembic_revision" in payload.model_fields_set:
|
|
321
|
+
updates["alembic_revision"] = payload.alembic_revision
|
|
322
|
+
if version_root is not None and uid != version_root:
|
|
323
|
+
updates["alembic_version_meta_table_uid"] = version_root
|
|
324
|
+
# Do not dirty equal-valued rows: pre-flush hooks see assignments
|
|
325
|
+
# before SQLAlchemy decides whether they need an UPDATE.
|
|
326
|
+
changes = {field: value for field, value in updates.items() if getattr(table, field) != value}
|
|
327
|
+
labels = authored.labels if authored is not None else None
|
|
328
|
+
# Only a table with catalog writes needs a savepoint (two round trips).
|
|
329
|
+
writes = bool(replace_projection or changes or labels or new_specialization is not None)
|
|
330
|
+
written += writes
|
|
331
|
+
with session.begin_nested() if writes else nullcontext():
|
|
272
332
|
if replace_projection:
|
|
333
|
+
shapes.clear()
|
|
273
334
|
session.execute(delete(MetaTableForeignKey).where(MetaTableForeignKey.source_table_uid == uid))
|
|
274
335
|
session.execute(delete(MetaTableIndex).where(MetaTableIndex.meta_table_uid == uid))
|
|
275
336
|
session.execute(delete(MetaTableColumn).where(MetaTableColumn.meta_table_uid == uid))
|
|
276
337
|
session.flush()
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
"protect_from_deletion": True,
|
|
282
|
-
}
|
|
283
|
-
if authored is not None:
|
|
284
|
-
if authored.description and authored.description.strip():
|
|
285
|
-
updates["description"] = authored.description
|
|
286
|
-
if authored.labels:
|
|
287
|
-
LabelRepository(session).mutate_target(
|
|
288
|
-
kind="meta_table", target_uid=uid, mode="replace",
|
|
289
|
-
names=authored.labels, created_by_user_uid=actor.user_uid,
|
|
290
|
-
)
|
|
291
|
-
if not same_contract_state(table.table_contract, contract):
|
|
292
|
-
updates["table_contract"] = contract
|
|
293
|
-
if not same_contract_state(table.introspection_snapshot, snapshot):
|
|
294
|
-
updates["introspection_snapshot"] = snapshot
|
|
295
|
-
authoring = contract.get("authoring") or {}
|
|
296
|
-
has_time_profile = (
|
|
297
|
-
contract.get("table_kind") == "time_indexed"
|
|
298
|
-
or isinstance(authoring, dict) and isinstance(authoring.get("time_indexed"), dict)
|
|
299
|
-
)
|
|
300
|
-
if specialization is None and has_time_profile:
|
|
301
|
-
spec = time_index_spec_from_contract({}, contract)
|
|
302
|
-
specialization = TimeIndexTable(
|
|
303
|
-
meta_table_uid=uid,
|
|
304
|
-
time_index_name=spec.time_index_name,
|
|
305
|
-
index_names=list(spec.index_names),
|
|
306
|
-
storage_layout=spec.normalized_layout(),
|
|
307
|
-
cadence=spec.cadence,
|
|
338
|
+
if labels:
|
|
339
|
+
LabelRepository(session).mutate_target(
|
|
340
|
+
kind="meta_table", target_uid=uid, mode="replace",
|
|
341
|
+
names=labels, created_by_user_uid=actor.user_uid,
|
|
308
342
|
)
|
|
343
|
+
if new_specialization is not None:
|
|
344
|
+
specialization = new_specialization
|
|
309
345
|
session.add(specialization)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
updates["alembic_revision"] = payload.alembic_revision
|
|
313
|
-
if version_root is not None and uid != version_root:
|
|
314
|
-
updates["alembic_version_meta_table_uid"] = version_root
|
|
315
|
-
# Do not dirty equal-valued rows: pre-flush hooks see assignments
|
|
316
|
-
# before SQLAlchemy decides whether they need an UPDATE.
|
|
317
|
-
for field, value in updates.items():
|
|
318
|
-
if getattr(table, field) != value:
|
|
319
|
-
setattr(table, field, value)
|
|
346
|
+
for field, value in changes.items():
|
|
347
|
+
setattr(table, field, value)
|
|
320
348
|
convert_time_index_table(source, table, specialization, convert=make_hypertable)
|
|
321
349
|
if replace_projection:
|
|
322
350
|
materialize_contract_projection(
|
|
@@ -345,11 +373,17 @@ def finalize_managed(
|
|
|
345
373
|
},
|
|
346
374
|
))
|
|
347
375
|
continue
|
|
376
|
+
logger.info("Managed finalization: reconciling %s tables (%s with catalog writes) took %.3fs",
|
|
377
|
+
len(eligible), written, perf_counter() - reconcile_started)
|
|
378
|
+
commit_started = perf_counter()
|
|
348
379
|
try:
|
|
349
380
|
session.commit()
|
|
350
381
|
except (IntegrityError, SQLAlchemyError) as exc:
|
|
351
382
|
session.rollback()
|
|
352
383
|
raise HTTPException(status_code=503, detail="MetaTables catalog is unavailable.") from exc
|
|
384
|
+
finally:
|
|
385
|
+
logger.info("Managed finalization: commit and security refresh took %.3fs",
|
|
386
|
+
perf_counter() - commit_started)
|
|
353
387
|
by_uid = {row["meta_table_uid"]: row for row in rows}
|
|
354
388
|
rows = [by_uid[str(uid)] for uid in requested]
|
|
355
389
|
finalized_count = sum(row["finalized"] for row in rows)
|
|
@@ -27,7 +27,7 @@ from metatables.api.backend.contracts.storage_layouts import StorageLayoutValida
|
|
|
27
27
|
from metatables.api.backend.contracts.table_contracts import ContractValidationError
|
|
28
28
|
from metatables.api.backend.domain.catalog_rules import CatalogAccessError, CatalogInvariantError
|
|
29
29
|
from metatables.api.backend.domain.data_source_rules import DataSourceAdmissionError
|
|
30
|
-
from metatables.api.backend.domain.permission_rules import TrustedActorFacts
|
|
30
|
+
from metatables.api.backend.domain.permission_rules import TrustedActorFacts, allowing
|
|
31
31
|
from metatables.api.backend.integrations.runtime_data_sources import DataSourceIntegrationError
|
|
32
32
|
from metatables.api.backend.operations.register_catalog import register_catalog_entry
|
|
33
33
|
from metatables.api.backend.persistence.grants import GrantRepository
|
|
@@ -94,8 +94,11 @@ def _registration(payload, *, indexed, actor, session, sources, creator, introsp
|
|
|
94
94
|
schema=payload.physical_schema, contract=raw['table_contract'], create=create)
|
|
95
95
|
for fk in raw['table_contract'].get('foreign_keys', []):
|
|
96
96
|
target_uid = UUID(str(fk['target_meta_table_uid']))
|
|
97
|
-
|
|
97
|
+
current = allowing(actor, lambda candidate: GrantRepository(session).may_access_table(
|
|
98
|
+
table_uid=target_uid, actor=candidate, action="tables.get_data"))
|
|
99
|
+
if current is None:
|
|
98
100
|
raise HTTPException(404, 'Foreign-key target was not found.')
|
|
101
|
+
actor = current
|
|
99
102
|
result = register_catalog_entry(session=session, actor=actor, source=source, payload=raw,
|
|
100
103
|
time_indexed=indexed, allow_new=True)
|
|
101
104
|
table = result.table
|
|
@@ -104,7 +107,7 @@ def _registration(payload, *, indexed, actor, session, sources, creator, introsp
|
|
|
104
107
|
root_uid = payload.alembic_version_meta_table_uid
|
|
105
108
|
if root_uid is not None:
|
|
106
109
|
root = session.get(MetaTable, root_uid)
|
|
107
|
-
if (root is None or root.data_source_uid != source.uid or root.alembic_version_meta_table_uid is not None or (root.schema_management_mode != 'alembic_managed') or (root.migration_provider_key != table.migration_provider_key) or (
|
|
110
|
+
if (root is None or root.data_source_uid != source.uid or root.alembic_version_meta_table_uid is not None or (root.schema_management_mode != 'alembic_managed') or (root.migration_provider_key != table.migration_provider_key) or allowing(actor, lambda candidate: GrantRepository(session).may_access_table(table_uid=root_uid, actor=candidate, action="tables.migrate")) is None):
|
|
108
111
|
raise HTTPException(404, 'Alembic version table was not found.')
|
|
109
112
|
if root_uid != table.uid:
|
|
110
113
|
table.alembic_version_meta_table_uid = root_uid
|
|
@@ -32,6 +32,22 @@ def is_workload(actor: TrustedActorFacts) -> bool:
|
|
|
32
32
|
return actor.check_workload is not None and actor.check_workload()
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def allowing(actor: TrustedActorFacts,
|
|
36
|
+
allowed: Callable[[TrustedActorFacts], bool]) -> TrustedActorFacts | None:
|
|
37
|
+
"""The actor ``allowed`` accepts, or None. Before refusing, asks the platform for the
|
|
38
|
+
actor's current Team membership: an answer up to a day old must not keep refusing
|
|
39
|
+
someone just added to a Team (#80). Accepted requests keep the cached answer."""
|
|
40
|
+
if allowed(actor):
|
|
41
|
+
return actor
|
|
42
|
+
if actor.check_teams is None:
|
|
43
|
+
return None
|
|
44
|
+
teams = actor.check_teams(0)
|
|
45
|
+
if teams == actor.active_team_uids:
|
|
46
|
+
return None
|
|
47
|
+
current = replace(actor, active_team_uids=teams)
|
|
48
|
+
return current if allowed(current) else None
|
|
49
|
+
|
|
50
|
+
|
|
35
51
|
def current_team_facts(actor: TrustedActorFacts, *, write: bool) -> TrustedActorFacts:
|
|
36
52
|
"""The actor for one SQL admission: a write's teams at most a minute old, and at
|
|
37
53
|
most one fresh check however often the admission repeats."""
|
|
@@ -6,7 +6,7 @@ from collections.abc import Mapping
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
from uuid import UUID
|
|
8
8
|
|
|
9
|
-
from sqlalchemy import or_, select
|
|
9
|
+
from sqlalchemy import inspect, or_, select
|
|
10
10
|
from sqlalchemy.orm import Session
|
|
11
11
|
|
|
12
12
|
from metatables.api.backend.contracts.table_contracts import normalize_table_contract
|
|
@@ -14,11 +14,25 @@ from metatables.api.backend.domain.catalog_rules import CatalogInvariantError
|
|
|
14
14
|
from metatables.api.backend.persistence.models import MetaTable
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
def foreign_key_target_names(snapshot: Mapping[str, Any]) -> set[str]:
|
|
18
|
+
"""The physical table names a snapshot's foreign keys reference."""
|
|
19
|
+
return {
|
|
20
|
+
str(item.get("target_table_name") or "")
|
|
21
|
+
for item in snapshot.get("constraints") or ()
|
|
22
|
+
if isinstance(item, Mapping) and item.get("constraint_type") == "f"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
17
26
|
def contract_from_physical_snapshot(
|
|
18
27
|
*, session: Session, table: MetaTable, snapshot: Mapping[str, Any],
|
|
19
28
|
authored_metadata: Mapping[str, Any] | None = None,
|
|
29
|
+
registered: Mapping[str, list[MetaTable]] | None = None,
|
|
20
30
|
) -> dict[str, Any]:
|
|
21
|
-
"""Use physical column, index, and FK facts; preserve declared semantic metadata.
|
|
31
|
+
"""Use physical column, index, and FK facts; preserve declared semantic metadata.
|
|
32
|
+
|
|
33
|
+
``registered`` holds the DataSource's MetaTables by physical name, read once for
|
|
34
|
+
a batch; without it each foreign key's target is read here.
|
|
35
|
+
"""
|
|
22
36
|
schema = str(snapshot.get("schema_name") or table.physical_schema or "").strip()
|
|
23
37
|
name = str(snapshot.get("table_name") or table.physical_table_name or "").strip()
|
|
24
38
|
if name != table.physical_table_name or (table.physical_schema and schema != table.physical_schema):
|
|
@@ -83,14 +97,23 @@ def contract_from_physical_snapshot(
|
|
|
83
97
|
target_name = str(item.get("target_table_name") or "")
|
|
84
98
|
# A reserved row may store an empty schema while the DataSource's
|
|
85
99
|
# default schema is only known after physical introspection.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
100
|
+
if registered is None:
|
|
101
|
+
schema_predicate = MetaTable.physical_schema == target_schema
|
|
102
|
+
if target_schema == schema:
|
|
103
|
+
schema_predicate = or_(schema_predicate, MetaTable.physical_schema == "")
|
|
104
|
+
targets = list(session.scalars(select(MetaTable).where(
|
|
105
|
+
MetaTable.data_source_uid == table.data_source_uid,
|
|
106
|
+
schema_predicate,
|
|
107
|
+
MetaTable.physical_table_name == target_name,
|
|
108
|
+
)))
|
|
109
|
+
else:
|
|
110
|
+
targets = [
|
|
111
|
+
candidate for candidate in registered.get(target_name, ())
|
|
112
|
+
if candidate.data_source_uid == table.data_source_uid
|
|
113
|
+
and (candidate.physical_schema == target_schema
|
|
114
|
+
or target_schema == schema and candidate.physical_schema == "")
|
|
115
|
+
and not inspect(candidate).was_deleted and candidate not in session.deleted
|
|
116
|
+
]
|
|
94
117
|
if len(targets) != 1:
|
|
95
118
|
raise CatalogInvariantError("Physical foreign-key target is not uniquely registered")
|
|
96
119
|
target = targets[0]
|
|
@@ -16,7 +16,7 @@ from metatables.api.backend.domain.catalog_rules import (
|
|
|
16
16
|
TableRegistration,
|
|
17
17
|
TimeIndexSpec,
|
|
18
18
|
)
|
|
19
|
-
from metatables.api.backend.domain.permission_rules import TrustedActorFacts, is_workload
|
|
19
|
+
from metatables.api.backend.domain.permission_rules import TrustedActorFacts, allowing, is_workload
|
|
20
20
|
from metatables.api.backend.integrations.runtime_data_sources import RuntimeDataSource
|
|
21
21
|
from metatables.api.backend.persistence.catalog import CatalogRepository
|
|
22
22
|
from metatables.api.backend.persistence.grants import GrantRepository
|
|
@@ -230,10 +230,13 @@ def register_catalog_entry(
|
|
|
230
230
|
MetaTable.physical_table_name == name,
|
|
231
231
|
).with_for_update())
|
|
232
232
|
if existing is not None:
|
|
233
|
-
|
|
233
|
+
current = allowing(actor, lambda candidate: GrantRepository(session).may_access_table(
|
|
234
|
+
table_uid=existing.uid, actor=candidate, action="tables.update"))
|
|
235
|
+
if current is None:
|
|
234
236
|
requested = payload.get("namespace")
|
|
235
237
|
raise not_editable(session, existing, actor=actor, requested_namespace=(
|
|
236
238
|
requested.strip().lower() if isinstance(requested, str) else None))
|
|
239
|
+
actor = current
|
|
237
240
|
if existing.management_mode != management_mode or (existing.kind == "time_index") != time_indexed:
|
|
238
241
|
raise CatalogInvariantError("Existing MetaTable has incompatible kind or management mode")
|
|
239
242
|
if time_index_spec is not None:
|
|
@@ -254,8 +257,10 @@ def register_catalog_entry(
|
|
|
254
257
|
if isinstance(namespace_name, str) and namespace_name.strip():
|
|
255
258
|
requested = namespace_name.strip().lower()
|
|
256
259
|
namespace = session.scalar(select(Namespace).where(Namespace.name == requested))
|
|
257
|
-
if namespace is
|
|
258
|
-
|
|
260
|
+
current = actor if namespace is None else allowing(
|
|
261
|
+
actor, lambda candidate: GrantRepository(session).may_access_namespace(
|
|
262
|
+
namespace_uid=namespace.uid, actor=candidate, action="tables.create"))
|
|
263
|
+
if current is None:
|
|
259
264
|
raise CatalogAccessError(
|
|
260
265
|
"namespace_access_required",
|
|
261
266
|
f"Caller {caller} lacks tables.create on namespace {requested!r}. Ask an owner of the "
|
|
@@ -264,6 +269,7 @@ def register_catalog_entry(
|
|
|
264
269
|
caller_user_uid=caller, namespace=requested, action="tables.create",
|
|
265
270
|
owners=namespace_owners(session, namespace, actor),
|
|
266
271
|
)
|
|
272
|
+
actor = current
|
|
267
273
|
# A missing namespace is created by whoever registers into it (ADR 0024). A person
|
|
268
274
|
# owns it; a workload gets editor, and the people who manage that workload manage
|
|
269
275
|
# the namespace's access.
|
|
@@ -106,17 +106,25 @@ def _target_for_foreign_key(
|
|
|
106
106
|
|
|
107
107
|
|
|
108
108
|
def _check_target_columns(
|
|
109
|
-
session: Session, *, foreign_key: dict, target: MetaTable, contract: dict | None = None
|
|
109
|
+
session: Session, *, foreign_key: dict, target: MetaTable, contract: dict | None = None,
|
|
110
|
+
shapes: dict | None = None,
|
|
110
111
|
) -> None:
|
|
111
112
|
if contract is None:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
shape = shapes.get(target.uid) if shapes is not None else None
|
|
114
|
+
if shape is None:
|
|
115
|
+
shape = (
|
|
116
|
+
[{"name": row.name, "primary_key": row.primary_key, "unique": row.unique}
|
|
117
|
+
for row in session.scalars(
|
|
118
|
+
select(MetaTableColumn)
|
|
119
|
+
.where(MetaTableColumn.meta_table_uid == target.uid)
|
|
120
|
+
.order_by(MetaTableColumn.ordinal_position)
|
|
121
|
+
)],
|
|
122
|
+
[index.columns for index in session.scalars(select(MetaTableIndex).where(
|
|
123
|
+
MetaTableIndex.meta_table_uid == target.uid, MetaTableIndex.unique.__eq__(True)))],
|
|
124
|
+
)
|
|
125
|
+
if shapes is not None:
|
|
126
|
+
shapes[target.uid] = shape
|
|
127
|
+
columns, indexes = shape
|
|
120
128
|
else:
|
|
121
129
|
# A self-reference must validate against its freshly observed contract,
|
|
122
130
|
# not a damaged projection that this finalization is about to repair.
|
|
@@ -151,8 +159,13 @@ def resolved_foreign_key_targets(
|
|
|
151
159
|
data_source_uid: UUID,
|
|
152
160
|
contract: dict,
|
|
153
161
|
source_table_uid: UUID | None = None,
|
|
162
|
+
shapes: dict | None = None,
|
|
154
163
|
) -> list[UUID]:
|
|
155
|
-
"""Preflight all targets before registering the new source table.
|
|
164
|
+
"""Preflight all targets before registering the new source table.
|
|
165
|
+
|
|
166
|
+
``shapes`` keeps each target's key columns across calls of one request; the
|
|
167
|
+
caller clears it when it replaces a projection.
|
|
168
|
+
"""
|
|
156
169
|
targets = []
|
|
157
170
|
for foreign_key in contract["foreign_keys"]:
|
|
158
171
|
target = _target_for_foreign_key(
|
|
@@ -161,7 +174,8 @@ def resolved_foreign_key_targets(
|
|
|
161
174
|
foreign_key=foreign_key,
|
|
162
175
|
)
|
|
163
176
|
_check_target_columns(session, foreign_key=foreign_key, target=target,
|
|
164
|
-
contract=contract if target.uid == source_table_uid else None
|
|
177
|
+
contract=contract if target.uid == source_table_uid else None,
|
|
178
|
+
shapes=shapes)
|
|
165
179
|
targets.append(target.uid)
|
|
166
180
|
return targets
|
|
167
181
|
|
|
@@ -114,7 +114,7 @@ def test_hosted_admin_comes_from_the_assertion_and_teams_from_membership_checks(
|
|
|
114
114
|
monkeypatch.setattr(User, "get_authenticated_user_details", classmethod(lookup))
|
|
115
115
|
workload, team, other = uuid4(), uuid4(), uuid4()
|
|
116
116
|
granted = frozenset({str(team), str(other)})
|
|
117
|
-
monkeypatch.setattr(team_membership, "grant_teams", lambda request: granted)
|
|
117
|
+
monkeypatch.setattr(team_membership, "grant_teams", lambda request, fresh=False: granted)
|
|
118
118
|
asked = []
|
|
119
119
|
|
|
120
120
|
class Caller:
|