---
title: "Orleans.Lattice.Api.Schema.Grpc API reference"
url: "https://nsta1.github.io/Orleans.Lattice/docs/lattice.api.schema.grpc/api.html"
source: "https://github.com/NSTA1/Orleans.Lattice/blob/release/9.9/docs/lattice.api.schema.grpc/api.md"
package: "Orleans.Lattice.Api.Schema.Grpc"
version: "9.9.0"
documents: "Orleans.Lattice 9.9.0 (release line 9.9)"
built: "2026-10-04"
all-pages: "https://nsta1.github.io/Orleans.Lattice/llms.txt"
bundle: "https://nsta1.github.io/Orleans.Lattice/docs/lattice.api.schema.grpc/llms-full.txt"
---
# Orleans.Lattice.Api.Schema.Grpc API reference

Part of the [Api.Schema.Grpc documentation](README.md).

The public surface is the typed client, the server-side options, the registration extensions, the authorization and identity seams (with the operation enum and authorization-context struct), and the wire message records. The gRPC service, method definitions, marshallers, interceptor, and the default header credential bridge / options auth-scheme source are internal and are described by behaviour in [Architecture](architecture.md).

The wire message records are Orleans-serialized (`[GenerateSerializer]`) with stable aliases prefixed `oisg.`. The facade's own shared abstractions record (`LatticeSchemaCapabilities`) uses the `ois.` prefix, and the schema engine's records the wire carries (`LatticeSchemaPolicy`, `LatticeSchemaDeadLetterEntry`, `LatticeSchemaRemediationReport`, and the rest) keep the engine's own `ols.` aliases.

## Registration

### `LatticeSchemaApiGrpcServiceCollectionExtensions`

Static extensions.

- `IServiceCollection AddLatticeSchemaApiGrpc(this IServiceCollection services, Action<LatticeSchemaApiGrpcOptions>? configure = null)`

  Registers the binding: the method-definition singleton, the server-side service, the default-deny authorizer, the header credential bridge, the options-backed auth-scheme source, and the authorization interceptor. The interceptor is registered globally but scopes enforcement to the schema control-API service by service-name prefix, so unrelated gRPC services on the same host are unaffected. Every seam and the service are registered with `TryAdd`, so a repeat call keeps the first registration of each; the interceptor, added to the global gRPC options, is appended again on each call. Throws `ArgumentNullException` when `services` is null.

- `IEndpointRouteBuilder MapLatticeSchemaApiGrpc(this IEndpointRouteBuilder endpoints)`

  Maps the schema control-API RPC routes. The host must have called `AddLatticeSchemaApiGrpc` and must expose the control facade (via `AddLatticeSchemaApi`) in the same service provider first. Throws `ArgumentNullException` when `endpoints` is null.

## Client

### `LatticeSchemaApiGrpcClient`

The public typed client. Wraps a `CallInvoker` and the code-first method definitions; carries no transport policy of its own.

- `static LatticeSchemaApiGrpcClient Create(CallInvoker callInvoker, IServiceProvider serializerProvider)` - builds a client over the invoker, resolving the per-message Orleans serializers from `serializerProvider` (which must have `AddSerializer()` registered). Throws `ArgumentNullException` when either argument is null.

Methods (one per RPC):

