Skip to main content

Multi-Tenant Data Isolation PRD

Date: 2026-06-04 Status: Draft for architecture and implementation planning Owner: Platform / ThorAPI / GrayMatter

Executive Summary

ValkyrAI must support production-grade multi-tenancy with physical customer data isolation, strict RBAC boundaries, generated application bundles, and no ad hoc database workarounds.

The target model is:

  1. ValkyrAI platform data stays in the platform control-plane schema.
  2. Each customer organization receives a physically separate schema named org_<organization_uuid_without_dashes>.
  3. GrayMatter data for that organization is written into that organization schema.
  4. Customer application/domain tables are generated from ThorAPI/OpenAPI bundles and exist only in that organization's schema or in that customer's paid runtime database.
  5. Valkyr platform RBAC controls platform objects only.
  6. Tenant RBAC controls customer-owned application data only when the customer has a paid application runtime.
  7. Anonymous users cannot use GrayMatter or application generation.

This PRD intentionally uses existing ValkyrAI and ThorAPI surfaces: api.hbs.yaml, ThorAPI bundles, generated services, thin custom controllers, deployment records, credits, organization schema provisioning, runtime isolation metadata, and existing RBAC policy hooks.

Non-Negotiable Invariants

  1. No customer data may be shared across organization schemas.
  2. No request may choose a schema by client-supplied string.
  3. The active tenant schema must be derived from authenticated identity, organization membership, and the tenant schema registry.
  4. Production customer schema names must be canonical: org_ plus the lower-case organization UUID without dashes.
  5. Organization-less authenticated users are denied tenant-scoped access.
  6. Generated ThorAPI CRUD/DataWorkbook paths must not become generic cross-tenant admin browsers.
  7. Valkyr ADMIN can manage customer schema data only through audited tenant-schema-scoped admin APIs.
  8. Customer-hosted or customer-paid application runtimes must not use Valkyr platform RBAC as their tenant RBAC.
  9. GrayMatter-only accounts may use Valkyr-managed RBAC for common GrayMatter endpoints, but their memory rows still live in their isolated organization schema.
  10. Tenant-owned ValkyrAI instances are first-class runtimes: ValorIDE agents that login/register to a tenant instance may run that tenant's workflows and commands through that instance's own agent registry, workflow state, tenant RBAC, command/event channels, audit ids, and data-plane binding.
  11. Commands created inside the shared ValkyrAI/api-0 control plane remain Valkyr RBAC scoped and must carry or resolve explicit tenant/application/runtime scope before crossing into tenant data, logs, workflow state, shell output, deployments, app-factory work, or ValorIDE control.
  12. Tenant table creation must come from ThorAPI/OpenAPI specs, application bundles, and Hibernate DDL, not handwritten migration scripts.
  13. Explicit relationship and query indexes must be declared in the OpenAPI spec when they matter.
  14. Tenant bundle model scope is declared in the enhanced OpenAPI schema with x-valkyr-scope set to shared or app_private.
  15. org_schema app-private tables use <appid8>_<table_name>; shared business tables use shared_<table_name>; app-schema/app-database placements keep unprefixed app-private table names because the physical data plane carries the app boundary.
  16. Shared tenant bundle models cannot reference app-private models; app-private models can reference same-bundle app-private models and shared models.
  17. External or cross-app component references must be declared on the field with x-valkyr-relationship-contract: shared.
  18. Generated files are read-only outputs. Implementation changes happen in specs, bundles, templates, generated-service overrides, aspects, and custom controllers.

Source Map

Existing code already covers meaningful pieces of this system:

