ADR-0015: Factory tenancy and scope under canonical ADR-0100¶
Decision
This page records a decision and its status. A Proposed decision is not binding; an Accepted decision is binding on the Factory until amended or superseded.
- Status: Accepted 2026-10-09 by the product owner (amends ADR-0011, which stays in force except where this ADR changes it)
- Date: 2026-10-09
- Deciders: Dmitry Khaymov (product owner), 2026-10-09; proposed by the 2026-10 independent review
- Tags: multi-tenancy, scope, identity, isolation
Context¶
ADR-0011 adopts a shared tenant-aware model with database-per-tenant as a premium tier and a Factory-specific enforcement chain (token claim → TenantContext → handler assertion → row filter → event filter → per-tenant secrets). The user confirmed on 2026-10-08 that the canonical ConnectSoft decisions are binding on the Factory:
- ADR-0100 (ConnectSoft.Documentation, accepted 2026-05-01) defines canonical tenant tokens per layer (
tidclaim;X-Tenant-Iduntrusted until the gateway validates it;tenant-idfor gRPC and messaging metadata, including Orleans call context), a deterministic resolution order, four installation modes (SharedDb, DatabasePerTenant, ResidencySilo, DedicatedSingleTenant), fail-closed behaviour on conflicting evidence, and the rule that shared-DB loads never bypass a tenant predicate. - ADR-0101 (accepted 2026-06-30) assigns token issuance to the Authorization Server, accounts/memberships to the Identity Service, route policy to the gateway, domain and tenant authorization to backends, and frontend auth state to the Blazor Shell.
- The Factory's own contracts (
AgentTraceContext,AgentEventEnvelope, retrieval options) currently carry no tenant or project scope at all, so the ADR-0011 chain is not implemented in the Factory libraries. - Generated SaaS products have their own tenants; a Factory customer tenant and a generated-product tenant are different things.
Decision¶
- The Factory inherits ADR-0100 and ADR-0101 as written. It does not define its own tenant tokens, resolution order or trust boundary. ADR-0011's enforcement chain is restated as the Factory's application of ADR-0100 in SharedDb mode; the "premium database-per-tenant tier" becomes the canonical DatabasePerTenant mode, and ResidencySilo and DedicatedSingleTenant become supported modes of the Factory as well.
- On top of the tenant, the Factory defines a scope hierarchy: organization (tenant) → workspace/project → environment → run → step/attempt, plus source scope (which repositories, documents and tools a run may touch). Every Factory contract (run request, execution snapshot, tool invocation, retrieval request, artifact reference, usage record, lifecycle event) carries the trusted tenant id and project id, derived from the authenticated context, never from prompt text or caller-controlled headers.
- Authorization is enforced at the backend for every read and write, including retrieval before top-k selection (ADR-0013), tool execution, artifact access and projections. Selecting a tenant or project in the Studio grants nothing.
- A Factory tenant and a generated-product tenant are distinct identities and stores. Any mapping between them is an explicit, documented contract of the generation recipe, never an implicit identity share.
- The Factory defines seven roles under canonical identity, assigned per project except Platform admin (decided by the product owner on 2026-10-09, decision D18):
| Role | Scope of assignment | May do |
|---|---|---|
| Requester | project | Submit runs within project scope and budget; inspect own runs, artifacts and usage; cancel own runs |
| Reviewer | project | Decide approvals (accept, reject, request changes) on an exact run, artifact or action version, within authority and expiry; never on a run they requested |
| Asset maintainer | project | Author agents, skills, tool bindings and workflows; run evaluations; publish a release only with evaluation evidence attached |
| Operator | project | Retry, resume, cancel and replay runs; manage workers and sandboxes within scope; no approval authority |
| Workspace admin | project | Everything above for the project; manage membership and role assignments; set project policy that is stricter than platform policy, never looser; may decide approvals on runs they did not request |
| Platform admin | tenant | Everything; owns global policy, model profiles, provider connections and tenant-wide settings; may break glass on an approval with an audited reason |
| Observer | project or tenant | Read-only access to runs, artifacts, decisions, usage and audit for auditors and stakeholders; no commands |
-
Role rules:
-
Roles are issued as claims by the Authorization Server (canonical ADR-0101) and enforced by every backend per request; menu visibility in the Studio grants nothing.
- Assignment is per project; Platform admin is the only tenant-wide role. Membership itself is per tenant (Identity Service).
- Separation of duties: the requester of a run cannot approve any proposal from that run, even if they also hold Reviewer or Workspace admin.
- Delegation: a role holder may delegate the same or a lesser role to another member for a bounded period; every delegation is recorded with grantor, grantee, scope, expiry and reason, is revocable at any time, and expires automatically. A delegated Reviewer inherits the separation-of-duties rule.
- Policy layering: platform policy is the ceiling; a project policy may tighten it (more approval gates, lower budgets, fewer tools) and may never loosen it.
Consequences¶
Positive¶
- One tenancy model across the Factory, the templates and generated products, owned where the user placed it.
- Makes explicit that the Factory libraries currently carry no scope, which is the root of the retrieval and tool isolation gaps.
- Supports the four canonical modes without inventing a Factory variant.
Negative / trade-offs¶
AgentTraceContext, envelopes, retrieval and tool contracts need additive scope fields (implementation work outside this task).- Pages that describe the ADR-0011 chain as implemented must be relabelled Target.
Neutral¶
- Marketplace and knowledge sharing across tenants remain explicit, classified publications, as ADR-0011 already stated.
Alternatives considered¶
| Alternative | Why not chosen |
|---|---|
| Keep ADR-0011 as a standalone Factory model | Duplicates and partially contradicts the binding canonical decision (two modes vs four; Factory-specific token chain). |
| Leave Factory roles open | The review first left roles as open questions; the product owner chose on 2026-10-09 to fix them here so that approvals, publication and delegation have one authoritative definition. |
| Share identity between Factory tenants and generated-product tenants | Breaks product isolation and the canonical trust boundary. |
Evidence¶
- ConnectSoft.Documentation
Docs/decisions/adr/adr-0100-connectsoft-saas-multitenancy-resolution.md,adr-0101-connectsoft-identity-platform.md ConnectSoft.Extensions.AI.Factory.Abstractions/src/.../AgentTraceContext.cs;ConnectSoft.Extensions.AI.Factory.Messaging/src/.../AgentEventEnvelope.csConnectSoft.Extensions.Saas.*repositories (tenant context, middleware, NHibernate filters, Orleans, options)- Verification record V-A3, V-A9, V-C13; decision log D17, D18 (role answers), D21 (action classes) and Q-03/Q-06/Q-07
Related¶
- ADR-0011 — amended by this ADR
- ADR-0008 (review note: Authorization Server is the only issuer per ADR-0101)
- ADR-0013
- Multi-Tenancy — to be revised to this decision