| Method | Signature |
|---|---|
| `SetPolicyAsync` | `Task SetPolicyAsync(string treeId, LatticeSchemaPolicy policy, CancellationToken cancellationToken = default)` |
| `ClearPolicyAsync` | `Task<bool> ClearPolicyAsync(string treeId, CancellationToken cancellationToken = default)` |
| `GetPolicyAsync` | `Task<LatticeSchemaPolicy?> GetPolicyAsync(string treeId, CancellationToken cancellationToken = default)` |
| `ListDeadLettersAsync` | `IAsyncEnumerable<LatticeSchemaDeadLetterEntry> ListDeadLettersAsync(string treeId, CancellationToken cancellationToken = default)` |
| `CountDeadLettersAsync` | `Task<int> CountDeadLettersAsync(string treeId, CancellationToken cancellationToken = default)` |
| `SetVersionConfigAsync` | `Task SetVersionConfigAsync(string treeId, LatticeSchemaVersionConfig config, CancellationToken cancellationToken = default)` |
| `GetVersionConfigAsync` | `Task<LatticeSchemaVersionConfig?> GetVersionConfigAsync(string treeId, CancellationToken cancellationToken = default)` |
| `AdvanceTargetVersionAsync` | `Task<LatticeSchemaVersionConfig> AdvanceTargetVersionAsync(string treeId, uint newTargetVersion, CancellationToken cancellationToken = default)` |
| `AdvanceAndMigrateAsync` | `Task<LatticeSchemaRemediationReport> AdvanceAndMigrateAsync(string treeId, uint newTargetVersion, CancellationToken cancellationToken = default)` |
| `MigrateToTargetVersionAsync` | `Task<LatticeSchemaRemediationReport> MigrateToTargetVersionAsync(string treeId, CancellationToken cancellationToken = default)` |
| `ClearVersionConfigAsync` | `Task<bool> ClearVersionConfigAsync(string treeId, CancellationToken cancellationToken = default)` |
| `RemediateAsync` | `Task<LatticeSchemaRemediationReport> RemediateAsync(string treeId, LatticeValueTransform transform, LatticeSchemaPolicy targetPolicy, CancellationToken cancellationToken = default)` |
| `GetRemediationStatusAsync` | `Task<LatticeSchemaRemediationReport> GetRemediationStatusAsync(string treeId, CancellationToken cancellationToken = default)` |
| `ScanComplianceAsync` | `Task<LatticeSchemaComplianceReport> ScanComplianceAsync(string treeId, CancellationToken cancellationToken = default)` - deprecated (`LATTICE0002`) |
| `StartComplianceScanAsync` | `Task<LatticeOperationHandle> StartComplianceScanAsync(string treeId, string? operationId = null, CancellationToken cancellationToken = default)` |
| `GetComplianceScanStatusAsync` | `Task<LatticeOperationStatus?> GetComplianceScanStatusAsync(string operationId, CancellationToken cancellationToken = default)` |
| `ListComplianceScansAsync` | `Task<LatticeOperationPage> ListComplianceScansAsync(LatticeOperationListRequest request, CancellationToken cancellationToken = default)` |
| `CancelComplianceScanAsync` | `Task<LatticeOperationStatus?> CancelComplianceScanAsync(string operationId, CancellationToken cancellationToken = default)` |
| `ProbeCapabilitiesAsync` | `Task<LatticeSchemaCapabilities> ProbeCapabilitiesAsync(string treeId, CancellationToken cancellationToken = default)` |
| `GetAuthSchemeAsync` | `Task<IReadOnlyList<AuthSchemeDescriptor>> GetAuthSchemeAsync(CancellationToken cancellationToken = default)` |
| `StartRemediationAsync` | `Task<LatticeOperationHandle> StartRemediationAsync(string treeId, LatticeValueTransform transform, LatticeSchemaPolicy targetPolicy, string? operationId = null, CancellationToken cancellationToken = default)` |
| `StartMigrationAsync` | `Task<LatticeOperationHandle> StartMigrationAsync(string treeId, string? operationId = null, CancellationToken cancellationToken = default)` |
| `StartAdvanceAndMigrateAsync` | `Task<LatticeOperationHandle> StartAdvanceAndMigrateAsync(string treeId, uint newTargetVersion, string? operationId = null, CancellationToken cancellationToken = default)` |
| `GetSchemaOperationStatusAsync` | `Task<LatticeOperationStatus?> GetSchemaOperationStatusAsync(string operationId, CancellationToken cancellationToken = default)` |
| `ListSchemaOperationsAsync` | `Task<LatticeOperationPage> ListSchemaOperationsAsync(LatticeOperationListRequest request, CancellationToken cancellationToken = default)` |
| `CancelSchemaOperationAsync` | `Task<LatticeOperationStatus?> CancelSchemaOperationAsync(string operationId, CancellationToken cancellationToken = default)` |

Methods that take a tree id throw `ArgumentException` on a null or empty id. `SetPolicyAsync` and `RemediateAsync` throw `ArgumentNullException` on a null policy or target policy (the version config and value transform are value types). `ListDeadLettersAsync` is server-streaming and re-exposes the server stream as an `IAsyncEnumerable<LatticeSchemaDeadLetterEntry>`. `ProbeCapabilitiesAsync` reports the caller's allowed-operation set (`LatticeSchemaCapabilities`) with no side effects; it never replaces the fail-closed authorization each real RPC still performs. `GetAuthSchemeAsync` is unauthenticated - callable before any credential is acquired. `ScanComplianceAsync` calls the blocking `ScanCompliance` RPC and is deprecated (`LATTICE0002`, removed in the next major version); `StartComplianceScanAsync` starts the same scan as a tracked operation over the `StartComplianceScan` RPC and returns at once, and the `GetComplianceScanStatus`, `ListComplianceScans` and `CancelComplianceScan` RPCs follow it (status and cancel return `null` for an operation the caller may not see). The server answers `Unimplemented` when its host registers no `ILatticeSchemaComplianceOperations`. See [Schema compliance operations](../lattice.api.schema/operations.md).