AreaExisting anchorCurrent role
Organization schema naming/provisioningOrganizationSchemaProvisioningServiceCreates and verifies canonical org_<uuid> schemas, then records generated registry and operation state. Tenant table shape is applied by ThorAPI bundles and Hibernate DDL, not provisioning-time table DDL.
Post-payment provisioningPostPaymentTenantProvisioningService, CheckoutControllerCreates/attaches organizations after payment and returns provisioned tenant schemas.
Signup schema claimsAuthControllerAdds customerSchema, tenantSchema, and databaseScope=customer for non-platform customer roles.
Organization contextOrganizationContextResolverFail-closed organization lookup for tenant-scoped file access. This pattern should become the model for every tenant-scoped API.
Runtime isolation proofRuntimeIsolationControllerReports VALKYRAI_CUSTOMER_SCHEMA, VALKYRAI_DATABASE_SCOPE, JDBC catalog/schema, and isolated runtime status.
Tenant RBAC guardrailsRoleManagementPolicyBlocks hosted customer schemas from assigning platform/internal roles.
Paid deployment isolationLightsailDeploymentService, OpenClawLightsailProvisioningService, MultiCloudDeploymentServiceRequires customer schema, rejects shared/internal DB targets, stamps customer runtime env, and validates provisioned DB URLs.
ThorAPI generationThorAPIController, AssembleSpecsRunner, openapi/bundles/*, api.hbs.yamlExisting bundle and generated-code path for custom application/API generation.
GrayMatter object graphMemoryEntry, GrayMatter, SemanticIndexEntry, RetrievalReceipt, OpenApiObjectGraphShapeServiceCommon memory, semantic index, and retrieval proof objects.
CreditsAccountBalance, PaymentTransaction, UsageTransaction, credits servicesExisting prepaid usage model for generation, deployment, LLM, and memory operations.
Frontend isolation UXSignupCompletionService, MemoryDashboard, CustomerInstanceOpsDashboard, DeploymentWizardPanelDisplays schema/scope metadata and enforces deployment schema validation in the UI.

Customer Surfaces

Customer stateAllowed surfaceData planeRBAC source
Anonymous / unauthenticatedPublic website Valor chat onlyNo customer schemaPublic/anonymous website policy
Agentic signup500 starter credits, Valkyr-hosted GrayMatter common modelOrganization schemaValkyr-managed customer/agent RBAC
GrayMatter-onlyCommon GrayMatter API such as api-0.valkyrlabs.com/v1/GrayMatter and memory endpointsOrganization schemaValkyr-managed RBAC; ignore tenant Principal/ACL tables
Subscription customer without deploymentValkyr-hosted GrayMatter plus app design/generation workflows allowed by subscription/creditsOrganization schema for common GrayMatter onlyValkyr-managed RBAC
Subscription customer with paid runtimeCustomer-hosted application APIs, GrayMatter endpoints, domain tables, and custom generated UI/app codeCustomer runtime data plane: org schema, app schema, app database, or BYOC databaseTenant-managed RBAC and ACL inside customer runtime
Valkyr ADMINTenant-schema lifecycle and audited admin inspectionSchema-scoped onlyValkyr platform admin RBAC plus audit/break-glass reason

Data-Plane Architecture

Control Plane

The platform control plane remains in ValkyrAI's own database/schema and stores:

  • Customer, Principal, Organization, subscription, entitlement, and billing records.
  • Credits ledger and usage transactions.
  • Application, Deployment, DeploymentSpec, runtime metadata, and deployment status.
  • Tenant schema registry and lifecycle operations.
  • Valkyr platform RBAC and admin audit events.

Platform control-plane data is never copied into customer application schemas except as generated runtime bootstrap state required by a paid tenant runtime.

Organization Schema

Each customer organization has one canonical physical schema:

org_<organization_uuid_without_dashes>

This schema stores:

  • GrayMatter common memory data for the organization.
  • Semantic index and retrieval receipt data scoped to the organization.
  • Tenant runtime RBAC/ACL tables only when the customer has a paid runtime or explicitly provisioned tenant RBAC bundle.
  • Domain-specific generated tables such as teeth for a dentistry app, created from that customer's ThorAPI application bundle.

The schema name is a derived system value, not a user-facing free-form identifier.

Application Data-Plane Placement

Customer applications are not forced to share one physical placement forever. The organization schema is the default workspace/memory anchor, but each generated application can be bound to its own data-plane placement.

ModePhysical placementDefault use
org_schemaApplication tables live inside org_<uuid>Default for GrayMatter-only, early paid customers, low-risk internal apps, and apps that should share workspace memory closely.
app_schemaApplication tables live in a separate schema for that app on an approved customer/shared clusterHigher isolation when one app has distinct lifecycle, backup, compliance, or performance needs.
app_databaseApplication tables live in a fully separate database/database instance with its own credentialsStrong isolation for regulated, high-value, or noisy apps.
byoc_databaseApplication tables live in a customer-owned database/runtimeEnterprise/BYOC deployments where the customer owns the data plane.

The platform must treat this as a first-class binding, not a naming convention. Application code, generated APIs, deployment specs, GrayMatter project/app memory, and tenant RBAC all resolve their data plane through the application binding.

Example:

org_98195a01eeb44dc6a8e06d88bf36c5c5            # customer workspace + common GrayMatter
org_98195a01eeb44dc6a8e06d88bf36c5c5_app_12345678 # optional app_schema placement
appdb_98195a01eeb44dc6a8e06d88bf36c5c5_12345678 # optional app_database placement

Rules:

  1. org_schema is the default for new customer applications unless the subscription/deployment explicitly requests stronger isolation.
  2. app_schema, app_database, and byoc_database require a paid runtime/deployment binding.
  3. Each application has exactly one active write data plane at a time.
  4. Application data-plane promotion must be an audited lifecycle operation.
  5. Cross-app data access is not a raw SQL/schema join. It must use explicit APIs, generated integration contracts, or GrayMatter retrieval receipts with policy checks.
  6. App/project memory follows the application data plane when the application is isolated; workspace/org memory stays in org_<uuid>.
  7. Managed app_database names are server-derived as appdb_<organization_uuid_without_dashes>_<application_id_prefix>.
  8. BYOC database names may be customer-specific, but only after the active binding and runtime datasource match the approved host, database name, and managed credential reference.

Paid application runtimes run on customer-paid Lightsail, Fargate, or approved BYOC infrastructure. The runtime receives:

  • VALKYRAI_CUSTOMER_SCHEMA
  • application data-plane mode and binding identifier
  • VALKYRAI_DATABASE_SCOPE=customer-organization
  • VALKYRAI_SHARED_DATABASE_ALLOWED=false
  • Generated application bundle version and OpenAPI checksum.
  • Customer runtime auth/RBAC mode.

The customer runtime owns its domain APIs and tenant RBAC. The platform control plane owns deployment lifecycle, billing, registry, and launch metadata.

ThorAPI Contract

Implementation must use ThorAPI-native surfaces:

  1. Add new persistent models as component schemas in valkyrai/src/main/resources/openapi/api.hbs.yaml or a checked-in ThorAPI bundle assembled into that spec.
  2. Regenerate through the normal ThorAPI/Maven workflow.
  3. Use generated models, repositories, services, delegates, and TypeScript clients.
  4. Use thin delegate overrides only when generated behavior needs custom side effects or narrowed/widened authorization.
  5. Use custom controllers only for non-CRUD orchestration and admin/lifecycle actions.
  6. Keep custom controller paths lowercase kebab-case, such as /v1/tenant-schemas.
  7. Do not create duplicate custom CRUD paths for generated ThorAPI resources.
  8. Do not hand-edit generated backend or frontend files.
  9. Do not introduce handwritten SQL migration files or production-only DDL scripts for tenant tables; schema evolution is expressed through ThorAPI specs/bundles and applied by the generated application/Hibernate DDL path or by a ThorAPI-generated migration/reconciliation ledger.
  10. When Hibernate auto-DDL fails to reconcile an existing physical table, use the ThorAPI/spec-derived schema reconciliation rail. The rail auto-applies allowlisted safe generated repairs such as widening generated string columns for large maxLength fields and expanding enum constraints when OpenAPI enum values change, with no user-facing migration chore for normal ThorAPI projects. It must also provide ADMIN-visible preview, generated SchemaEvolutionLedger audit records, locking/idempotency, generated migration identity, and fail-closed manual review for data backfills, narrowing, removals, arbitrary SQL, and unknown DDL shapes. Flyway or a similar migration ledger remains acceptable only when the migration identity and SQL are generated from ThorAPI/spec deltas rather than handwritten workarounds; handwritten migration files are not an acceptable substitute for ThorAPI ownership.

Required Component Schemas

These component schemas should be added to the OpenAPI spec so ThorAPI owns the persistent model, generated services, generated TypeScript clients, and indexes.

TenantSchemaRegistry

Purpose: authoritative platform record for a customer schema.

Required fields:

  • organization reference
  • schemaName
  • databaseScope
  • isolationMode
  • status
  • region
  • databaseHost
  • currentGrayMatterBundleVersion
  • currentApplicationBundleVersion
  • currentOpenApiChecksum
  • provisionedAt
  • lastValidatedAt

Important indexes:

  • unique schemaName
  • organization,status
  • databaseScope,status
  • region,status

ApplicationDataPlaneBinding

Purpose: authoritative binding from one generated customer Application to one active data-plane placement.

Required fields:

  • organization reference
  • application reference
  • tenantSchemaRegistry reference for org_schema and app_schema modes
  • isolationMode
  • schemaName
  • databaseName
  • databaseHost
  • databaseRegion
  • credentialRef
  • activeDeployment reference
  • status
  • promotedFromBinding reference
  • boundAt
  • lastValidatedAt

Allowed isolationMode values:

  • org_schema
  • app_schema
  • app_database
  • byoc_database

Important indexes:

  • unique application,status for active bindings
  • organization,status
  • tenantSchemaRegistry,status
  • isolationMode,status
  • databaseHost,databaseName

TenantRuntimeBinding

Purpose: binds an Application/Deployment to exactly one runtime and its active application data plane.

Required fields:

  • organization reference
  • application reference
  • deployment reference
  • tenantSchemaRegistry reference
  • applicationDataPlaneBinding reference
  • runtimeKind
  • runtimeUrl
  • authMode
  • rbacMode
  • status
  • boundAt

Important indexes:

  • organization,status
  • application,status
  • deployment,status
  • tenantSchemaRegistry,status

TenantSchemaBundle

Purpose: records the generated table/model set allowed in a tenant schema for a specific bundle version.

Required fields:

  • tenantSchemaRegistry reference
  • application reference
  • applicationDataPlaneBinding reference
  • bundleName
  • bundleVersion
  • openApiChecksum
  • modelManifestJson
  • tableManifestJson
  • generatedAt
  • status

Important indexes:

  • tenantSchemaRegistry,status
  • application,status
  • applicationDataPlaneBinding,status
  • unique tenantSchemaRegistry,application,bundleVersion
  • openApiChecksum

TenantSchemaOperation

Purpose: auditable lifecycle operation record for provisioning, validation, runtime/data-plane binding, bundle apply, backup, export, clone, suspend, restore, and delete.

Required fields:

  • tenantSchemaRegistry reference
  • operationType
  • status
  • requestedBy
  • approvedBy
  • reason
  • requestId
  • startedAt
  • completedAt
  • errorCode
  • errorMessage

Important indexes:

  • tenantSchemaRegistry,status,startedAt
  • requestedBy,startedAt
  • operationType,status
  • requestId

TenantSchemaAccessAudit

Purpose: mandatory audit log for every Valkyr admin access to customer schema data.

Required fields:

  • tenantSchemaRegistry reference
  • adminPrincipalId
  • action
  • resourceType
  • resourceId
  • reason
  • sourceIp
  • userAgent
  • requestId
  • result
  • occurredAt

Important indexes:

  • tenantSchemaRegistry,occurredAt
  • adminPrincipalId,occurredAt
  • action,result,occurredAt
  • requestId

Tenant API Contract

Generated Customer APIs

Generated customer application APIs are produced from customer application OpenAPI specs and bundles. A dentistry customer's Teeth component, for example, is generated into that customer's app bundle and deployed only into their tenant runtime/schema.

Generated customer APIs must:

  1. Resolve schema from the runtime binding, not from request parameters.
  2. Use tenant RBAC when deployed in a paid customer runtime.
  3. Reject platform/internal roles inside customer-managed RBAC.
  4. Use tenant-local ACL tables only when tenant-managed RBAC is active.
  5. Include explicit relationship/query indexes in the OpenAPI spec for hot access paths.

Valkyr-Hosted GrayMatter APIs

GrayMatter-only customers use platform-hosted endpoints and platform-managed RBAC, but writes and retrievals are tenant data-plane operations.

Required behavior:

  1. Resolve organization from the authenticated principal.
  2. Resolve schema from TenantSchemaRegistry.
  3. Route memory, semantic index, and retrieval receipt reads/writes to the organization schema.
  4. Do not use tenant Principal, Role, Authority, or ACL tables for GrayMatter-only access decisions.
  5. Debit credits through the platform credits ledger.

Admin Tenant-Schema APIs

Valkyr ADMIN access must be explicit, audited, scoped, and narrow.

Allowed custom controller surface:

  • GET /v1/tenant-schemas
  • GET /v1/tenant-schemas/{id}
  • GET /v1/tenant-schemas/{id}/health
  • POST /v1/tenant-schemas/{id}/validate
  • POST /v1/tenant-schemas/{id}/operations
  • GET /v1/tenant-schemas/{id}/audit
  • GET /v1/tenant-schemas/{id}/objects/{objectType}
  • GET /v1/tenant-schemas/{id}/objects/{objectType}/{objectId}

Admin object reads must be allowlisted by bundle manifest and object type. No free-form SQL endpoint is allowed.

Index Policy

Hibernate auto-DDL may create tables and basic constraints from generated entities, but performance-critical indexes must be explicit in the spec.

Add x-thorapi-dataField, x-index, x-index-groups, or class-level @Table(indexes = ...) annotations in api.hbs.yaml when a field participates in:

  • tenant/schema lookup
  • owner/principal/organization filtering
  • deployment/runtime status lookup
  • application-to-deployment joins
  • application data-plane binding lookup
  • audit lookup by admin, schema, request, or timestamp
  • semantic retrieval lookup
  • lifecycle operations by status and time
  • unique bundle/version checks
  • foreign-key relationship traversal used by dashboards, generated APIs, or background jobs

The default rule is: if production code queries by a relationship or compound filter more than incidentally, the index belongs in the OpenAPI spec before regeneration.

Security Requirements

  1. Every tenant-scoped controller must fail closed when organization context is missing.
  2. Every tenant-scoped service must reject schema names that are not registry-derived.
  3. Every platform-to-tenant operation must produce a TenantSchemaAccessAudit or TenantSchemaOperation row.
  4. Admin access must require Valkyr platform ADMIN and a reason.
  5. Tenant runtime role creation must reject platform roles such as ROLE_ADMIN, ROLE_SYSTEM, and Valkyr internal agent roles unless the runtime is explicitly platform scope.
  6. Customer app runtime credentials must not have privileges outside the customer schema/database.
  7. Connection/schema switching must be reset in finally blocks, or isolated by separate tenant-scoped data sources/pools.
  8. Tenant schemas must not expose platform Customer, platform Principal, billing, invoice, payment, or internal PII tables.
  9. SecureField/KMS key material must be tenant-scoped for tenant data.
  10. Logs must include request IDs and schema registry IDs, but not secrets, raw tokens, credentials, or decrypted customer data.

Subscription and Credit Gating

  1. Anonymous users can use public Valor chat only.
  2. App generation requires authentication, entitlement, and sufficient credits.
  3. GrayMatter requires authentication and an assigned organization schema.
  4. Agentic signup grants 500 starter credits and common GrayMatter access.
  5. Paid runtime deployment requires enough credits or an active customer-paid deployment method.
  6. Without Lightsail, Fargate, or BYOC deployment, customer access is limited to Valkyr-hosted common GrayMatter data models.
  7. Deployment lifecycle and runtime usage must debit credits through the existing ledger path.

Implementation Phases

Phase 1: Registry and Contracts

  • Add the required tenant schemas to api.hbs.yaml.
  • Regenerate ThorAPI backend and frontend artifacts.
  • Add indexes in the spec for registry, application data-plane binding, runtime binding, lifecycle operation, and audit access paths.
  • Add focused generated-model tests and repository/service smoke tests.

Phase 2: Provisioning Orchestration

  • Keep OrganizationSchemaProvisioningService as the schema-name, create-schema, verification, and orchestration service.
  • Remove handwritten tenant table DDL from the target path.
  • Apply GrayMatter/common tenant tables through generated ThorAPI application bundles and Hibernate DDL.
  • Persist TenantSchemaRegistry and TenantSchemaOperation for every provision/validate action.

Implementation evidence, 2026-06-05:

  • OrganizationSchemaProvisioningService now creates and verifies only the canonical organization schema, then records generated TenantSchemaRegistry and TenantSchemaOperation lifecycle state.
  • The transitional handwritten minimum tenant table DDL path was removed from provisioning; tenant tables must be applied by ThorAPI/Hibernate bundle execution.
  • OrganizationSchemaProvisioningServiceTest now asserts schema creation/verification without handwritten CREATE TABLE statements and continues to cover registry/operation success and failure states.
  • Added TenantSchemaBundleLifecycleService to register ThorAPI enhanced OpenAPI outputs as generated TenantSchemaBundle manifests, supersede older active manifests for the same tenant/application, update the registry's active bundle/checksum fields, and record an apply_bundle TenantSchemaOperation.
  • ThorAPI code generation now calls the lifecycle service when generation is tenant-scoped by explicit tenantSchemaRegistryId/schema config or an active ApplicationDataPlaneBinding; legacy/global generation remains unchanged and does not invent tenant state.
  • Bundle lifecycle registration stores model/table allowlists only. It does not emit table DDL; the physical table shape remains owned by ThorAPI-generated application code and Hibernate DDL.
  • TenantSchemaBundleLifecycleServiceTest covers manifest persistence, prior-bundle supersession, apply_bundle audit operations, active data-plane binding discovery, legacy/global generation skip behavior, registry/schema mismatch rejection, required x-valkyr-scope, post-scope table collision rejection, org_schema app-private table prefixing, shared-table shared_ prefixing, app-schema unprefixed private tables, shared-model reference rejection for app-private targets, legal app-private references to shared models, external reference rejection without x-valkyr-relationship-contract: shared, and declared shared external relationship contract persistence.

Phase 3: Tenant Routing

  • Introduce a tenant schema resolver that derives schema from authenticated principal, organization, registry, and runtime binding.
  • Apply it to GrayMatter memory, semantic index, retrieval receipt, and customer runtime paths.
  • Deny org-less authenticated users consistently across tenant-scoped APIs.

Implementation evidence, 2026-06-05:

  • Added TenantSchemaContextResolver as the GrayMatter/common data-plane context gate. It resolves a ThorUser/Principal through OrganizationContextResolver, selects an active or validating generated TenantSchemaRegistry, validates the canonical org_[0-9a-f]{32} schema name, and fails closed when organization or registry context is missing.
  • Wired the resolver into MemoryEntryController, MemoryEntryApiDelegateOverride, and MemoryApiDelegateOverride so GrayMatter create/read/list/export/clear/runtime operations require tenant schema context before generated-object service access.
  • Wired retrieval receipts to require tenant context and stamp persisted RetrievalReceipt.tenantId with the resolved schema name.
  • Wired memory semantic indexing to stamp SemanticIndexRequest.tenantScope with the resolved schema name, and filtered vector/summary semantic retrieval to the same tenant scope when the resolver is present.
  • Added TenantSchemaExecutionService so tenant data-plane work switches to the registry-derived schema/catalog, flushes successful writes before reset, and restores JDBC schema/catalog state in finally.
  • TenantSchemaExecutionServiceTest now includes H2-backed sibling-schema regressions where identical tables in two org_<uuid> schemas return only the selected tenant's row, unqualified writes persist only into the selected tenant schema, identical record ids remain isolated, and the connection schema resets to PUBLIC after each read/write.
  • MemoryEntry now has generated application and project relationships plus explicit app/project query indexes, so app/project memory can be routed through ThorAPI model state instead of source-channel conventions.
  • Application-scoped generated POST /MemoryEntry now preserves those generated relationships and resolves tenant context through the active generated ApplicationDataPlaneBinding when MemoryEntry.application.id is present.
  • Custom GrayMatter compatibility writes and reads now carry the same generated relationship scope: /v1/memory/write accepts applicationId/application_id and projectId/project_id, creates a generated MemoryEntry payload, and /v1/memory/query plus /v1/memory/list route scoped queries through app/project filters before tenant schema execution.
  • App-schema execution remains fail-closed to registry/server-derived names only: org_<uuid> or org_<uuid>_app_<8hex>.
  • Application data-plane context now preserves the active generated ApplicationDataPlaneBinding id, isolation mode, database name, database host, database region, and credential reference when app/project memory resolves beyond the organization schema.
  • app_database and byoc_database app memory contexts now fail closed unless the active binding has a valid generated database name, database host, and managed credential reference, and shared schema execution rejects those placements instead of silently running app-database work on the platform DataSource.
  • Managed app_database routing now requires the exact server-derived appdb_<organization_uuid_without_dashes>_<application_id_prefix> database name; BYOC remains allowed to use customer-specific database names only when the runtime binding matches the approved BYOC placement.
  • Routed GrayMatter memory repository operations, semantic index writes/searches, retrieval receipt persistence/reads, sparse keyword retrieval, graph retrieval, MySQL full-text retrieval, and generated-target semantic retrieval through the tenant schema execution boundary.
  • Retrieval receipt reads now require persisted tenantId to match the resolved tenant schema before ACL checks can return a receipt.
  • Hardened legacy and compatibility memory search surfaces (/MemoryEntry/search, /v1/memory/search, and /v1/memory/semantic-search) so they require authenticated GrayMatter roles, read entitlement, tenant schema context, and registry-derived tenant read execution before search results are queried or returned.
  • Generated and custom GrayMatter GET surfaces (/v1/GrayMatter, /v1/graymatter/**, /v1/graymatter-retrieval-receipts/**, /v1/memory/**, and /v1/MemoryEntry/**) now authenticate before the generic /v1/** GET fallback. /v1/GrayMatter was also removed from the public API cache-header allowlist.
  • GrayMatter action surfaces now have runtime coverage proving anonymous callers with valid CSRF tokens are still denied before use: /v1/memory/write, /v1/memory/query, /v1/memory/semantic-index/search, /v1/graymatter/retrieval-context, /v1/graymatter/retrieval-benchmark, /v1/graymatter/activation/bridge/event, /v1/graymatter/mcp/bundles, and /v1/graymatter-retrieval-receipts.
  • GrayMatter activation and MCP bundle controllers now carry explicit controller-level authenticated GrayMatter role guards in addition to the HTTP route-order guardrails.
  • GrayMatter control-surface metadata endpoints (/v1/graymatter/control, /v1/graymatter/retrieval-tools, /v1/graymatter/semantic-index/manifest, /v1/graymatter/object-graph/shape, and /v1/graymatter/retrieval-benchmark) now require resolved tenant schema context before returning control, tool, manifest, object-graph, or benchmark planning metadata.
  • Application generation/deployment action surfaces now have runtime coverage proving anonymous callers with valid CSRF tokens cannot use /v1/thorapi/**, /v1/deployments, /deployments, or tenant-schema validation/operation routes.
  • Hot GrayMatter memory usage telemetry now uses bounded projection queries through CustomUsageTransactionRepository instead of a single OR/LOWER ledger query; UsageTransaction keeps explicit ThorAPI spec-level generated indexes for customer/provider/spent, customer/model/spent, owner/customer/provider/spent, and owner/customer/model/spent query paths.
  • Controller-level GrayMatter write coverage now proves hosted/common /v1/memory/write resolves tenant schema context before entitlement debit or persistence, and that missing tenant context blocks persistence entirely.
  • Verified this slice with TenantSchemaContextResolverTest, TenantSchemaExecutionServiceTest, MemoryEntryApiDelegateOverrideTest, MemoryApiDelegateOverrideTest, MemoryEntryControllerTest, MemoryEntryServiceTest, MemorySemanticSearchServiceTest, JpaMemoryEntrySparseSearchProviderTest, MemoryEntryGraphSearchProviderTest, MySqlFullTextMemoryEntrySparseSearchProviderTest, SemanticIndexSummarySearchProviderTest, SemanticIndexTargetSearchProviderTest, RetrievalReceiptRuntimeServiceTest, GrayMatterControlSurfaceControllerTest, SecurityConfigGrayMatterAuthContractTest, and ThorApiAuthSurfaceSecurityTest.

Phase 4: Admin Management Surface

  • Add lowercase kebab-case tenant schema lifecycle controllers.
  • Allow only registry-backed, bundle-manifest-backed inspection.
  • Emit TenantSchemaAccessAudit for every admin read/action.
  • Block generic DataWorkbook browsing of customer schemas.

Implementation evidence, 2026-06-05:

  • The LCARS Tenant Schemas panel already reads manifest-backed health from /v1/tenant-schemas/{id}/health; newly registered TenantSchemaBundle rows become the expected-table list used before allowlisted object inspection.
  • Tenant schema health now returns active bundle summaries so the panel displays the ThorAPI bundle name, version, checksum, generated time, and status that control the allowlist.
  • Generated tenant isolation model HTTP/DataWorkbook routes (/v1/TenantSchemaRegistry, /v1/ApplicationDataPlaneBinding, /v1/TenantRuntimeBinding, /v1/TenantSchemaBundle, /v1/TenantSchemaOperation, and /v1/TenantSchemaAccessAudit) are explicitly denied in SecurityConfig before the generic /v1/** GET fallback. The generated repositories/services remain available for internal ThorAPI-native orchestration.
  • Full Spring security coverage now proves a platform ADMIN receives forbidden responses on generated tenant isolation model list, detail, and stats routes, so the denial is runtime behavior rather than only source-order intent.
  • Generated identity and billing control-plane DataWorkbook routes (/v1/Principal, /v1/Customer, /v1/Organization, /v1/IntegrationAccount, /v1/AccountBalance, /v1/UsageTransaction, and /v1/PaymentTransaction) now require authentication before the generic /v1/** GET fallback can match list, stats, or detail reads. They remain generated platform model surfaces, not public catalog routes or tenant-schema admin browsers.
  • Added authenticated lowercase /v1/tenant-schemas/preflight for deployment-time registry readiness checks. Admin callers may preflight a named registry; non-admin callers must resolve through their authenticated organization context and cannot preflight sibling schemas.
  • Custom lowercase /v1/tenant-schemas/** admin and preflight routes are now explicitly authenticated in SecurityConfig before the generic anonymous /v1/** GET fallback, with runtime MockMvc coverage proving anonymous callers receive unauthorized responses across list, detail, health, audit, object, and preflight reads, and authenticated non-admin callers receive forbidden responses across tenant-schema admin list, detail, health, audit, object, validate, and operation routes.
  • Deployment Wizard hosted AWS verification now calls the audited preflight endpoint instead of generated TenantSchemaRegistry RTK/DataWorkbook routes.
  • Tenant schema validation and unsupported lifecycle operation requests now write explicit TenantSchemaAccessAudit rows against TenantSchemaOperation, and tenant-admin transactional entrypoints use noRollbackFor = ResponseStatusException.class so denied/failed admin audit rows and failed operation records are not discarded by expected 4xx responses.
  • Tenant admin reads now have backend regression coverage proving blank or too-short operational reasons fail before schema inspection and before any audit row is written, matching the LCARS reason gate server-side.
  • No new dashboard write path was added for bundle application because bundle registration is tied to ThorAPI generation/deployment lifecycle, not an operator-entered DDL action.
  • Tenant Schemas LCARS audit lookup now has frontend regression coverage proving the panel calls /tenant-schemas/{id}/audit with the operational reason, skipOrganizationHeaders, and only lowercase audited tenant-schema paths.

Phase 5: Paid Runtime Integration

  • Bind Application, Deployment, DeploymentSpec, ApplicationDataPlaneBinding, TenantRuntimeBinding, and TenantSchemaBundle.
  • Support org_schema, app_schema, app_database, and byoc_database as explicit deployment/data-plane modes.
  • Ensure Lightsail/Fargate/BYOC runtime env matches registry state.
  • Ensure customer runtime RBAC is tenant-managed and platform roles are blocked.
  • Validate customer schema/database URL at deployment time and runtime health time.

Implementation evidence, 2026-06-05:

  • TenantDataPlaneBindingService now resolves a first-class binding plan for each successful deployment and persists the generated ApplicationDataPlaneBinding plus TenantRuntimeBinding as the authoritative data-plane/runtime record.
  • app_schema placement uses a server-derived schema name from the active TenantSchemaRegistry and Application.id; an explicit mismatched schema name is rejected instead of trusting a request-provided physical schema.
  • Runtime data-plane binding by schema name now selects only deployable ACTIVE/VALIDATING TenantSchemaRegistry rows, prefers ACTIVE, rejects stale inactive duplicates, and rejects noncanonical registry schema names before any ApplicationDataPlaneBinding or TenantRuntimeBinding row is written.
  • app_database and byoc_database placements require approved deployment metadata for database host/name and managed credential references; environment-only BYOC placement strings do not create bindings. Managed app_database names are still derived by the service and any explicit mismatched applicationDatabaseName/appDatabaseName is rejected before an active binding can be persisted.
  • Application data-plane routing now exposes app-database placement metadata to the tenant context while keeping shared-schema execution limited to org_schema and app_schema; app-database/BYOC execution requires a runtime-specific data source.
  • Runtime execution for app_database and byoc_database now fails closed unless the running process is tenant/customer/organization scoped, VALKYRAI_SHARED_DATABASE_ALLOWED=false, and runtime mode, application database name, database host, and managed credential reference match the active generated ApplicationDataPlaneBinding. Managed app_database placement also requires the server-derived appdb_<organization_uuid_without_dashes>_<application_id_prefix> database name. When the guard passes, the executor switches only to the bound application database catalog and does not switch into the shared organization schema.
  • A change in registry, isolation mode, schema, database name, host, region, or credential reference retires the prior active application data-plane binding and creates a promoted active binding, preserving promotedFromBinding provenance and avoiding dual active write planes.
  • Deployments without tenant schema or registry hints are treated as generic platform deployments and do not create tenant data-plane, runtime binding, or tenant lifecycle operation rows.
  • Redeploying an application with the same registry and physical data-plane placement reuses the existing active ApplicationDataPlaneBinding, updates its active deployment pointer, and records bind_runtime instead of creating a duplicate active write plane or false promotion.
  • ApplicationDataPlaneBinding history is indexed by application/status but is not globally unique on application/status because that would block multiple retired historical bindings. The binding service owns the active-write-plane invariant by retiring duplicate active/validating/binding rows before reusing or promoting a placement.
  • Successful runtime binding writes a generated TenantSchemaOperation with operationType=bind_runtime; data-plane promotion writes operationType=promote_data_plane. Both operations use the deployment actor as requester/approver and tenant-data-plane:<deploymentId> as the request correlation id.
  • MultiCloudDeploymentService stamps binding ids, registry id, data-plane mode, runtime kind, and database placement evidence back onto deployment metadata after a successful binding operation.
  • AWS Fargate deployments now normalize tenant runtime metadata from the validated DeploymentSpec.environmentVariables into the deployment result, including provider, registry id/status, customer schema, database scope, isolation mode, database host, region, OpenAPI checksum, shared-DB flag, and tenant auth/RBAC mode before the binding service evaluates the runtime.
  • Lightsail deployments now derive managed app_database placement from the active tenant registry and Application.id, rewrite provisioned db-0 JDBC URLs to the server-owned appdb_<organization_uuid_without_dashes>_<application_id_prefix> database, reject mismatched explicit database names, and stamp non-secret app database host/name/credential-reference metadata into the deployment result.
  • Deployment validation now applies a provider-agnostic customer runtime data-plane guard before launch. Specs that declare customer schema, tenant registry id, tenant data-plane mode, or tenant RBAC must reject shared ValkyrAI endpoints, shared/internal/platform scopes, VALKYRAI_SHARED_DATABASE_ALLOWED=true, platform database/schema names, and sibling db-0 schemas for org_schema runtimes while allowing approved app_database placement.
  • Tenant RBAC replacement now rejects platform/internal roles in hosted customer schemas even when a stale principal already has the role, so tenant runtime role updates cannot preserve ROLE_ADMIN, ROLE_SYSTEM, or internal Valkyr agent privileges.
  • Tenant RBAC replacement also supports safe recovery from stale platform roles: a customer-schema principal with an existing ROLE_ADMIN can be replaced with tenant-safe roles such as ROLE_FREE/ROLE_PRO, proving the policy blocks preservation without trapping cleanup.
  • Tenant RBAC positive coverage now proves hosted customer schemas can create tenant-domain roles such as ROLE_DENTIST and grant generated-object authorities such as TEETH_READ/APPOINTMENT_WRITE, while Valkyr platform/internal roles and authorities remain blocked.
  • Generated customer application scaffolds now emit per-model REST controllers, a tenant TenantRbacAuthorization guard, and method security. Generated app data access requires object authorities such as WIDGET_READ, WIDGET_CREATE, or WIDGET_WRITE; ROLE_ADMIN, ROLE_SYSTEM, ROLE_VALKYR_AGENT, and VALKYR_* authorities are treated as platform-only and do not grant tenant app data access.
  • Deployment surfaces now require authenticated callers explicitly in SecurityConfig before the generic /v1 GET fallback and at controller/delegate boundaries for generated deployment operations, Fargate upgrades, database connectivity checks, generated deployment secrets, and the /deployments compatibility path.
  • /v1/runtime/isolation now reports application data-plane mode, application data-plane binding id, tenant runtime binding id, tenant schema registry id, application database placement, tenant runtime auth/RBAC mode, and a paidRuntimeIsolationReady boolean alongside customer schema, database scope, shared-DB flag, deployment target/stage, and JDBC catalog/schema.
  • /v1/runtime/isolation readiness now mirrors the execution guard: app_database and byoc_database runtimes are not marked ready unless binding ids and app database name, host, a managed credential reference, and live JDBC catalog alignment are configured; org/app schema runtimes are not marked ready unless the live JDBC schema or catalog matches the tenant schema. The response exposes only non-secret alignment booleans such as applicationCredentialRefConfigured, tenantSchemaConnectionAligned, and applicationDatabaseCatalogAligned, not credential references or direct schema-switching controls.
  • /v1/runtime/isolation also runs a server-configured TenantDatabasePrivilegeProbe through the runtime datasource before marking paid runtime isolation ready. The probe can require a tenant/app target table to be readable and configured platform or sibling tables to be unreadable, reports only non-secret booleans/counts, rejects unsafe qualified-table config, and fails readiness if forbidden access is detected.
  • Customer Instance Ops now renders the runtime data-plane mode, shared database guardrail, application database placement, tenant runtime RBAC values, live tenant/app connection alignment, and database privilege probe result from /v1/runtime/isolation, including forbidden-table readable counts when overprivileged runtime credentials are detected. It also warns when a managed app_database runtime still reports a non-derived database name.
  • Tenant Schemas admin health now exposes active bundle application and application data-plane binding ids, and the LCARS panel renders those ids beside bundle name/version/checksum so admins can see which app and write-plane binding controls the allowlist.
  • Tenant Schemas admin health now exposes non-secret active data-plane placement details per bundle, including write-plane mode/status, schema/database placement, database host/region, and active deployment id. The LCARS panel renders those details from /v1/tenant-schemas/{id}/health, never from generated tenant DataWorkbook routes, warns when a managed app_database placement reports a stale/friendly database name instead of the server-derived appdb_<organization_uuid_without_dashes>_<application_id_prefix> contract, renders manifest-derived model/scope/shared-contract/external-reference posture counts without raw manifest access, disables shared-datasource object loading for runtime-only app_database/BYOC objects, and enables those object buttons only when backend health verifies the object table through a matching runtime admin datasource.
  • Deployment Wizard now shows the resolved managed app database placement for app_database registries, carries a stable generated Application.id through review/submit, and sends the server-derived app database name/host/credential reference in the runtime environment instead of accepting friendly database names.
  • Verified this slice with TenantDataPlaneBindingServiceTest, TenantSchemaExecutionServiceTest, TenantDatabasePrivilegeProbeTest, LightsailDeploymentServiceTest, MultiCloudDeploymentServiceTest, DeploymentSecurityContractTest, RuntimeIsolationControllerTest, customerInstanceOps.test.ts, CustomerInstanceOpsDashboard.test.tsx, DeploymentWizardPanel.test.tsx, TenantSchemaAdminControllerContractTest, and TenantSchemaAdminPanel.test.tsx.

Phase 6: Verification and Hardening

  • Run cross-tenant isolation tests with at least two organizations.
  • Run app-domain table tests using a generated sample component such as Teeth.
  • Current evidence: MemoryEntryControllerTest proves a GrayMatter-only hosted /v1/memory/write resolves TenantSchemaContextResolver before credit entitlement or persistence, and that missing tenant context prevents both entitlement debit and persistence.
  • Current evidence: MemoryEntryServiceTest proves generated MemoryEntry creation enters TenantSchemaExecutionService.executeWrite with the resolved tenant context and stamps the resolved schema into semantic index requests, while TenantSchemaExecutionServiceTest proves the write boundary lands unqualified rows with identical ids only in the selected organization schema.
  • Current evidence: MemorySemanticSearchControllerTest and MemorySemanticSearchServiceTest prove semantic recall accepts app/project scope, forwards it into SemanticSearchRequest, resolves the tenant read context through TenantSchemaContextResolver.requireCurrentGrayMatterContext(..., relationshipScope), and filters candidates to the requested application/project after tenant-scope filtering.
  • Current evidence: GrayMatterControlSurfaceControllerTest proves GrayMatter control, retrieval-tools, semantic-index manifest, object-graph shape, and retrieval-benchmark metadata routes resolve TenantSchemaContextResolver before returning planning/control metadata, and that missing tenant context blocks object-graph schema topology before OpenApiObjectGraphShapeService is called.
  • Current evidence: RetrievalReceiptRuntimeServiceTest, SemanticIndexVectorSearchProviderTest, JpaMemoryEntrySparseSearchProviderTest, MemoryEntryGraphSearchProviderTest, MySqlFullTextMemoryEntrySparseSearchProviderTest, SemanticIndexSummarySearchProviderTest, and SemanticIndexTargetSearchProviderTest prove receipt-backed dense, sparse, graph, summary, generated-target, and full-text retrieval read app/project filters from the generated request filter map, resolve tenant reads through the active application data-plane binding, filter MemoryEntry candidates to the requested app/project, and stamp app-scoped receipts with the application schema.
  • Current evidence: JpaMemoryEntrySparseSearchProviderTest and MemoryEntryGraphSearchProviderTest prove sparse and graph retrieval push app/project IDs into the DB-backed MemoryEntrySearchService.searchAcrossOwners(...) criteria query, while MemoryEntrySearchServiceIT proves the Criteria query itself filters through the generated MemoryEntry.application and MemoryEntry.project relationships and excludes sibling project rows. Post-query candidate filtering remains in place as defense in depth.
  • Current evidence: TenantSchemaExecutionServiceTest now also covers a representative generated app-domain teeth table with the same domain object id in two sibling org_<uuid> schemas, proving each tenant reads only its own domain row through the registry-derived execution boundary.
  • Current evidence: TenantSchemaContextResolverTest and TenantSchemaExecutionServiceTest prove shared/platform execution still rejects app_database placements, managed app database names must be server-derived, BYOC database names remain allowed only through a matching runtime binding, and credential-reference mismatches fail before the action or JDBC connection is touched.
  • Current evidence: TenantDatabasePrivilegeProbeTest proves an H2 app-database user with SELECT only on appdb can read the generated-domain appdb.teeth target while platform platform.TenantSchemaRegistry and sibling sibling.teeth tables remain unreadable, and also proves an overprivileged runtime user that can read the platform table is detected as not isolated.
  • Current evidence: TenantDatabasePrivilegeProbeTest rejects unsafe server-configured table identifiers, and RuntimeIsolationControllerTest keeps the privilege probe wired into /v1/runtime/isolation readiness alongside live catalog/schema alignment.
  • Current evidence: RuntimeIsolationControllerTest, customerInstanceOps.test.ts, and CustomerInstanceOpsDashboard.test.tsx prove runtime readiness and Customer Instance Ops fail closed/display mismatches when the live JDBC catalog does not match the configured application database binding, visibly warn when managed app database names are not server-derived, and visibly warn when the database privilege probe detects forbidden platform/sibling table access.
  • Current evidence: TenantSchemaBundleLifecycleServiceTest proves a generated Teeth OpenAPI component is captured in the tenant TenantSchemaBundle model/table manifests, while TenantSchemaAdminServiceTest proves admin object reads only use the active bundle allowlist for the teeth table and reject non-allowlisted domain objects.
  • Current evidence: TenantSchemaAdminServiceTest proves admin allowlist parsing ignores generated model field entries such as toothNumber and generic OpenAPI schema metadata such as type: object, so only explicit bundle model/table entries become object inspection targets.
  • Current evidence: TenantSchemaBundleLifecycleServiceTest proves tenant bundle registration rejects platform-owned model/table contamination such as Principal, Customer, Invoice, UsageTransaction, payment, credit, and Valkyr billing control objects before those objects can be persisted into a tenant manifest allowlist.
  • Current evidence: TenantSchemaAdminServiceTest proves blank and too-short reasons block admin reads before schema inspection/audit writes; validate success, validate failure, and unsupported operation denial write TenantSchemaAccessAudit rows; and every transactional admin entrypoint keeps expected ResponseStatusException paths from rolling back audit records.
  • Current evidence: TenantSchemaAdminServiceTest proves allowlisted tenant object list and record inspection redact common credential, key, token, authorization, and bearer column variants before returning admin payloads, while preserving non-sensitive display values and writing the required audited access rows.
  • Current evidence: TenantSchemaAdminServiceTest proves tenant object inspection validates the canonical registry schema before bundle lookup, reads app_schema bundle objects only from the server-derived application schema, rejects app_database/byoc_database bundle object reads rather than falling back to the registry org schema without a runtime-specific admin datasource, and allows app-database inspection only when TenantSchemaExecutionService enters a matching runtime admin data plane.
  • Current evidence: TenantSchemaAdminServiceTest and TenantSchemaAdminPanel.test.tsx prove tenant schema health is placement-aware: app-schema bundle tables are checked in the server-derived org_<uuid>_app_<8hex> schema, app-database bundle tables are not checked through the shared registry datasource, validation fails on missing app-schema tables, the LCARS panel visibly reports runtime-datasource-required checks while disabling shared-datasource object loading for unverified runtime placements, and runtime-database object buttons become loadable only after backend verification succeeds.
  • Current evidence: SecureKMSTenantScopeTest proves default SecureField KMS key derivation is tenant-aware when generated/domain objects expose tenant schema, tenant registry, application database, or owner scope. Different tenant scopes derive different key hashes from the same platform secret, matching scopes normalize to the same generated key, and unscoped legacy objects stay on the existing default-key path.
  • Current evidence: RoleManagementPolicyTest and RoleManagementServiceTest prove hosted customer schemas reject platform/internal role assignment and replacement payloads, reject stale internal agentic role preservation, allow tenant-domain role/authority creation for generated app objects, and allow safe replacement of a stale ROLE_ADMIN principal with tenant-safe roles.
  • Current evidence: AppCodegenScaffoldServiceTest compiles generated backend scaffold output and invokes the generated tenant RBAC guard, proving object authorities such as WIDGET_READ, WIDGET_CREATE, TEETH_READ, and ROLE_TEETH_CREATE authorize generated app data while ROLE_ADMIN, ROLE_ADMIN combined with object authorities, VALKYR_SCHEMA_READ, and VALKYR_SCHEMA_READ combined with role-prefixed object authorities do not.
  • Current evidence: ThorAPIControllerAuthSemanticsTest reflects every ThorAPI controller route and requires the ADMIN/DEVELOPER guard for code generation, OpenAPI import, hosted instance, bundle generation, consolidation, job status, validation, and spec-filtering routes. The same test proves the explicit /v1/thorapi/** SecurityConfig rule is evaluated before the generic anonymous /v1/** GET fallback.
  • Current evidence: ThorApiAuthSurfaceSecurityTest keeps anonymous access denied for workflow/app-generation-adjacent protected surfaces, includes runtime MockMvc denials for anonymous reads of exact collection/root surfaces (/v1/credits, /v1/workflow, /v1/vaiworkflow, /v1/mcp, /v1/memory, /v1/mo, /v1/graymatter, /v1/thorapi, /v1/deployments, /deployments, /v1/workflow-test, and /v1/schema-evolution), child routes such as /v1/thorapi/jobs/{jobId}, /v1/tenant-schemas/**, tenant file list/meta/download/S3-info routes under /v1/files/**, account privacy and compliance routes under /v1/auth/login-history and /v1/compliance/**, runtime isolation metadata under /v1/runtime/**, SWARM/agent control-plane metadata under /v1/swarm-ops/**, /v1/swarm/agents/**, /v1/agents/**, SWARM agent chat history under /v1/agent-chat/**, /v1/team-projects/**, workflow module/control metadata under /v1/modules/**, /v1/module-schemas/**, /v1/execmodules/**, legacy /v1/execModule/**, /v1/workflow-tasks/**, and command ABI /v1/abi/**, app-generation and command UX metadata under /v1/app-factory/**, /v1/workflow/design/**, and /v1/slash-command/**, creator monetization account reads under /v1/monetization/services, /v1/monetization/earnings/**, and /v1/monetization/services/{serviceId}/preview, generated identity/billing DataWorkbook list/stats/detail reads under /v1/Principal, /v1/Customer, /v1/Organization, /v1/IntegrationAccount, /v1/AccountBalance, /v1/UsageTransaction, and /v1/PaymentTransaction, Customer Launchpad app listing and launch-token routes under /v1/launchpad/**, docs-fragment schema/workflow/module metadata under /v1/docs/fragments/**, operational table/summary statistics under /v1/statistics/tables and /v1/statistics/summary, admin/operator metadata under /v1/admin/**, dashboard ops telemetry/contracts under /v1/ops/**, and API telemetry under /v1/metrics/api/** plus /v1/api/telemetry/**; it also proves authenticated non-admin users cannot use tenant-schema admin routes, schema-evolution roots/actions, ops dashboard routes, or API telemetry routes, and platform ADMIN cannot browse generated tenant isolation DataWorkbook routes.
  • Current evidence: WorkflowMetricsAspectTest proves workflow-specific WebSocket metric emission delegates to the central ValkyrAclService.hasPermission(..., READ) decision for the generated Workflow object identity, denies normal users when ACL denies, allows explicit workflow operator roles, and fails closed for malformed workflow ids or missing ACL service wiring.
  • Current evidence: ValkyrAclSecuritySupportTest, ValkyrAclPermissionsTest, and ValkyrAiPermissionEvaluatorTest prove Spring PermissionEvaluator.hasPermission(...) and concrete ACL Acl.isGranted(...) remain separate framework entry points while SID construction, permission normalization, anonymous/decrypt denial, admin override, owner-default masks, and permission implication stay centralized in ThorAPI ACL support rather than duplicated across security paths.
  • Current evidence: MemoryApiDelegateOverrideTest proves /v1/memory/runs uses the bounded custom usage telemetry repository when available and does not call generated UsageTransaction owner/customer repository methods on that hot path; CreditSchemaContractTest proves the ThorAPI spec and regenerated UsageTransaction entity retain the memory-ledger compound indexes.
  • Current evidence: TenantIsolationOpenApiContractTest proves hot tenant readiness/retrieval/polling paths keep explicit ThorAPI spec-level indexes for tenant retrieval receipts, app/project memory, tenant semantic index recall, deployment status polling, deployment-spec status lookup, deployed-by status lookup, and cloud-resource reconciliation.
  • Current evidence: TenantIsolationOpenApiContractTest also proves regenerated ThorAPI repositories expose bounded hot-path query methods for schema-name registry lookup, registry-scoped audit lookup, tenant/status/owner retrieval receipts, and deployment status/spec/deployed-by/cloud-resource polling instead of depending on handwritten repository code.
  • Current evidence: TenantIsolationOpenApiContractTest proves the tenant isolation schemas are not introduced through SQL migration files by scanning migration resource folders for the generated tenant isolation table names.
  • Current evidence: SchemaColumnAutoExpansionServiceTest, SchemaEvolutionReconciliationServiceTest, SchemaEvolutionSettingsServiceTest, ThorApiAuthSurfaceSecurityTest, SecurityConfigTest, and TenantSchemaAdminPanel.test.tsx prove the planner itself cannot run as a raw startup DDL mutator, safe generated string-widening changes are ledgered and auto-applied, unsafe data backfills are ledgered for manual review without SQL execution, previously applied statement hashes are skipped idempotently, generated SchemaEvolutionLedger DataWorkbook routes are denied, the lowercase schema-evolution root/preview/reconcile/settings surface is ADMIN-only before the generic /v1/** GET fallback and rejects anonymous plus non-admin runtime callers, and LCARS Platform Ops exposes preview/reconcile controls without using generated ledger browsing.
  • Current evidence: TenantDataPlaneBindingServiceTest proves successful runtime binding by schema name uses generated key/relationship lookups for registry, application data-plane binding, and runtime binding, and does not call repository-wide findAll() scans on that hot path. It also proves application data-plane promotion retires every prior active/validating write-plane binding, creates exactly one new active binding, points the runtime binding at that promoted binding, and records a promote_data_plane TenantSchemaOperation with deployment actor approval and request correlation.
  • Current evidence: TenantSchemaAdminServiceTest proves tenant audit lookup uses the generated registry-scoped pageable repository query, clamps page size, writes one access audit row, and does not scan all audit rows.
  • Current evidence: deploy/tests/tenant-isolation-release-gate.sh is now an executable production-release gate for the staging p95/load evidence named in this PRD. It requires fresh evidence for registry lookup, GrayMatter retrieval, audit writes, deployment status polling, runtime binding lookup, and application data-plane promotion validation.
  • Current evidence: deploy/deploy-app.sh enforces the tenant isolation release gate before non-dry-run production deployment API calls, and deploy/tests/deployment-launcher-contract-test.sh proves production deploys fail closed when the evidence path is missing or required p95 evidence is incomplete.
  • Current evidence: MultiCloudDeploymentServiceTest proves dashboard/API production tenant runtime specs fail closed unless fresh inline release evidence is supplied through VALKYRAI_TENANT_ISOLATION_RELEASE_EVIDENCE_JSON or VALKYRAI_TENANT_RELEASE_EVIDENCE_JSON, with p95 values at or under their thresholds for every required release-gate result.
  • Current evidence: Lightsail staging launches remain allowed without production release evidence when the deployment stage is explicitly non-production, even if the staged runtime starts with SPRING_PROFILES_ACTIVE=production; production tenant runtime stages and tags remain gated.
  • Current evidence: Fargate promotion requires tenant release evidence before cloud provisioning, and the dashboard validates and passes that evidence to /v1/deployments/{deploymentId}/upgrade/fargate instead of allowing a staging Lightsail runtime to be promoted through an ungated or malformed production path.
  • Current evidence: DeploymentWizardPanel.test.tsx, LightsailDeploymentServiceTest, and deploy/tests/deployment-launcher-contract-test.sh prove dashboard, Java Lightsail, and shell-generated runtime specs enable VALKYRAI_SCHEMA_RECONCILIATION_ENABLED=true and do not emit the removed raw VALKYRAI_SCHEMA_AUTO_EXPAND_COLUMNS startup-mutator flag.
  • GrayMatter-only tests now cover platform-controller authorization order, tenant context resolution before persistence, generated MemoryEntry service writes entering the tenant execution boundary, and H2-backed tenant-schema write isolation for identical ids.
  • Current evidence: ValorIDEExecModuleTest proves tenant-instance ValorIDE agents can receive workflow commands through their local ValkyrAI runtime boundary without shared api-0 tenant schema metadata, while shared-control-plane ValorIDE commands fail closed unless explicit tenant/application/runtime scope is present and that non-secret scope is forwarded in the SWARM envelope.
  • Current evidence: SwarmCommandServiceTest proves the shared REST/WebSocket SWARM command forwarding service now enforces the same boundary centrally: shared-control-plane ValorIDE/agent control commands are rejected without tenant/application/runtime scope, scoped shared-control-plane commands are forwarded, tenant-owned ValkyrAI runtimes can control their local ValorIDE agents, and ordinary targeted SWARM messages plus direct-dispatch policy denials keep their existing behavior.
  • Current evidence: SwarmApiDelegateImplTest, SwarmDashboard.test.tsx, SwarmControlPanel.test.tsx, and swarmCommandUtils.test.ts prove /swarm-ops/command returns server-issued commandId and deterministic rejectionCode receipts, while the ValorIDE Swarm Control Panel dispatches generated SwarmMessage payloads through that server control plane, forwards non-secret runtime scope, and renders accepted/rejected/failed state from the authoritative response instead of simulating command completion in the browser. The same dashboard suite proves SWARM discovery, activation, and suspend UX calls use the shared authenticated API fetch rail instead of a separate local JWT fetch path.
  • Current evidence: SageChat.test.tsx proves workflow and completion protocol blocks render as command/status cards without raw XML leakage, persisted workflow commands execute through real REST endpoints, and the command guide offers natural-language examples rather than raw executor envelopes.
  • Current evidence: AppCodegenScaffoldServiceTest includes a generated dentistry Teeth paid-runtime scaffold contract proving tenant object authorities authorize generated-domain data while platform RBAC signals cannot authorize the same object.
  • Current evidence: RoleManagementPolicyTest and RoleManagementServiceTest cover tenant RBAC replacement rules proving hosted customer schemas cannot create, assign, or preserve platform/internal roles, while stale platform roles can be removed with tenant-safe replacements.
  • Current evidence: Customer Launchpad treats tenant instances as first-class launch targets: /v1/launchpad/apps exposes source-backed organization, tenant registry/schema, tenant database scope/isolation mode, application data-plane binding/schema/database placement, runtime binding, and runtime auth/RBAC metadata for generated apps without using generated tenant DataWorkbook routes. /v1/launchpad/apps/{applicationId}/launch issues five-minute audience-scoped launch JWTs carrying the same tenant/application/runtime scope for customer ValkyrAI jars, fails closed when a bound runtime lacks tenant registry/data-plane scope, rejects non-HTTP(S) or userinfo-bearing launch URLs before token creation, omits managed credential references from launch claims, appends launch tokens before URL fragments, and the dashboard refuses to open raw runtime or entrypoint URLs unless the launch response returns a tokenized URL.
  • Staging release gate: run environment-level p95/load tests for registry lookup, GrayMatter retrieval, audit writes, and deployment status polling before production rollout; local deterministic contracts currently cover query shape and index presence, not production latency.

Acceptance Criteria

  1. Two organizations can create identical domain object IDs without either org reading the other's data.
  2. GrayMatter-only users write memory data into their organization schema while authorization is decided by Valkyr-managed RBAC.
  3. Paid runtime customers can use tenant-managed RBAC for generated app/domain tables.
  4. Each paid customer application has an active ApplicationDataPlaneBinding.
  5. org_schema, app_schema, app_database, and byoc_database deployments resolve writes through the binding rather than request parameters.
  6. App/project GrayMatter memory follows the isolated application data plane when the application is promoted beyond org_schema.
  7. Anonymous users cannot call GrayMatter, app generation, deployment, or tenant-schema endpoints.
  8. Valkyr ADMIN cannot browse tenant schema data through generic generated DataWorkbook routes.
  9. Valkyr ADMIN can inspect tenant data only through audited schema-scoped admin endpoints.
  10. Runtime isolation endpoint reports customer schema, customer database scope, application data-plane mode, and shared DB disabled for paid runtimes.
  11. Deployment validation rejects shared ValkyrAI DB targets for customer app runtimes.
  12. All hot tenant relationship/query paths have explicit spec-level indexes.
  13. No implementation edits generated output directly.
  14. Hot tenant runtime/retrieval/polling indexes are declared in the ThorAPI spec and covered by contract tests.

Test Plan

Unit Tests

  • Schema name derivation and validation.
  • Registry lookup and failure modes.
  • Organization-less denial.
  • Role boundary policy for platform roles inside customer scopes.
  • Admin reason/audit requirement.
  • Bundle manifest allowlist checks.

Integration Tests

  • Signup creates/returns organization schema claims.
  • Payment provisions or attaches an organization schema.
  • GrayMatter writes and reads use the correct organization schema.
  • Cross-organization reads return 403 or empty results, never another tenant's rows.
  • Paid runtime deployment validates customer schema and shared DB rejection.
  • Admin tenant object inspection writes audit rows.
  • Generated sample app component writes only into its tenant schema.
  • Generated sample app can run in org_schema, app_schema, and app_database modes with the same ThorAPI model contract.
  • Application data-plane promotion creates a new binding and lifecycle operation without allowing dual active write planes.

Security Tests

  • Reject path/query/body schema injection attempts.
  • Reject malformed org_ schema names.
  • Reject customer runtime assignment of Valkyr platform/internal roles.
  • Verify customer DB credentials cannot read platform schema; covered by TenantDatabasePrivilegeProbeTest and runtime readiness reporting through /v1/runtime/isolation.
  • Verify app database credentials cannot read sibling app schemas/databases; covered by TenantDatabasePrivilegeProbeTest using sibling teeth tables.
  • Verify admin object inspection cannot access object types outside the tenant bundle manifest.

Performance Tests

  • Registry lookup p95 latency.
  • GrayMatter retrieval under tenant routing.
  • Semantic index queries using explicit owner/status/tenant indexes.
  • Deployment status and runtime binding queries.
  • Application data-plane binding lookup and promotion validation.
  • Audit insert throughput under admin inspection and lifecycle operations.
  • Current index evidence: TenantIsolationOpenApiContractTest covers registry, bundle, runtime binding, operation/audit write, GrayMatter retrieval, semantic index, app/project memory, and deployment polling index declarations in api.hbs.yaml.
  • Current query-shape evidence: TenantIsolationOpenApiContractTest, TenantDataPlaneBindingServiceTest, and TenantSchemaAdminServiceTest cover regenerated repository methods and service calls for schema registry lookup, GrayMatter retrieval support, tenant data-plane binding, deployment polling support, and registry-scoped audit lookup.
  • Current schema-authority evidence: TenantIsolationOpenApiContractTest guards against adding tenant isolation SQL migration scripts for TenantSchemaRegistry, ApplicationDataPlaneBinding, TenantRuntimeBinding, TenantSchemaBundle, TenantSchemaOperation, or TenantSchemaAccessAudit.
  • Required staging evidence before release: capture p95 latency/load-test results for registry lookup, GrayMatter retrieval under tenant routing, audit writes, deployment polling, runtime binding lookup, and application data-plane promotion validation.

Remaining Open Questions

  1. Should paid customer runtimes use one DB user per organization schema by default, even on shared db-0, to make cross-schema access impossible at the database privilege layer?
  2. Should app-private tables in org_schema mode use an app prefix for collision avoidance, while app_schema and app_database modes use plain generated names?
  3. Should tenant schema lifecycle operations require two-person approval for export, clone, restore, promote, and delete?

Risks

  1. Existing handwritten minimum table DDL can diverge from ThorAPI-generated models unless it is removed from the target path.
  2. Schema switching on shared pools can leak state if not reset or isolated by tenant-scoped pools.
  3. Generated DataWorkbook surfaces can accidentally expose tenant data if platform admin UX points at customer schemas directly.
  4. Tenant RBAC and Valkyr platform RBAC can be confused if role names overlap without explicit runtime scope.
  5. Missing compound indexes on registry, memory, semantic index, and audit tables can produce production timeouts.
  6. Application-level database isolation can create operational sprawl unless placement, promotion, backup, and billing are registry-driven.

Definition of Done

The project is done when customer GrayMatter, customer application domain data, tenant RBAC, deployment runtime binding, and admin management are all mediated by ThorAPI-generated models and schema-scoped custom controllers, with physical organization schema isolation, explicit spec-level indexes, audited admin access, and passing cross-tenant isolation tests.