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:
- ValkyrAI platform data stays in the platform control-plane schema.
- Each customer organization receives a physically separate schema named
org_<organization_uuid_without_dashes>. - GrayMatter data for that organization is written into that organization schema.
- 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.
- Valkyr platform RBAC controls platform objects only.
- Tenant RBAC controls customer-owned application data only when the customer has a paid application runtime.
- 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
- No customer data may be shared across organization schemas.
- No request may choose a schema by client-supplied string.
- The active tenant schema must be derived from authenticated identity, organization membership, and the tenant schema registry.
- Production customer schema names must be canonical:
org_plus the lower-case organization UUID without dashes. - Organization-less authenticated users are denied tenant-scoped access.
- Generated ThorAPI CRUD/DataWorkbook paths must not become generic cross-tenant admin browsers.
- Valkyr
ADMINcan manage customer schema data only through audited tenant-schema-scoped admin APIs. - Customer-hosted or customer-paid application runtimes must not use Valkyr platform RBAC as their tenant RBAC.
- GrayMatter-only accounts may use Valkyr-managed RBAC for common GrayMatter endpoints, but their memory rows still live in their isolated organization schema.
- 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.
- 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.
- Tenant table creation must come from ThorAPI/OpenAPI specs, application bundles, and Hibernate DDL, not handwritten migration scripts.
- Explicit relationship and query indexes must be declared in the OpenAPI spec when they matter.
- Tenant bundle model scope is declared in the enhanced OpenAPI schema with
x-valkyr-scopeset tosharedorapp_private. org_schemaapp-private tables use<appid8>_<table_name>; shared business tables useshared_<table_name>; app-schema/app-database placements keep unprefixed app-private table names because the physical data plane carries the app boundary.- Shared tenant bundle models cannot reference app-private models; app-private models can reference same-bundle app-private models and shared models.
- External or cross-app component references must be declared on the field with
x-valkyr-relationship-contract: shared. - 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:
| Area | Existing anchor | Current role |
|---|---|---|
| Organization schema naming/provisioning | OrganizationSchemaProvisioningService | Creates 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 provisioning | PostPaymentTenantProvisioningService, CheckoutController | Creates/attaches organizations after payment and returns provisioned tenant schemas. |
| Signup schema claims | AuthController | Adds customerSchema, tenantSchema, and databaseScope=customer for non-platform customer roles. |
| Organization context | OrganizationContextResolver | Fail-closed organization lookup for tenant-scoped file access. This pattern should become the model for every tenant-scoped API. |
| Runtime isolation proof | RuntimeIsolationController | Reports VALKYRAI_CUSTOMER_SCHEMA, VALKYRAI_DATABASE_SCOPE, JDBC catalog/schema, and isolated runtime status. |
| Tenant RBAC guardrails | RoleManagementPolicy | Blocks hosted customer schemas from assigning platform/internal roles. |
| Paid deployment isolation | LightsailDeploymentService, OpenClawLightsailProvisioningService, MultiCloudDeploymentService | Requires customer schema, rejects shared/internal DB targets, stamps customer runtime env, and validates provisioned DB URLs. |
| ThorAPI generation | ThorAPIController, AssembleSpecsRunner, openapi/bundles/*, api.hbs.yaml | Existing bundle and generated-code path for custom application/API generation. |
| GrayMatter object graph | MemoryEntry, GrayMatter, SemanticIndexEntry, RetrievalReceipt, OpenApiObjectGraphShapeService | Common memory, semantic index, and retrieval proof objects. |
| Credits | AccountBalance, PaymentTransaction, UsageTransaction, credits services | Existing prepaid usage model for generation, deployment, LLM, and memory operations. |
| Frontend isolation UX | SignupCompletionService, MemoryDashboard, CustomerInstanceOpsDashboard, DeploymentWizardPanel | Displays schema/scope metadata and enforces deployment schema validation in the UI. |
Customer Surfaces
| Customer state | Allowed surface | Data plane | RBAC source |
|---|---|---|---|
| Anonymous / unauthenticated | Public website Valor chat only | No customer schema | Public/anonymous website policy |
| Agentic signup | 500 starter credits, Valkyr-hosted GrayMatter common model | Organization schema | Valkyr-managed customer/agent RBAC |
| GrayMatter-only | Common GrayMatter API such as api-0.valkyrlabs.com/v1/GrayMatter and memory endpoints | Organization schema | Valkyr-managed RBAC; ignore tenant Principal/ACL tables |
| Subscription customer without deployment | Valkyr-hosted GrayMatter plus app design/generation workflows allowed by subscription/credits | Organization schema for common GrayMatter only | Valkyr-managed RBAC |
| Subscription customer with paid runtime | Customer-hosted application APIs, GrayMatter endpoints, domain tables, and custom generated UI/app code | Customer runtime data plane: org schema, app schema, app database, or BYOC database | Tenant-managed RBAC and ACL inside customer runtime |
Valkyr ADMIN | Tenant-schema lifecycle and audited admin inspection | Schema-scoped only | Valkyr 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
teethfor 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.
| Mode | Physical placement | Default use |
|---|---|---|
org_schema | Application 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_schema | Application tables live in a separate schema for that app on an approved customer/shared cluster | Higher isolation when one app has distinct lifecycle, backup, compliance, or performance needs. |
app_database | Application tables live in a fully separate database/database instance with its own credentials | Strong isolation for regulated, high-value, or noisy apps. |
byoc_database | Application tables live in a customer-owned database/runtime | Enterprise/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:
org_schemais the default for new customer applications unless the subscription/deployment explicitly requests stronger isolation.app_schema,app_database, andbyoc_databaserequire a paid runtime/deployment binding.- Each application has exactly one active write data plane at a time.
- Application data-plane promotion must be an audited lifecycle operation.
- 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.
- App/project memory follows the application data plane when the application is isolated; workspace/org memory stays in
org_<uuid>. - Managed
app_databasenames are server-derived asappdb_<organization_uuid_without_dashes>_<application_id_prefix>. - 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 Runtime Data Plane
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-organizationVALKYRAI_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:
- Add new persistent models as component schemas in
valkyrai/src/main/resources/openapi/api.hbs.yamlor a checked-in ThorAPI bundle assembled into that spec. - Regenerate through the normal ThorAPI/Maven workflow.
- Use generated models, repositories, services, delegates, and TypeScript clients.
- Use thin delegate overrides only when generated behavior needs custom side effects or narrowed/widened authorization.
- Use custom controllers only for non-CRUD orchestration and admin/lifecycle actions.
- Keep custom controller paths lowercase kebab-case, such as
/v1/tenant-schemas. - Do not create duplicate custom CRUD paths for generated ThorAPI resources.
- Do not hand-edit generated backend or frontend files.
- 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.
- 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
maxLengthfields 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, generatedSchemaEvolutionLedgeraudit 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:
organizationreferenceschemaNamedatabaseScopeisolationModestatusregiondatabaseHostcurrentGrayMatterBundleVersioncurrentApplicationBundleVersioncurrentOpenApiChecksumprovisionedAtlastValidatedAt
Important indexes:
- unique
schemaName organization,statusdatabaseScope,statusregion,status
ApplicationDataPlaneBinding
Purpose: authoritative binding from one generated customer Application to one active data-plane placement.
Required fields:
organizationreferenceapplicationreferencetenantSchemaRegistryreference fororg_schemaandapp_schemamodesisolationModeschemaNamedatabaseNamedatabaseHostdatabaseRegioncredentialRefactiveDeploymentreferencestatuspromotedFromBindingreferenceboundAtlastValidatedAt
Allowed isolationMode values:
org_schemaapp_schemaapp_databasebyoc_database
Important indexes:
- unique
application,statusfor active bindings organization,statustenantSchemaRegistry,statusisolationMode,statusdatabaseHost,databaseName
TenantRuntimeBinding
Purpose: binds an Application/Deployment to exactly one runtime and its active application data plane.
Required fields:
organizationreferenceapplicationreferencedeploymentreferencetenantSchemaRegistryreferenceapplicationDataPlaneBindingreferenceruntimeKindruntimeUrlauthModerbacModestatusboundAt
Important indexes:
organization,statusapplication,statusdeployment,statustenantSchemaRegistry,status
TenantSchemaBundle
Purpose: records the generated table/model set allowed in a tenant schema for a specific bundle version.
Required fields:
tenantSchemaRegistryreferenceapplicationreferenceapplicationDataPlaneBindingreferencebundleNamebundleVersionopenApiChecksummodelManifestJsontableManifestJsongeneratedAtstatus
Important indexes:
tenantSchemaRegistry,statusapplication,statusapplicationDataPlaneBinding,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:
tenantSchemaRegistryreferenceoperationTypestatusrequestedByapprovedByreasonrequestIdstartedAtcompletedAterrorCodeerrorMessage
Important indexes:
tenantSchemaRegistry,status,startedAtrequestedBy,startedAtoperationType,statusrequestId
TenantSchemaAccessAudit
Purpose: mandatory audit log for every Valkyr admin access to customer schema data.
Required fields:
tenantSchemaRegistryreferenceadminPrincipalIdactionresourceTyperesourceIdreasonsourceIpuserAgentrequestIdresultoccurredAt
Important indexes:
tenantSchemaRegistry,occurredAtadminPrincipalId,occurredAtaction,result,occurredAtrequestId
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:
- Resolve schema from the runtime binding, not from request parameters.
- Use tenant RBAC when deployed in a paid customer runtime.
- Reject platform/internal roles inside customer-managed RBAC.
- Use tenant-local ACL tables only when tenant-managed RBAC is active.
- 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:
- Resolve organization from the authenticated principal.
- Resolve schema from
TenantSchemaRegistry. - Route memory, semantic index, and retrieval receipt reads/writes to the organization schema.
- Do not use tenant
Principal,Role,Authority, or ACL tables for GrayMatter-only access decisions. - 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-schemasGET /v1/tenant-schemas/{id}GET /v1/tenant-schemas/{id}/healthPOST /v1/tenant-schemas/{id}/validatePOST /v1/tenant-schemas/{id}/operationsGET /v1/tenant-schemas/{id}/auditGET /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
- Every tenant-scoped controller must fail closed when organization context is missing.
- Every tenant-scoped service must reject schema names that are not registry-derived.
- Every platform-to-tenant operation must produce a
TenantSchemaAccessAuditorTenantSchemaOperationrow. - Admin access must require Valkyr platform
ADMINand a reason. - 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. - Customer app runtime credentials must not have privileges outside the customer schema/database.
- Connection/schema switching must be reset in
finallyblocks, or isolated by separate tenant-scoped data sources/pools. - Tenant schemas must not expose platform
Customer, platformPrincipal, billing, invoice, payment, or internal PII tables. - SecureField/KMS key material must be tenant-scoped for tenant data.
- Logs must include request IDs and schema registry IDs, but not secrets, raw tokens, credentials, or decrypted customer data.
Subscription and Credit Gating
- Anonymous users can use public Valor chat only.
- App generation requires authentication, entitlement, and sufficient credits.
- GrayMatter requires authentication and an assigned organization schema.
- Agentic signup grants 500 starter credits and common GrayMatter access.
- Paid runtime deployment requires enough credits or an active customer-paid deployment method.
- Without Lightsail, Fargate, or BYOC deployment, customer access is limited to Valkyr-hosted common GrayMatter data models.
- 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
OrganizationSchemaProvisioningServiceas 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
TenantSchemaRegistryandTenantSchemaOperationfor every provision/validate action.
Implementation evidence, 2026-06-05:
OrganizationSchemaProvisioningServicenow creates and verifies only the canonical organization schema, then records generatedTenantSchemaRegistryandTenantSchemaOperationlifecycle state.- The transitional handwritten minimum tenant table DDL path was removed from provisioning; tenant tables must be applied by ThorAPI/Hibernate bundle execution.
OrganizationSchemaProvisioningServiceTestnow asserts schema creation/verification without handwrittenCREATE TABLEstatements and continues to cover registry/operation success and failure states.- Added
TenantSchemaBundleLifecycleServiceto register ThorAPI enhanced OpenAPI outputs as generatedTenantSchemaBundlemanifests, supersede older active manifests for the same tenant/application, update the registry's active bundle/checksum fields, and record anapply_bundleTenantSchemaOperation. - ThorAPI code generation now calls the lifecycle service when generation is tenant-scoped by explicit
tenantSchemaRegistryId/schema config or an activeApplicationDataPlaneBinding; 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.
TenantSchemaBundleLifecycleServiceTestcovers manifest persistence, prior-bundle supersession,apply_bundleaudit operations, active data-plane binding discovery, legacy/global generation skip behavior, registry/schema mismatch rejection, requiredx-valkyr-scope, post-scope table collision rejection,org_schemaapp-private table prefixing, shared-tableshared_prefixing, app-schema unprefixed private tables, shared-model reference rejection for app-private targets, legal app-private references to shared models, external reference rejection withoutx-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
TenantSchemaContextResolveras the GrayMatter/common data-plane context gate. It resolves aThorUser/PrincipalthroughOrganizationContextResolver, selects an active or validating generatedTenantSchemaRegistry, validates the canonicalorg_[0-9a-f]{32}schema name, and fails closed when organization or registry context is missing. - Wired the resolver into
MemoryEntryController,MemoryEntryApiDelegateOverride, andMemoryApiDelegateOverrideso 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.tenantIdwith the resolved schema name. - Wired memory semantic indexing to stamp
SemanticIndexRequest.tenantScopewith the resolved schema name, and filtered vector/summary semantic retrieval to the same tenant scope when the resolver is present. - Added
TenantSchemaExecutionServiceso tenant data-plane work switches to the registry-derived schema/catalog, flushes successful writes before reset, and restores JDBC schema/catalog state infinally. TenantSchemaExecutionServiceTestnow includes H2-backed sibling-schema regressions where identical tables in twoorg_<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 toPUBLICafter each read/write.MemoryEntrynow has generatedapplicationandprojectrelationships 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 /MemoryEntrynow preserves those generated relationships and resolves tenant context through the active generatedApplicationDataPlaneBindingwhenMemoryEntry.application.idis present. - Custom GrayMatter compatibility writes and reads now carry the same generated relationship scope:
/v1/memory/writeacceptsapplicationId/application_idandprojectId/project_id, creates a generatedMemoryEntrypayload, and/v1/memory/queryplus/v1/memory/listroute scoped queries through app/project filters before tenant schema execution. - App-schema execution remains fail-closed to registry/server-derived names only:
org_<uuid>ororg_<uuid>_app_<8hex>. - Application data-plane context now preserves the active generated
ApplicationDataPlaneBindingid, isolation mode, database name, database host, database region, and credential reference when app/project memory resolves beyond the organization schema. app_databaseandbyoc_databaseapp 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 platformDataSource.- Managed
app_databaserouting now requires the exact server-derivedappdb_<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
tenantIdto 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/GrayMatterwas 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
CustomUsageTransactionRepositoryinstead of a single OR/LOWER ledger query;UsageTransactionkeeps 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/writeresolves 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, andThorApiAuthSurfaceSecurityTest.
Phase 4: Admin Management Surface
- Add lowercase kebab-case tenant schema lifecycle controllers.
- Allow only registry-backed, bundle-manifest-backed inspection.
- Emit
TenantSchemaAccessAuditfor 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 registeredTenantSchemaBundlerows 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 inSecurityConfigbefore the generic/v1/**GET fallback. The generated repositories/services remain available for internal ThorAPI-native orchestration. - Full Spring security coverage now proves a platform
ADMINreceives 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/preflightfor 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 inSecurityConfigbefore 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
TenantSchemaRegistryRTK/DataWorkbook routes. - Tenant schema validation and unsupported lifecycle operation requests now write explicit
TenantSchemaAccessAuditrows againstTenantSchemaOperation, and tenant-admin transactional entrypoints usenoRollbackFor = ResponseStatusException.classso 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}/auditwith 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, andbyoc_databaseas 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:
TenantDataPlaneBindingServicenow resolves a first-class binding plan for each successful deployment and persists the generatedApplicationDataPlaneBindingplusTenantRuntimeBindingas the authoritative data-plane/runtime record.app_schemaplacement uses a server-derived schema name from the activeTenantSchemaRegistryandApplication.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/VALIDATINGTenantSchemaRegistryrows, prefersACTIVE, rejects stale inactive duplicates, and rejects noncanonical registry schema names before anyApplicationDataPlaneBindingorTenantRuntimeBindingrow is written. app_databaseandbyoc_databaseplacements require approved deployment metadata for database host/name and managed credential references; environment-only BYOC placement strings do not create bindings. Managedapp_databasenames are still derived by the service and any explicit mismatchedapplicationDatabaseName/appDatabaseNameis 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_schemaandapp_schema; app-database/BYOC execution requires a runtime-specific data source. - Runtime execution for
app_databaseandbyoc_databasenow 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 generatedApplicationDataPlaneBinding. Managedapp_databaseplacement also requires the server-derivedappdb_<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
promotedFromBindingprovenance 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 recordsbind_runtimeinstead of creating a duplicate active write plane or false promotion. ApplicationDataPlaneBindinghistory 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
TenantSchemaOperationwithoperationType=bind_runtime; data-plane promotion writesoperationType=promote_data_plane. Both operations use the deployment actor as requester/approver andtenant-data-plane:<deploymentId>as the request correlation id. MultiCloudDeploymentServicestamps 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.environmentVariablesinto 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_databaseplacement from the active tenant registry andApplication.id, rewrite provisioneddb-0JDBC URLs to the server-ownedappdb_<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 siblingdb-0schemas fororg_schemaruntimes while allowing approvedapp_databaseplacement. - 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_ADMINcan be replaced with tenant-safe roles such asROLE_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_DENTISTand grant generated-object authorities such asTEETH_READ/APPOINTMENT_WRITE, while Valkyr platform/internal roles and authorities remain blocked. - Generated customer application scaffolds now emit per-model REST controllers, a tenant
TenantRbacAuthorizationguard, and method security. Generated app data access requires object authorities such asWIDGET_READ,WIDGET_CREATE, orWIDGET_WRITE;ROLE_ADMIN,ROLE_SYSTEM,ROLE_VALKYR_AGENT, andVALKYR_*authorities are treated as platform-only and do not grant tenant app data access. - Deployment surfaces now require authenticated callers explicitly in
SecurityConfigbefore the generic/v1GET fallback and at controller/delegate boundaries for generated deployment operations, Fargate upgrades, database connectivity checks, generated deployment secrets, and the/deploymentscompatibility path. /v1/runtime/isolationnow 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 apaidRuntimeIsolationReadyboolean alongside customer schema, database scope, shared-DB flag, deployment target/stage, and JDBC catalog/schema./v1/runtime/isolationreadiness now mirrors the execution guard:app_databaseandbyoc_databaseruntimes 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 asapplicationCredentialRefConfigured,tenantSchemaConnectionAligned, andapplicationDatabaseCatalogAligned, not credential references or direct schema-switching controls./v1/runtime/isolationalso runs a server-configuredTenantDatabasePrivilegeProbethrough 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 managedapp_databaseruntime 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 managedapp_databaseplacement reports a stale/friendly database name instead of the server-derivedappdb_<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-onlyapp_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_databaseregistries, carries a stable generatedApplication.idthrough 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, andTenantSchemaAdminPanel.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:
MemoryEntryControllerTestproves a GrayMatter-only hosted/v1/memory/writeresolvesTenantSchemaContextResolverbefore credit entitlement or persistence, and that missing tenant context prevents both entitlement debit and persistence. - Current evidence:
MemoryEntryServiceTestproves generatedMemoryEntrycreation entersTenantSchemaExecutionService.executeWritewith the resolved tenant context and stamps the resolved schema into semantic index requests, whileTenantSchemaExecutionServiceTestproves the write boundary lands unqualified rows with identical ids only in the selected organization schema. - Current evidence:
MemorySemanticSearchControllerTestandMemorySemanticSearchServiceTestprove semantic recall accepts app/project scope, forwards it intoSemanticSearchRequest, resolves the tenant read context throughTenantSchemaContextResolver.requireCurrentGrayMatterContext(..., relationshipScope), and filters candidates to the requested application/project after tenant-scope filtering. - Current evidence:
GrayMatterControlSurfaceControllerTestproves GrayMatter control, retrieval-tools, semantic-index manifest, object-graph shape, and retrieval-benchmark metadata routes resolveTenantSchemaContextResolverbefore returning planning/control metadata, and that missing tenant context blocks object-graph schema topology beforeOpenApiObjectGraphShapeServiceis called. - Current evidence:
RetrievalReceiptRuntimeServiceTest,SemanticIndexVectorSearchProviderTest,JpaMemoryEntrySparseSearchProviderTest,MemoryEntryGraphSearchProviderTest,MySqlFullTextMemoryEntrySparseSearchProviderTest,SemanticIndexSummarySearchProviderTest, andSemanticIndexTargetSearchProviderTestprove 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, filterMemoryEntrycandidates to the requested app/project, and stamp app-scoped receipts with the application schema. - Current evidence:
JpaMemoryEntrySparseSearchProviderTestandMemoryEntryGraphSearchProviderTestprove sparse and graph retrieval push app/project IDs into the DB-backedMemoryEntrySearchService.searchAcrossOwners(...)criteria query, whileMemoryEntrySearchServiceITproves the Criteria query itself filters through the generatedMemoryEntry.applicationandMemoryEntry.projectrelationships and excludes sibling project rows. Post-query candidate filtering remains in place as defense in depth. - Current evidence:
TenantSchemaExecutionServiceTestnow also covers a representative generated app-domainteethtable with the same domain object id in two siblingorg_<uuid>schemas, proving each tenant reads only its own domain row through the registry-derived execution boundary. - Current evidence:
TenantSchemaContextResolverTestandTenantSchemaExecutionServiceTestprove shared/platform execution still rejectsapp_databaseplacements, 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:
TenantDatabasePrivilegeProbeTestproves an H2 app-database user withSELECTonly onappdbcan read the generated-domainappdb.teethtarget while platformplatform.TenantSchemaRegistryand siblingsibling.teethtables remain unreadable, and also proves an overprivileged runtime user that can read the platform table is detected as not isolated. - Current evidence:
TenantDatabasePrivilegeProbeTestrejects unsafe server-configured table identifiers, andRuntimeIsolationControllerTestkeeps the privilege probe wired into/v1/runtime/isolationreadiness alongside live catalog/schema alignment. - Current evidence:
RuntimeIsolationControllerTest,customerInstanceOps.test.ts, andCustomerInstanceOpsDashboard.test.tsxprove 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:
TenantSchemaBundleLifecycleServiceTestproves a generatedTeethOpenAPI component is captured in the tenantTenantSchemaBundlemodel/table manifests, whileTenantSchemaAdminServiceTestproves admin object reads only use the active bundle allowlist for theteethtable and reject non-allowlisted domain objects. - Current evidence:
TenantSchemaAdminServiceTestproves admin allowlist parsing ignores generated model field entries such astoothNumberand generic OpenAPI schema metadata such astype: object, so only explicit bundle model/table entries become object inspection targets. - Current evidence:
TenantSchemaBundleLifecycleServiceTestproves tenant bundle registration rejects platform-owned model/table contamination such asPrincipal,Customer,Invoice,UsageTransaction, payment, credit, and Valkyr billing control objects before those objects can be persisted into a tenant manifest allowlist. - Current evidence:
TenantSchemaAdminServiceTestproves blank and too-short reasons block admin reads before schema inspection/audit writes; validate success, validate failure, and unsupported operation denial writeTenantSchemaAccessAuditrows; and every transactional admin entrypoint keeps expectedResponseStatusExceptionpaths from rolling back audit records. - Current evidence:
TenantSchemaAdminServiceTestproves 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:
TenantSchemaAdminServiceTestproves tenant object inspection validates the canonical registry schema before bundle lookup, readsapp_schemabundle objects only from the server-derived application schema, rejectsapp_database/byoc_databasebundle object reads rather than falling back to the registry org schema without a runtime-specific admin datasource, and allows app-database inspection only whenTenantSchemaExecutionServiceenters a matching runtime admin data plane. - Current evidence:
TenantSchemaAdminServiceTestandTenantSchemaAdminPanel.test.tsxprove tenant schema health is placement-aware: app-schema bundle tables are checked in the server-derivedorg_<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:
SecureKMSTenantScopeTestproves 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:
RoleManagementPolicyTestandRoleManagementServiceTestprove 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 staleROLE_ADMINprincipal with tenant-safe roles. - Current evidence:
AppCodegenScaffoldServiceTestcompiles generated backend scaffold output and invokes the generated tenant RBAC guard, proving object authorities such asWIDGET_READ,WIDGET_CREATE,TEETH_READ, andROLE_TEETH_CREATEauthorize generated app data whileROLE_ADMIN,ROLE_ADMINcombined with object authorities,VALKYR_SCHEMA_READ, andVALKYR_SCHEMA_READcombined with role-prefixed object authorities do not. - Current evidence:
ThorAPIControllerAuthSemanticsTestreflects every ThorAPI controller route and requires theADMIN/DEVELOPERguard 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:
ThorApiAuthSurfaceSecurityTestkeeps 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-historyand/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/tablesand/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 platformADMINcannot browse generated tenant isolation DataWorkbook routes. - Current evidence:
WorkflowMetricsAspectTestproves workflow-specific WebSocket metric emission delegates to the centralValkyrAclService.hasPermission(..., READ)decision for the generatedWorkflowobject 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, andValkyrAiPermissionEvaluatorTestprove SpringPermissionEvaluator.hasPermission(...)and concrete ACLAcl.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:
MemoryApiDelegateOverrideTestproves/v1/memory/runsuses the bounded custom usage telemetry repository when available and does not call generatedUsageTransactionowner/customer repository methods on that hot path;CreditSchemaContractTestproves the ThorAPI spec and regeneratedUsageTransactionentity retain the memory-ledger compound indexes. - Current evidence:
TenantIsolationOpenApiContractTestproves 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:
TenantIsolationOpenApiContractTestalso 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:
TenantIsolationOpenApiContractTestproves 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, andTenantSchemaAdminPanel.test.tsxprove 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, generatedSchemaEvolutionLedgerDataWorkbook 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:
TenantDataPlaneBindingServiceTestproves 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-widefindAll()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 apromote_data_planeTenantSchemaOperationwith deployment actor approval and request correlation. - Current evidence:
TenantSchemaAdminServiceTestproves 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.shis 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.shenforces the tenant isolation release gate before non-dry-run production deployment API calls, anddeploy/tests/deployment-launcher-contract-test.shproves production deploys fail closed when the evidence path is missing or required p95 evidence is incomplete. - Current evidence:
MultiCloudDeploymentServiceTestproves dashboard/API production tenant runtime specs fail closed unless fresh inline release evidence is supplied throughVALKYRAI_TENANT_ISOLATION_RELEASE_EVIDENCE_JSONorVALKYRAI_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/fargateinstead of allowing a staging Lightsail runtime to be promoted through an ungated or malformed production path. - Current evidence:
DeploymentWizardPanel.test.tsx,LightsailDeploymentServiceTest, anddeploy/tests/deployment-launcher-contract-test.shprove dashboard, Java Lightsail, and shell-generated runtime specs enableVALKYRAI_SCHEMA_RECONCILIATION_ENABLED=trueand do not emit the removed rawVALKYRAI_SCHEMA_AUTO_EXPAND_COLUMNSstartup-mutator flag. - GrayMatter-only tests now cover platform-controller authorization order, tenant context resolution before persistence, generated
MemoryEntryservice writes entering the tenant execution boundary, and H2-backed tenant-schema write isolation for identical ids. - Current evidence:
ValorIDEExecModuleTestproves 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:
SwarmCommandServiceTestproves 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, andswarmCommandUtils.test.tsprove/swarm-ops/commandreturns server-issuedcommandIdand deterministicrejectionCodereceipts, while the ValorIDE Swarm Control Panel dispatches generatedSwarmMessagepayloads 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.tsxproves 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:
AppCodegenScaffoldServiceTestincludes a generated dentistryTeethpaid-runtime scaffold contract proving tenant object authorities authorize generated-domain data while platform RBAC signals cannot authorize the same object. - Current evidence:
RoleManagementPolicyTestandRoleManagementServiceTestcover 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/appsexposes 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}/launchissues 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
- Two organizations can create identical domain object IDs without either org reading the other's data.
- GrayMatter-only users write memory data into their organization schema while authorization is decided by Valkyr-managed RBAC.
- Paid runtime customers can use tenant-managed RBAC for generated app/domain tables.
- Each paid customer application has an active
ApplicationDataPlaneBinding. org_schema,app_schema,app_database, andbyoc_databasedeployments resolve writes through the binding rather than request parameters.- App/project GrayMatter memory follows the isolated application data plane when the application is promoted beyond
org_schema. - Anonymous users cannot call GrayMatter, app generation, deployment, or tenant-schema endpoints.
- Valkyr
ADMINcannot browse tenant schema data through generic generated DataWorkbook routes. - Valkyr
ADMINcan inspect tenant data only through audited schema-scoped admin endpoints. - Runtime isolation endpoint reports customer schema, customer database scope, application data-plane mode, and shared DB disabled for paid runtimes.
- Deployment validation rejects shared ValkyrAI DB targets for customer app runtimes.
- All hot tenant relationship/query paths have explicit spec-level indexes.
- No implementation edits generated output directly.
- 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, andapp_databasemodes 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
TenantDatabasePrivilegeProbeTestand runtime readiness reporting through/v1/runtime/isolation. - Verify app database credentials cannot read sibling app schemas/databases; covered by
TenantDatabasePrivilegeProbeTestusing siblingteethtables. - 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:
TenantIsolationOpenApiContractTestcovers registry, bundle, runtime binding, operation/audit write, GrayMatter retrieval, semantic index, app/project memory, and deployment polling index declarations inapi.hbs.yaml. - Current query-shape evidence:
TenantIsolationOpenApiContractTest,TenantDataPlaneBindingServiceTest, andTenantSchemaAdminServiceTestcover 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:
TenantIsolationOpenApiContractTestguards against adding tenant isolation SQL migration scripts forTenantSchemaRegistry,ApplicationDataPlaneBinding,TenantRuntimeBinding,TenantSchemaBundle,TenantSchemaOperation, orTenantSchemaAccessAudit. - 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
- 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? - Should app-private tables in
org_schemamode use an app prefix for collision avoidance, whileapp_schemaandapp_databasemodes use plain generated names? - Should tenant schema lifecycle operations require two-person approval for export, clone, restore, promote, and delete?
Risks
- Existing handwritten minimum table DDL can diverge from ThorAPI-generated models unless it is removed from the target path.
- Schema switching on shared pools can leak state if not reset or isolated by tenant-scoped pools.
- Generated DataWorkbook surfaces can accidentally expose tenant data if platform admin UX points at customer schemas directly.
- Tenant RBAC and Valkyr platform RBAC can be confused if role names overlap without explicit runtime scope.
- Missing compound indexes on registry, memory, semantic index, and audit tables can produce production timeouts.
- 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.