`AdvanceAndMigrateAsync`, `MigrateToTargetVersionAsync` and `RemediateAsync` call blocking RPCs and are **deprecated** (`LATTICE0002`), for removal in the next major version, together with the `AdvanceAndMigrate`, `MigrateToTargetVersion` and `Remediate` RPCs. The start methods call the accept-then-poll `StartRemediation`, `StartMigration` and `StartAdvanceAndMigrate` RPCs, which return a `LatticeOperationHandle` as soon as the run is accepted; `GetSchemaOperationStatus`, `ListSchemaOperations` and `CancelSchemaOperation` read, page and cancel the operation. A status read or cancel of an operation the caller may not see returns `null`. See [Schema operations](../lattice.api.schema/operations.md).

## Server-side options

### `LatticeSchemaApiGrpcOptions`

See [Configuration](configuration.md) for the full table. Properties: `bool RequireAuthorization` (default `true`), `string CredentialHeaderName` (default `authorization`), `string CredentialScheme` (default `Bearer`), `string ActiveTenantHeaderName` (default `lattice-active-tenant`), and `IList<AuthSchemeDescriptor> AdvertisedAuthSchemes` (empty by default).

## Authorization and identity seams

### `ILatticeSchemaApiAuthorizer`

The transport meta-authorization seam. A host supplies an implementation to decide whether an inbound call may drive the schema control API.

- `Task<bool> IsAuthorizedAsync(LatticeSchemaApiAuthorizationContext authorizationContext, CancellationToken cancellationToken)` - `true` to allow, `false` to reject with `PermissionDenied`.

### `DenySchemaApiAuthorizer` : `ILatticeSchemaApiAuthorizer`

The default authorizer, registered automatically (via `TryAdd`, so a host-registered authorizer wins), that rejects every protected call so a host that maps the surface without configuring authorization fails closed.

### `AllowAllSchemaApiAuthorizer` : `ILatticeSchemaApiAuthorizer`

An opt-in authorizer that permits every protected call, for trusted-network deployments behind a separate authentication boundary. Register it explicitly to override the default-deny posture.

### `ILatticeSchemaApiCredentialBridge`

The identity seam that lifts the caller identity on an inbound call into an ambient `LatticeCredential` so the schema access gate can resolve the caller's subject.

- `LatticeCredential? Resolve(ServerCallContext context)` - the resolved credential, or `null` when the call carries none (the caller is then anonymous, and denied when auth-backed schema control is active). The built-in default reads `CredentialHeaderName` and strips a case-insensitive `CredentialScheme` prefix; a host registers its own implementation for a bespoke identity source.

### `ILatticeSchemaApiAuthSchemeSource`

Supplies the advertisement the unauthenticated `GetAuthScheme` RPC returns.

- `AuthSchemeAdvertisement GetAdvertisement()` - the current advertisement (the built-in default projects `AdvertisedAuthSchemes`, so it is empty when nothing is configured). An implementation must return only public configuration - never a secret.

### `LatticeSchemaApiOperation`

Identifies which control-API operation an inbound call invokes, so an authorizer can make per-operation decisions. Values: `SetPolicy`, `ClearPolicy`, `GetPolicy`, `StreamDeadLetters`, `CountDeadLetters`, `SetVersionConfig`, `GetVersionConfig`, `AdvanceTargetVersion`, `AdvanceAndMigrate`, `MigrateToTargetVersion`, `ClearVersionConfig`, `Remediate`, `GetRemediationStatus`, `ScanCompliance`, `ProbeCapabilities`, and `Unknown` (an unrecognised method, presented so a deny-by-default policy refuses it rather than treating it as a benign read), followed - appended after `Unknown` so the shipped numeric values stay stable - by `StartComplianceScan`, `GetComplianceScanStatus`, `ListComplianceScans` and `CancelComplianceScan` (#4126), then `StartRemediation`, `StartMigration`, `StartAdvanceAndMigrate`, `GetSchemaOperationStatus`, `ListSchemaOperations` and `CancelSchemaOperation`. A start targets its tree; a status, list or cancel names an operation rather than a tree, so its `TargetId` is `null` and the facade scopes it to the caller.

### `LatticeSchemaApiAuthorizationContext`

A `readonly struct` describing an inbound call to the authorizer.

- Constructor: `LatticeSchemaApiAuthorizationContext(ServerCallContext call, LatticeSchemaApiOperation operation, string? targetId)`. Throws `ArgumentNullException` when `call` is null.
- `ServerCallContext Call` - the underlying gRPC call context (headers, deadline, peer).
- `LatticeSchemaApiOperation Operation` - the operation being invoked.
- `string? TargetId` - the governed tree id the call targets; every protected schema RPC carries one. It is the id exactly as the request carries it - the caller's tenant-local name - because the transport gate runs before the facade scopes that name into an asserted tenant's `t/{tenant}/{name}` namespace; the facade's own scope authorization then runs against the effective id.

### Authorization interceptor

The internal authorization interceptor runs the registered `ILatticeSchemaApiAuthorizer` on every protected call while `RequireAuthorization` is `true` (the default), exempts only `GetAuthScheme`, and presents an unrecognised method as `Unknown`. A host must configure authorization deliberately or place the endpoint behind a trusted boundary and set `RequireAuthorization = false`. Server faults that the binding does not map to a specific status are returned with a safe gRPC status code (see [Architecture](architecture.md#status-mapping)).

`GetAuthScheme` advertises the configured public auth schemes to unauthenticated callers. It must never return secrets or user-specific data.

## Wire message records

Each RPC's request and response is one of these Orleans-serialized records, except the dead-letter stream and the capability probe, which carry schema-package record types directly (see the note below the table). Properties marked `required` must be set by the caller.

| Record | Members |
|---|---|
| `SchemaTreeRequest` | `required string TreeId`. |
| `SetPolicyRequest` | `required string TreeId`, `required LatticeSchemaPolicy Policy`. |
| `SetVersionConfigRequest` | `required string TreeId`, `required LatticeSchemaVersionConfig Config`. |
| `AdvanceVersionRequest` | `required string TreeId`, `required uint NewTargetVersion`, `string? OperationId` (used by `StartAdvanceAndMigrate`). |
| `RemediateRequest` | `required string TreeId`, `required LatticeValueTransform Transform`, `required LatticeSchemaPolicy TargetPolicy`, `string? OperationId` (used by `StartRemediation`). |
| `SchemaMigrationStartRequest` | `required string TreeId`, `string? OperationId`. |
| `SchemaOperationRequest` | `required string OperationId`. |
| `SchemaOperationStatusResponse` | `LatticeOperationStatus? Status` (`null` when not found). |
| `AuthSchemeAdvertisementRequest` | (empty). |
| `SchemaAckResponse` | (empty). |
| `SchemaRemovedResponse` | `required bool Removed`. |
| `GetPolicyResponse` | `required bool Found`, `LatticeSchemaPolicy? Policy`. |
| `SchemaCountResponse` | `required int Count`. |
| `GetVersionConfigResponse` | `required bool Found`, `LatticeSchemaVersionConfig Config`. |
| `VersionConfigResponse` | `required LatticeSchemaVersionConfig Config`. |
| `SchemaRemediationReportResponse` | `required LatticeSchemaRemediationReport Report`. |
| `SchemaComplianceReportResponse` | `required LatticeSchemaComplianceReport Report`. |
| `AuthSchemeAdvertisement` | `IReadOnlyList<AuthSchemeDescriptor> Schemes`. |
| `AuthSchemeDescriptor` | `required string SchemeId`, `string DisplayName`, `IReadOnlyDictionary<string, string> Parameters`. |

`SetPolicy` and `SetVersionConfig` return the empty `SchemaAckResponse`; `ClearPolicy` and `ClearVersionConfig` return `SchemaRemovedResponse`. `StreamDeadLetters` takes a `SchemaTreeRequest` and streams `LatticeSchemaDeadLetterEntry` values directly (no wrapper record). `ProbeCapabilities` returns a `LatticeSchemaCapabilities` value directly. The start RPCs return a `LatticeOperationHandle`, and `ListSchemaOperations` takes a `LatticeOperationListRequest` and returns a `LatticeOperationPage`, directly; those types are defined in `Orleans.Lattice.Api.Abstractions`. Both of those types are defined in the schema packages, not in this binding. `GetAuthScheme` takes `AuthSchemeAdvertisementRequest` and returns `AuthSchemeAdvertisement`; the typed client projects that response to `IReadOnlyList<AuthSchemeDescriptor>`.

## Serialization aliases

### `GrpcSchemaTypeAliases`

A public static class holding the stable Orleans serialization alias constants for the wire message records, referenced by their `[Alias(...)]` attributes so the wire contract stays stable across renames. Contract versioning is additive-only: new fields use new `[Id(n)]` values, and aliases or field numbers are never renumbered, so a newer response can decode under an older client.
