---
title: Capability reference
editUrl: https://github.com/Cratis/Arc.TypeScript/edit/main/Documentation/reference/capabilities.md
description: The status of every Arc capability in Arc for TypeScript, the TypeScript contract behind it, the spec or check that proves it, and where it deliberately differs from Arc on .NET.
---


This page is the single status and parity reference for Arc for TypeScript. The shared [Arc capability matrix](/arc/capabilities/) covers C#, Kotlin, and Java; this page records, for TypeScript, whether each capability exists, where its boundary lies, and which spec, contract test, or sample proves it. The wire behavior every implementation follows is the [Arc HTTP contract](/arc/http-contract/). Other pages link here instead of restating status.

:::caution[Source preview, no full parity]
No package is published to npm, and Arc for TypeScript does not have full parity with Arc on .NET. Package names and APIs can still change.
:::

## Status key

| Status | Meaning |
| --- | --- |
| Supported | Implemented and covered by passing specs, contract tests, or runnable samples in this repository. Supported describes TypeScript behavior; it is not a parity claim. |
| Bounded | Supported within the boundary the row states. |
| Experimental | Implemented and checked, but the API and guarantees can change. |
| Not implemented | Not available. |
| Not applicable | Belongs to another platform's host or toolchain. |

Evidence paths are relative to the repository root. Spec folders follow `for_<Subject>/when_<action>`. Each row states the contract in brief; where a capability has more boundaries, a bullet under its table, headed with the capability name, lists them.

## Commands

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| Model-bound commands | Supported | `@command()` classes with Fundamentals `@field` declarations and an instance `handle()`; `defineCommand` with Zod remains the low-level path. See [Model-bound commands](/arc/backend/typescript/commands/model-bound/). | `Source/Core/commands/modelBound/for_compileCommand`, `Source/Core/for_ArcApplicationBuilder/when_building_model_bound_artifacts`, `Samples/Tasks/Features/Tasks/Registration/for_RegisterTask` |
| Artifact discovery | Bounded | `builder.add(...)` takes an explicit catalog; `discover()` imports exported artifacts from a dedicated file-URL folder, derives namespaces from paths, and rejects conflicting namespaces and mixed JS/TS output. No bundler or assembly scanning. | `Source/Core/for_ArcApplicationBuilder/when_discovering_artifacts`, `.../when_adding_artifacts` |
| Validate without executing | Supported | `POST <route>/validate` runs authorization, global command filters, and validation only; a command named `Validate` executes on its own route. | `Source/Core/for_ArcServer/when_validating_a_command`, `ContractTests/Http/conformance.test.mjs` |
| Global command filters | Bounded | Scoped `AuthorizationCommandFilter` services always precede `CommandPipelineFilter` services, independent of registration order. Context-value/key resolution on valid input precedes context-aware authorization filters; these providers/resolvers must not perform protected mutations. Decorators and builder registration support both; result fragments merge and stop on failure on execute and `/validate`. Express, Fastify, and Hono execute and `/validate` denial/allow are paired with .NET; TypeScript traces verify ordering and that denial skips validator construction and handling. Existing per-definition `CommandFilter<T>` callbacks still aggregate. See [Command filters](/arc/backend/typescript/commands/command-filters/). | `Source/Core/for_ArcApplicationBuilder/when_running_command_filters`, `Source/Core/for_ArcServer/when_authorizing_by_operation_name`, `ContractTests/Http/conformance.test.mjs` |
| `provide()` and outcomes | Supported | `provide()` runs after validation and may short-circuit with `rejected(...)` or `denied(...)`. Only helper-created values are outcomes; `isOutcome` recognizes them. See [Command outcomes](/arc/backend/typescript/commands/command-outcomes/). | `Source/Core/for_ArcServer/when_providing_a_command`, `Source/Core/for_ArcApplicationBuilder/when_providing_a_model_bound_command`, `Source/Core/commands/for_Outcome` |
| Several return values and response value handlers | Bounded | `tuple(...)` flattens branded groups; at most one unhandled value becomes the response, and scoped `CommandResponseValueHandler`s process every other value in deterministic name order. | `Source/Core/commands/for_tuple`, `Source/Core/for_ArcServer/when_processing_command_response`, `Source/Core/for_ArcApplicationBuilder/when_registering_a_response_handler` |
| Execution scopes | Supported | Low-level `scopes` complete once in reverse order, including a scope whose `begin` threw; a failed completion removes the response. Model-bound commands use command execution runners instead. | `Source/Core/for_ArcServer/when_beginning_a_command_scope`, `.../when_completing_a_command_scope`, `Source/Core/for_ArcApplicationBuilder/when_executing_command_runners` |
| Command operations | Bounded | `CommandOperation` declarations are preflighted, executed in order, and compensated in reverse after a known uncommitted failure; `Unknown` and `Mixed` fail closed. No distributed transaction, durable recovery, or crash guarantee. See [Command operations](/arc/backend/typescript/commands/operations/). | `Source/Core/for_ArcServer/when_executing_an_operation`, `.../when_an_operation_fails`, `.../when_a_commit_is_unknown`, `.../when_declaring_nested_operations` |
| Command context and keys | Bounded | `CommandContext` carries the command, a key resolved once, case-insensitive values, and request identity. `@key()`, `getKey()`, and scoped `CommandKeyResolver`s; `abortSignal()`, `commandContext()`, and `provided(Type)` markers. See [Command context](/arc/backend/typescript/commands/command-context/). | `Source/Core/for_ArcServer/when_resolving_command_keys`, `Source/Core/for_ArcApplicationBuilder/when_resolving_command_keys`, `.../when_resolving_command_arguments` |
| Command read models by key | Bounded | `commandReadModel(Type)` on `handle()` or `provide()` loads by command key through a registered resolver; MongoDB, Chronicle, and Drizzle provide resolvers. Equal ownership claims fail. | `Source/Chronicle/for_ChronicleReadModelForCommandResolver`, `Source/MongoDB/for_MongoCollection`, `Source/Drizzle/for_DrizzleReadModelForCommandResolver` |
| Calling from code | Supported | `executeCommand`, `execute(instance)`, `performQuery`, and `handle(request)`. See [Calling commands from code](/arc/backend/typescript/commands/calling-commands-from-code/). | `Source/Core/for_ArcServer/when_executing_a_command`, `Source/Core/for_ArcApplicationBuilder/when_executing_an_instance` |
| Controller-based commands and queries | Not applicable | ASP.NET Core MVC only. | |

- **Several return values and response value handlers.** Ordinary arrays are not flattened. At generation time, Chronicle event types/arrays and integration wrappers plus Arc operations are omitted from command responses. Each alternative path through an `Outcome`, union, alias, promise, or tuple must have at most one client-visible value, and all paths must use the same client decoder and cardinality; otherwise generation fails with guidance to return one response DTO with an application-owned status field. There is no general client-visible response union or implicit branch discriminator. The paired .NET 22.45.0 fixture pins DTO, primitive, validation, denial, arbitrary error DTO (a 200 success), and tuple alternatives. TypeScript matches those HTTP envelopes, but unlike .NET's lossy proxy generator it rejects distinct DTO or cardinality alternatives rather than silently picking one decoder; see [Command outcomes](/arc/backend/typescript/commands/command-outcomes/).
- **Command read models by key.** Drizzle command injection requires exactly one column-level `.primaryKey()` with an Arc `@field` on that key; without `@field` on an existing column-level key, the model can serve queries but injection fails at build (no resolver claims it). Table-level `primaryKey({ columns })` is not recognized, and `withDrizzle` rejects such a model at registration. Custom codec columns bind typed keys; plain columns bind primitives, with invalid GUID and integer keys rejected. Command injection is tested against SQLite, live MySQL 8.4, and live PostgreSQL 16 with node-postgres. PostgreSQL checks typed GUID and concept keys, tenant isolation, and missing required and optional rows. A type registered with both Chronicle and Drizzle fails at build when injected with `commandReadModel` (two resolver claims). Chronicle additionally supports `readModelForValidation(Type, { optional: true })` in model-bound command validators.

## Queries

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| Model-bound queries | Bounded | `@readModel()` with static `@query(...)` methods and complete ordered `argument`, `service`, and `queryOptions` descriptors; with generated metadata, a bare `@query()` infers ordered arguments, concrete services, and observable returns; without it, legacy emitted metadata infers only class-valued services. Identity includes namespace, read model, and method. | `Source/Core/queries/modelBound/for_compileQueries`, `Source/Core/for_ArcApplicationBuilder/when_serving_model_bound_http`, `Samples/Tasks/Features/Tasks/Listing/for_TaskItem` |
| Global query filters | Bounded | Scoped `AuthorizationQueryFilter` and `QueryPipelineFilter` services return result fragments; authorization precedes validator and performer dependency construction. They run once at observable admission, not per emission, including opt-in health. GET/`QUERY`/snapshot/direct SSE filter denial and allow are paired with .NET on Express, Fastify, and Hono. Direct WebSocket denial and allow, plus continued service to a second SSE/WS subscription after an early disconnect, are checked on all three TypeScript adapters; the .NET fixture does not expose a direct WebSocket upgrade. TypeScript traces verify authorization-before-ordinary-before-validation and that denial skips dependency construction and the producer. See [Query filters](/arc/backend/typescript/queries/query-filters/). | `Source/Core/for_ArcApplicationBuilder/when_running_query_filters`, `Source/Core/for_ArcServer/when_filtering_observable_health`, `ContractTests/Http/conformance.test.mjs` |
| GET and HTTP `QUERY` | Supported | `QUERY` answers with `Cache-Control: no-store` and can be turned off with `generatedApis: { enableQueryHttpMethod: false }`. | `Source/Core/for_ArcServer/when_handling_a_query`, `ContractTests/Http/conformance.test.mjs` |
| Argument binding | Supported | Case-insensitive names, number and boolean conversion on GET, repeated keys for array arguments. | `Source/Core/for_ArcServer/when_handling_a_query`, `Samples/Tasks/Features/Tasks/Listing/for_TaskItem/when_performing/with_a_concept_argument.ts` |
| Paging and sorting | Supported | Arrays are sorted and paged in memory; a provider returns `queryPage(items, totalItems, sorting?)`. Page offsets clamp to signed int32. See [Paging and sorting](/arc/backend/typescript/queries/model-bound/paging/). | `Source/Core/for_ArcServer/when_sorting_a_query`, `Source/Core/queries/for_queryRendering`, `Samples/Tasks/Features/Tasks/Listing/for_TaskItem/when_performing/with_sorting_and_paging.ts` |
| Renderers and read-model interceptors | Bounded | Ordered scoped `QueryRenderer`s own provider results; exact-class `ReadModelInterceptor`s transform snapshots and each emission, including HTTP snapshots. No automatic provider pushdown. | `Source/Core/queries/for_queryRendering`, `Source/Core/for_ArcApplicationBuilder/when_registering_read_model_interceptors` |
| Services and dependencies | Supported | Class and `serviceToken` tokens with singleton, scoped, and transient lifetimes; the build preflights declared graphs. Scopes snapshot every declared execution-context field at creation (including inherited getters) but retain the original principal for ordinary factories. Trusted hosts can borrow a live scope only when its principal is strictly plain data; borrowed work uses a separate deep-frozen principal copy and may override only correlation and link an additional signal. This is not authorization. Host integrations can register shutdown participants to stop admission and drain external work before Arc disposes scopes and singletons. See [Dependency injection](/arc/backend/typescript/dependency-injection/). | `Source/Core/dependencyInjection/for_ServiceRegistry`, `.../for_ServiceScope`, `Source/Core/for_ArcServer/when_borrowing_a_scope`, `Source/Core/for_ArcApplicationBuilder/when_resolving_model_bound_services`, `yarn test:legacy-decorators` |

- **Paging and sorting.** GET rejects nonpositive integer `pageSize` with a paging rule; nonnumeric and out-of-int32 GET paging values default, while leading zeros, `+`, and surrounding whitespace parse as integers. Structured `QUERY` treats nonpositive sizes as unpaged and rejects invalid sort directions with an owning member.

## Observable queries

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| Observable definitions and HTTP snapshots | Bounded | `{ observable: true }` model-bound queries and `defineObservableQuery` accept RxJS `BehaviorSubject`, `ReplaySubject`, `Subject`, `Observable`, async iterables, and structural subscribables. RxJS is an optional peer of core for async-iterable-only consumers. | `Source/Core/for_ArcServer/when_handling_observable_snapshot`, `Source/Core/queries/observable/for_CurrentValueSubject`, `Source/Core/for_ArcApplicationBuilder/when_serving_model_bound_observables` |
| Direct SSE and WebSocket | Bounded | The query route streams direct result frames through the Express, Fastify, and Hono Node adapters and the standalone host; generated installed-client subscriptions receive initial and later results. | `Source/Core/queries/observable/for_directWebSocket`, `ContractTests/Client/observable-direct-sse.test.mjs`, `ContractTests/Client/observable-upgrade-lifecycle.test.mjs` |
| Multiplexed WebSocket and SSE hubs | Bounded | `/.cratis/queries/ws` and `/.cratis/queries/sse` accept anonymous connections, with revisions, configurable keep-alive, and tombstones on all three adapters and the installed 22.45.0 client (including the React provider's default SSE transport). Query authorization is checked per subscription. | `Source/Core/queries/observable/for_HubConnection`, `Source/Core/for_ArcServer/when_subscribing_to_sse`, `.../for_SseHubTransport`, `.../for_SubscriptionRevisions`, `ContractTests/Client/observable-hub.test.mjs` |
| Full, delta, and legacy transfer | Bounded | `full`, `delta` (initial full, then change sets), and legacy full plus change set. The installed client does not rebuild delta arrays in subscription callbacks. | `Source/Core/queries/observable/for_ObservableTransfer` |
| Emission guards | Supported | Scoped guards `Allow`, `Suppress`, or `DenyAndTerminate` every rendered result; failures deny and are logged. | `Source/Core/queries/observable/for_ObservableQuerySession`, `Source/Core/for_ArcServer/when_opening_observable_query` |
| Query health | Supported, with a deliberate difference | `query: { enableObservableHealth: true }` exposes the authenticated caller's own hub connections only. Global query filters run at health admission, not per emission. .NET exposes broader anonymous metadata. | `Source/Core/for_ArcServer/when_reporting_caller_scoped_health.ts`, `.../when_filtering_observable_health`, `.../when_handling_observable_health`, `Source/Core/queries/observable/for_FilteredHealthSource` |
| Resource limits | Supported, configurable | Subscription, connection, frame, queue, tombstone, handshake, and shutdown limits; exhaustion answers 503 or WebSocket 1013/1009. No request-rate limit. | `Source/Core/queries/observable/for_ObservableLimits`, `ContractTests/Client/observable-capacity.test.mjs` |

- **Observable definitions and HTTP snapshots.** `CurrentValueSubject` remains supported but is deprecated. BehaviorSubject current values answer 200; sources without readable current values answer 202; bounded waits answer 408 or 500.
- **Multiplexed WebSocket and SSE hubs.** SSE control requests must match the opener's authenticated identity or anonymous state and tenant; anonymous callers are also matched by peer address when available, unlike .NET. Anonymous per-caller connection and subscription budgets are kept per tenant and peer address. SSE streams send `Cache-Control: no-cache`.

## Validation

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| Command and query validators | Bounded | `@validator(Target)` classes or validators with a generated target extending `CommandValidator` or `QueryValidator` with constructor-authored `ruleFor` rules; query validators target an explicit `argumentsModel`. One validator per exact target. | `Source/Core/validation/for_validator`, `.../for_ModelGraphValidator`, `.../for_RuleBuilder`, `Samples/Tasks/Features/Tasks/Registration/for_RegisterTask/when_validating` |
| Concept and model validators | Bounded | `ConceptValidator` and `ModelValidator` apply through declared `@field` graphs, with collection paths; `ignoreConceptRules()` skips only the direct member. No getter reflection or DataAnnotations. | `Source/Core/validation/for_ModelGraphValidator` |
| Result shape and failures | Supported | Results carry `severity`, `message`, `members`, `reason`, and optional `state` and `reasonDetail`. `ValidationResult.information/warning/error(message, options?)` constructs results with `members`, `state`, `reason`, and `reasonDetail`; optional metadata reaches command and query HTTP envelopes. Malformed input is 400 `malformedRequest`; a throwing validator is 400 `validatorFailed`, logged, without exception text. | `Source/Core/validation/for_ValidationResult`, `Source/Core/for_ArcServer/when_handling_a_command`, `Source/Core/for_ArcServer/when_handling_a_query`, `ContractTests/Http/conformance.test.mjs` |
| [Severity filtering](/arc/backend/typescript/commands/validation-severity-filtering/) | Supported, with a deliberate difference | HTTP caps `X-Allowed-Severity` at Warning; see [Deliberate differences](#deliberate-differences). | `Source/Core/for_ArcServer/when_selecting_http_severity`, `ContractTests/Http/conformance.test.mjs` |
| Rules shared with the client | Bounded | The proxy generator emits literal, unconditional client-safe rules; server-only rules produce diagnostics. See [Validation rules in proxies](/arc/backend/typescript/proxy-generation/validation/). | `Source/Tools/ProxyGenerator/for_renderRecordedRules`, `Source/Tools/ProxyGenerator/for_analyzeSource` |

## Security, identity, tenancy, and correlation

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| Declared authorization | Supported | `@authorize`, `@roles`, `@allowAnonymous`, or `authorization`; roles in one declaration are OR, stacked declarations on one target AND. Explicit query method declarations replace the read-model class declaration; command authorization is class-only. Contradictions fail at startup. See [Authorizing commands and queries](/arc/backend/typescript/authorizing-commands-and-queries/). | `Source/Core/for_ArcServer/when_handling_a_protected_command`, `.../when_handling_a_protected_query`, `Source/Core/for_ArcApplicationBuilder/when_authorizing_a_model_bound_command` |
| Per-request authorization | Supported | `authorize(input, context)` runs after the schema; allowed severity never affects it. | `Source/Core/for_ArcServer/when_handling_a_protected_command` |
| Named policies and schemes | Bounded | Function or scoped class policies; named Arc handlers selected per operation. Schemes on observable queries fail at build. See [Authorization policies and schemes](/arc/backend/typescript/core/authorization/). | `ContractTests/Http/conformance.test.mjs` (policy allow and deny against .NET 22.45.0), `Source/Core/for_ArcServer/when_authorizing_named_schemes.ts`, `.../when_authenticating_a_handler_scheme.ts`, `.../when_rejecting_observable_scheme_configuration.ts` |
| Authentication handlers | Supported | Ordered chain; the first recognizing handler decides, and a failure is terminal with 401. | `Source/Core/authentication/for_authenticate` |
| JWT bearer and EasyAuth | Supported, opt-in | `jwtBearer()` verifies signatures against an HTTPS JWKS with pinned issuer, audience, and algorithms (TypeScript only). `microsoftIdentityPlatform()` maps forwarded EasyAuth headers like .NET and requires a trusted ingress. See [Authentication](/arc/backend/typescript/core/authentication/). | `Source/Core/authentication/for_jwtBearer`, `.../for_microsoftIdentityPlatform`, `Source/Core/for_ArcServer/when_receiving_non_bearer_authorization.ts` |
| Native principal | Supported, opt-in | `nativePrincipal: true` plus a trusted adapter callback; mutually exclusive with handlers. | `Source/Express/for_identityHosts`, `ContractTests/Client/observable-native-auth.test.mjs` |
| [Identity details](/arc/backend/typescript/identity/) | Supported, opt-in | Zod or model-bound `detailsType` providers, discovered or explicit; `/.cratis/me` answers 401, 403, or 200 with a display cookie of at most 4096 bytes. | `Source/Core/for_ArcServer/when_handling_identity_request`, `.../when_issuing_identity_cookies`, `Source/Core/for_ArcApplicationBuilder/when_discovering_identity_details.ts` |
| Development users and tenants | Supported, opt-in | Fixture providers require `development: true` and are capped at 100 entries and 32 KiB. Their endpoints follow the [discovery access policy](/arc/backend/typescript/introspection/#production-access), anonymous only in Development by default. | `Source/Core/for_ArcServer/when_discovering_development_tenants`, `.../when_resolving_development_tenant.ts` |
| [Tenant resolution](/arc/backend/typescript/tenancy/) | Bounded | Default header, authoritative `tenancy.resolve`, a .NET-compatible `tenancy.resolverType`, and ordered header, query, claim, fixed, and strict subdomain sources with `required` and membership checks. | `Source/Core/for_ArcServer/when_configuring_tenancy`, `.../when_resolving_tenants`, `.../when_checking_tenant_membership`, `.../when_resolving_tenant_claims` |
| Correlation IDs | Supported | Valid non-zero UUIDs are reused, others replaced; the header name is configurable. W3C trace context stays host-owned. | `ContractTests/Http/conformance.test.mjs` |
| Exception redaction | Supported | Outside development, HTTP results carry a generic message and no stack trace; direct calls are not redacted. | `Source/Core/for_ArcServer/when_logging_a_failure`, `ContractTests/Http/conformance.test.mjs` |

## Proxies, introspection, and tooling

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| TypeScript proxy generation | Bounded | `arc-proxygenerator` reads decorated source and emits commands, queries, observable queries, models, hooks, derived types, and client-safe rules for the published `@cratis/arc` 22.45.0 client in strict Bundler mode. Full .NET template parity remains unverified. See [Proxy generation](/arc/backend/typescript/proxy-generation/). | `Source/Tools/ProxyGenerator/for_analyzeSource` (including duplicate-name tsc compilation), `.../for_renderSource`, `.../for_SourceTypeResolver`, `yarn test:client-generation` (`ContractTests/Client/source-generation.test.mjs`) |
| Low-level client manifest | Bounded | `exportClientManifest` plus the positional JSON CLI for `define*` definitions with explicit `clientOutput`: flat DTOs, basic inputs, and command responses. No hooks, nested DTOs, or shared rules. See [Low-level manifest](/arc/backend/typescript/proxy-generation/low-level-manifest/). | `Source/Core/introspection/for_exportClientManifest`, `ContractTests/Client/generation.test.mjs` |
| Introspection | Supported | `/.cratis/commands`, `/.cratis/queries`, and `/.cratis/identity-details/schema` describe input JSON Schema under the [discovery access policy](/arc/backend/typescript/introspection/#production-access): anonymous in Development, authenticated elsewhere by default. `introspection.enabled: false` (`Cratis:Arc:Introspection:Enabled`) disables catalogs and HTTP OpenAPI, not identity discovery or in-process metadata. See [Turn discovery off](/arc/backend/typescript/introspection/#turn-discovery-off). | `Source/Core/for_ArcServer/when_introspecting_queries.ts`, `.../when_discovery_is_disabled`, `Source/Express/for_identityHosts/when_discovery_is_disabled.ts`, `ContractTests/Http/conformance.test.mjs` |
| OpenAPI | Supported | `/openapi.json` is OpenAPI 3.1 with input schemas, result envelopes, generated typed result schemas when metadata is registered, command `POST <route>/validate` with an untyped envelope, query paging/sorting options only for declared array or `queryPage` results, and bearer security declarations for configured authentication handlers. Unknown query return cardinality does not advertise paging even though the runtime can page an array or `queryPage` result; renderer-backed (`QueryRenderer`) queries aren't automatically advertised as pageable. `info.version` can be set with `generatedApis.openApiVersion` (default `0.1.0`). See [OpenAPI](/arc/backend/typescript/open-api/). | `Source/Core/for_ArcServer/when_describing_observable_query_in_openapi.ts`, `.../when_serving_openapi`, `Source/Core/openApi/for_renderOpenApi`, `ContractTests/Client/source-generation.test.mjs` (JSDoc summary over HTTP) |
| Concepts, derived types, and wire format | Bounded | Primitives, `Date`, Fundamentals `Guid`, `DateOnly`, `TimeOnly`, `TimeSpan`, concepts, nested models, arrays, and field modifiers; `_derivedTypeId` polymorphism with `oneOf` schemas; .NET-style acronym-preserving camel case. See [Wire format](/arc/backend/typescript/reference/wire-format/). | `Source/Core/reflection/for_wireSchema`, `Source/Core/for_ArcServer/when_binding_a_polymorphic_command`, `ContractTests/Client/polymorphic.test.mjs` |
| Code analysis | Bounded | `@cratis/eslint-plugin-arc-core` for ESLint 10: .NET-mapped ARC rules and TypeScript-only binding rules, with `recommended` and `recommended-type-checked` presets. No automatic fixes. See [Code analysis](/arc/backend/typescript/code-analysis/). | `Source/CodeAnalysis/for_rules`, `yarn lint:tasks:arc` |
| Build-time checks | Bounded | `add()` rejects undecorated classes; `build()` rejects decorators with no effect, missing services, cycles, and captive lifetimes. Generated binding metadata checks runtime-verifiable shapes at registration; `--check-metadata` catches source-only changes. | `Source/Core/for_ArcApplicationBuilder/when_building`, `yarn test:decorator-types` |
| Screenplay generation | Not applicable | .NET only. | |

- **TypeScript proxy generation.** Optional server metadata infers service and argument bindings with an explicit `--metadata` option. Same-named models in distinct namespaces, decorated identity-provider result types, and symbol-resolved Chronicle event/operation command return filtering are supported, as are static query HTTP method and warning preferences. Source-only identity configuration also remains unverified. Identity details models outside the artifacts root are skipped with a diagnostic.

## Persistence and Chronicle

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| [MongoDB](/arc/backend/typescript/mongodb/) | Bounded | Tenant-scoped collections with BSON mapping, .NET-compatible naming policies, database-side paging, change streams, and command read models. No cross-store transactions. See [how it is checked](#mongodb-checks). | `Source/MongoDB/for_MongoCollection`, `.../for_MongoDocumentCodec`, `.../for_MongoReadModels`, `.../for_withMongoDB`, `bash Source/MongoDB/run-integration.sh` (live replica set, Docker) |
| [SQL with Drizzle](/arc/backend/typescript/sql/) | Bounded | Tenant-scoped Drizzle handles, column codecs, and SQL count, sort, and page for model-bound queries. SQLite, PostgreSQL 16, and MySQL 8.4 tested with real databases. MySQL live coverage includes tenant routing, codecs, stable paging, limits, sort rejection, and command lookup. PostgreSQL command lookup with node-postgres covers tenant routing, typed keys, and missing rows. No migrations, change tracking, or transactions. See [how it is checked](#sql-checks). | `Source/Drizzle/for_DrizzleReadModelForCommandResolver`, `Source/Drizzle/for_DrizzleReadModels`, `.../for_ColumnCodec`, `.../for_DrizzleModelCodec`, `.../for_withDrizzle`, `bash Source/Drizzle/run-integration.sh` (live PostgreSQL 16 and MySQL 8.4, Docker) |
| [SQL table observation](/arc/backend/typescript/sql/observing-tables/) | Experimental | `DrizzleObservation.InProcess` observes explicitly announced changes in one process. `PostgreSQLNotify` uses application-installed statement triggers and one dedicated listener per active tenant for committed cross-process invalidation. Listener loss pauses reads; bounded reconnect (five delayed attempts) revalidates live relations and forces fresh snapshots, including unused primes. Exhaustion errors subscriptions; later subscriptions may start fresh. Eventual committed state, not durable intermediate-state delivery or atomic page snapshots. No MySQL/SQLite cross-process observation or polling. | `Source/Drizzle/for_DrizzleReadModels/when_observing`, `.../when_serving_a_sqlite_observation`, `.../when_observing/with_postgres.integration.ts`, `.../for_DrizzleHandle`, `bash Source/Drizzle/run-integration.sh postgresql` |
| [Chronicle](/arc/backend/typescript/chronicle/) | Experimental | Not published to npm. `withChronicle` appends returned model-bound events through a response value handler, with routing, subject, and causation resolved from the command. Full .NET parity is unverified. See [how it is checked](#chronicle-checks). | `Source/Chronicle/for_ChronicleResponseHandler`, `.../for_ChronicleUnitOfWork`, `.../for_ChronicleReadModelForCommandResolver`, `.../for_reactorCommandResultHandler`, `.../for_AggregateRoot`, `Source/Chronicle/testing/for_ChronicleCommandScenario`, `bash Source/Chronicle/run-integration.sh` (live kernel, Docker) |
| [Chronicle compliance](/arc/backend/typescript/chronicle/compliance/) | Bounded | Subject resolution on appends and `@notAudited` and `@pii` exclusion from the causation chain. Arc releases protected models decoded into the exact read-model class, and raw `MongoReadModels` documents typed with `readModel`, at the query edge. A failed release fails the result. | `Source/Chronicle/for_ChronicleReadModelInterceptor`, `Source/Core/queries/for_interceptReadModel`, `Source/Chronicle/for_ChronicleReadModelForCommandResolver/when_resolving_a_private_projection`, `Source/Chronicle/Integration/live.test.mjs` |
| Reactor replay exclusion | Bounded (SDK 6.9.0+) | The SDK replays reactors by default and supports class- or handler-level `@onceOnly()` and alternate `@replay()` handlers. Arc executes returned commands under those SDK rules; type-checked `ARCCHR0006` warns on returned commands without a replay decision. Failed-partition recovery can re-deliver effects even with `@onceOnly()`. See [Reactors](/arc/backend/typescript/chronicle/reactors/). | SDK decorators; `Source/CodeAnalysis/for_rules/when_linting_artifacts/with_reactor_replay_decisions.ts` checks the lint rule; `Source/Chronicle/Integration/LiveArtifacts.ts` and `bash Source/Chronicle/run-integration.sh` exercise a once-only reactor returning a command on normal delivery, not replay exclusion |
| [Chronicle code analysis](/arc/backend/typescript/chronicle/code-analysis/) | Bounded | `ARCCHR0003` checks reactor store fields initialized from `this.client`/`this.runtime` (ownership is not proven); type-checked `ARCCHR0006` flags returned commands from live handlers without a replay decision; `ARCCHR0007` flags direct default-log appends from command `handle`/`provide`, including injected Chronicle services; `ARCCHR0009` checks unmasked secret-looking fields; type-checked `ARCCHR0010` flags Guid values beside direct decorated events on keyless commands. Other .NET diagnostics are inapplicable, checked at runtime, or require review. | `Source/CodeAnalysis/for_rules/when_linting_artifacts/with_chronicle_rules.ts`, `Source/CodeAnalysis/for_rules/when_linting_artifacts/with_reactor_replay_decisions.ts` |
| Transactions and units of work | Experimental | Chronicle stages returned and aggregate-applied events from nested commands in one tenant, correlation, and event store, and sends one `appendMany` after the outer command succeeds. It participates in Arc command-operation failure handling; it is not a transaction across stores or immediate SDK appends. | `Source/Chronicle/for_ChronicleUnitOfWork`, `Source/Chronicle/for_ChronicleCommandScope` |
| Event source definitions | Experimental | `@eventSourceDefinition` on a command or aggregate routes events through a registered Chronicle definition and stream: startup validation, per-event source and stream replacement as a unit, definition-derived concurrency when no explicit scope or flags are set, and aggregate rehydration limited to the declared source and stream. Needs `@cratis/chronicle` 6.49.0 or later; string routing works with older SDKs. Verified against Chronicle kernel 19.30.0 and SDK 6.49.0. Screenplay grammar and generation for definitions are not part of this package. | `Source/Chronicle/for_ChronicleResponseHandler/when_routing_through_an_event_source_definition`, `Source/Chronicle/for_withChronicle/when_validating_event_source_definitions`, `Source/Chronicle/for_AggregateRoot/when_declaring_an_event_source_definition`, `ARC_CHRONICLE_TEST_SUITE=event-source-routing bash Source/Chronicle/run-integration.sh` |

- **MongoDB.** Also [joined observation](/arc/backend/typescript/mongodb/joined-observe/), a [scoped watcher](/arc/backend/typescript/mongodb/change-stream-watcher/), [GeoJSON geometry](/arc/backend/typescript/mongodb/geospatial/), bounded transient read retries, MongoDB driver metrics for Arc-owned clients, and `Cratis:MongoDB:{Server,Database}` configuration binding. No durable watcher checkpoint; nonresumable stream failures terminate subscriptions. .NET's process-wide watcher, general-purpose resilience interceptors, and comprehensive metrics for supplied clients are not implemented.
- **SQL with Drizzle.** `bash Source/Drizzle/run-integration.sh` exercises live PostgreSQL and MySQL for existing SQL reads and command lookup, not observation. In-process observation is checked using SQLite (`sql.js`), gated race and burst specs, and SSE/GET through Express, Fastify, and Hono. Command read models load by a single column-level `.primaryKey()` with `@field` in the tenant scope; models without `@field` on their column-level key still serve queries but cannot be injected into commands. Tables without a column-level primary key are rejected at registration. Custom columns bind typed keys, plain columns primitives. Command read models are tested against SQLite, live MySQL 8.4, and live PostgreSQL 16 with node-postgres. PostgreSQL coverage includes typed GUID and concept keys, tenant isolation, and missing required and optional rows.
- **Chronicle.** It also resolves Chronicle read models by command key and in validators, batches nested returned events, and executes Arc commands returned from reactors through the SDK reactor result hook. SDK 6.49.0 loads in native Node ESM. Keyed aggregates and returned reactor commands are experimental.
- **Chronicle compliance.** Mark projected read-model properties `@pii()` to encrypt them at rest; event-only marking does not protect the materialized field. Chronicle kernel reads already release values (including command injection), and Arc skips releasing those instances twice. For protected Chronicle models decoded into the exact read-model class by `MongoCollection`, Arc releases at the query edge, including snapshots, pages, and observable emissions. Raw `MongoReadModels` documents typed with `readModel` are released with the request's tenant and each document's subject: `subjectFor(document)` when given, otherwise the stored `__subject`, otherwise a string or numeric `_id`. It must match any stored `__subject` and the model's `@subject()` or `id`. Kernel bookkeeping fields are stripped. The path fails closed on undeclared fields, non-JSON BSON values (including `Guid` fields stored as `Binary`), per-property `__subjects`, a subject or tenant mismatch, typed documents nested in another shape, and MongoDB projections. Unreleased instances of a protected class nested in another returned shape, such as a joined `select` result, fail the query. Specs check snapshots, pages, and observable SSE through Express, Fastify, and Hono against a Chronicle substitute; the kernel integration reads a real materialized document through `MongoReadModels`. Untyped raw documents, typed documents of models not registered with Chronicle, codec-selected derived subtypes, `MongoDBWatcher.changes()` payloads, documents hidden behind `toJSON()`, getters, or private fields, and DTOs, mapped objects, or copies are served as stored and need explicit `readModels.release` on the tenant store. Nested, array-item, class-level PII and `@encrypted()` security metadata are detected. A directly read protected model needs `@subject()` or `id` matching the event subject to release; one without either is served only when it holds no protected value, and fails otherwise. The kernel integration checks raw MongoDB ciphertext, Chronicle delivery, and Arc query-edge release for a direct MongoDB read.

## Testing

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| [Pipeline scenarios](/arc/backend/typescript/testing/) | Bounded | `CommandScenario`, `QueryScenario`, and `ObservableQueryScenario` run decorated artifacts through real pipelines with wire encoding and fakes; `ArcScenario` covers low-level definitions and HTTP. `ChronicleQueryScenario` resolves pinned, reducer-built, or supported flat projection-backed keyed read models in memory, but not lists or subscriptions. A [node:test recipe](/arc/backend/typescript/testing/node-test/) runs one command scenario with disposal. | `Source/Testing/for_CommandScenario`, `.../for_QueryScenario`, `.../for_ObservableQueryScenario`, `.../for_ArcScenario`, `.../for_withCommandAssertions`, `Source/Chronicle/testing/for_ChronicleCommandScenario`, `Source/Chronicle/testing/for_ChronicleQueryScenario`, `Samples/Library/kernel-scenarios.test.mjs` (live kernel, Docker), `yarn check:node-test` |

- **Pipeline scenarios.** `ChronicleCommandScenario` records command-produced events separately from seeded event history and resolves reducer-backed and [supported flat projection-backed](https://github.com/Cratis/Chronicle.TypeScript/blob/main/Documentation/testing.md#projection-capabilities) command read models with the SDK's `ReadModelScenario`; pins take precedence. `ChronicleQueryScenario` uses the same seed store for keyed Chronicle query reads and rejects unsupported lists and observations. Unsupported projection operations, aggregate replay, and observer-driven updates require `ChronicleKernelScenario`, which seeds events and runs against a live kernel. The in-memory scenario does not enforce concurrency or update reduced state after command appends.

## Hosting and observability

| Capability | Status | TypeScript contract | Evidence |
| --- | --- | --- | --- |
| Express 5, Fastify 5, and Hono 4 adapters | Supported | `cratisArc` accepts an `ArcServer` or built `ArcApplication`: Express middleware plus listener attach; Fastify plugin registers HTTP and WS in either shared-plugin order; Hono sub-app plus Node serving helper. The host keeps listener ownership. See [Host adapters](/arc/backend/typescript/hosts/). | `Source/Express/for_cratisArc`, `Source/Fastify/for_cratisArc`, `Source/Hono/for_cratisArc`, `ContractTests/Client/observable-origin.test.mjs` |
| Node configuration and Fetch dispatch | Bounded | The default `@cratis/arc.core` entry keeps Node file configuration, discovery, HTTP host, static files, and WebSocket upgrades. The separate `@cratis/arc.core/fetch` entry registers artifacts without file discovery or configuration and serves commands, queries, and SSE. Next.js App Router `next build && next start` on Node.js is checked with two catch-all routes and server minification disabled; Bun has a smoke check only. Workers and Next.js Edge are not supported. See [Fetch API runtimes](/arc/backend/typescript/hosts/fetch-runtimes/). | `Source/Core/configuration/for_loadConfiguration`, `Source/Core/for_FetchArcApplication`, `yarn check:fetch`, `yarn check:fetch:next`, `yarn check:fetch:bun` |
| Cratis composition | Experimental | `@cratis/cratis` composes Arc and Chronicle without installing an authentication handler; `CratisApplication.createBuilder` and `builder.addCratis`. It is not published to npm, and the composition itself has not been exercised against a live kernel. | `Source/Cratis` |
| Cancellation on client disconnect | Supported for Express, Fastify, and Node | Hono passes the signal of the request it received. | `Source/Express/for_cratisArc`, `Source/Fastify/for_cratisArc`, `Source/Core/http/for_createArcNodeHandler` |
| Unsupported methods | Supported | 405 with `Allow` for methods that reach Arc; the standalone host rejects TRACE and CONNECT. | `ContractTests/Http/conformance.test.mjs`, `Source/Core/http/for_runArc` |
| [Standalone host and static files](/arc/backend/typescript/core/) | Bounded | HTTP or HTTPS listener or request handler, public files, SPA fallback, path base, cache validators, and graceful shutdown. No private file authorization, directory listing, multiple roots, or byte ranges. | `Source/Core/http/for_runArc`, `.../for_createArcNodeHandler`, `Source/Core/for_ArcApplication` |
| [Tracing and metrics](/arc/backend/typescript/observability/) | Bounded | Versioned `Cratis.Arc` OpenTelemetry API spans and command/query duration histograms in seconds with canonical attributes (`cratis.arc.command.type`, `cratis.arc.query.name`); the operation-duration histogram remains emitted but is deprecated; the application supplies the SDK. Host-owned HTTP instrumentation produces a SERVER span above Arc's command HTTP span on real Express, Fastify, and Hono Node servers; Express and Fastify instrumentation also produces framework spans in the ancestry. Foreign routes have no Arc spans. A host-owned pino recipe verifies callback correlation, redacted HTTP errors, and omission of a command payload from structured logs. | `Source/Core/for_ArcServer/when_tracing_operations`, `yarn check:observability-recipes` |

- **Node configuration and Fetch dispatch.** `app.fetch(request)` answers 404 on non-Arc paths and `app.handle(request)` falls through. A neutral bundle allows only `node:async_hooks`, with no Node filesystem/crypto/stream imports, and passes in a restricted VM. Next.js 15.5.14 `next build && next start` on Node.js 26.8.1 passes commands, GET, validation, authorization, snapshot and streamed direct/hub SSE, direct client abort and subscription release, and tenant/correlation headers; Next.js itself returns 404 for unmatched routes. This is a local production-server check, not a deployment check. Server minification must be disabled to preserve model-bound class names. Next.js rejects HTTP `QUERY` with 400 before Arc sees it; use GET. Bun 1.3.10 `Bun.serve` passes the shared scenario including `QUERY`, as an optional smoke check, not a deployment guarantee. The older Deno 2.9.7 check passed the smaller pre-expansion scenario; the expanded scenario has not been rerun there. Arc targets Node-compatible servers for Chronicle gRPC, MongoDB TCP, and live queries; Cloudflare Workers and Next.js Edge are not supported, and these checks do not verify deployed production hosting or optional integrations.

## Deliberate differences

- **Ambiguous command response alternatives.** Both runtimes serialize only the selected value; an arbitrary `Result<TSuccess, TError>` error DTO is a 200 success response, not a rejection. The TypeScript proxy generator rejects alternatives requiring different client decoders or cardinalities, while .NET 22.45.0 picks one response type and hydrates all alternatives through that decoder. Use one DTO with an application-owned status field for several client-visible business outcomes.
- **Malformed command input and filters.** TypeScript runs authorization filters with raw input when binding fails, allowing a denial to take precedence over a 400 response. .NET 22.45.0 returns 400 before those filters for malformed command input. The paired fixture checks both execute and `/validate` modes; authorized malformed input returns `malformedRequest` on both with different message text.
- **Global filter warnings and errors.** TypeScript applies severity filtering to each command and query fragment before short-circuiting; .NET short-circuits before filtering. Otherwise a filtered-out warning could skip later authorization filters. A thrown global command or query filter produces a 500 exception result, not .NET's 400 `IValidationFailure` result; ordinary per-definition validation failures still produce 400.
- **Severity 3 over HTTP.** On a command, `X-Allowed-Severity` accepts `0`, `1`, and `2`. A request that sends `3` is treated as `2` (Warning), so error-severity results still block with 400 and the handler does not run. Arc on .NET 22.45.0 accepts `3` and runs the command unless it declares `[BlockOnValidationSeverity]`. Queries ignore the header. A trusted caller of `executeCommand` can still pass `Severity.Error`.
- **Anonymous caller on a protected operation.** With authentication handlers configured, Arc for TypeScript answers 401; Arc on .NET answers 403.
- **Method authorization on commands.** TypeScript rejects `@allowAnonymous()`, `@authorize()`, or `@roles()` on `handle()`, `provide()`, or another command method at build; declare authorization on the class. The pinned .NET 22.45.0 command pipeline evaluates only the type and ignores authorization attributes on `Handle()`. Query methods on both runtimes replace, rather than combine with, their read-model class declaration; stacked attributes on one target are AND requirements, with OR roles within one attribute.
- **Identity denial and display cookie.** `/.cratis/me` returns a JSON `{ error }` on 401/403 in TypeScript; the pinned .NET host sends an empty body. Both return the same successful identity fields and a base64 display cookie, but cookie attribute casing and base64 escaping are host-dependent. TypeScript never reads the unsigned cookie as a credential; .NET 22.45.0 reads it before checking the authenticated principal. Identity-details schemas describe the same required fields but use different schema generators. Both runtimes require authentication outside Development by default for discovery (`/.cratis/commands`, `/.cratis/queries`, `/.cratis/users`, `/.cratis/tenants`, and `/.cratis/identity-details/schema`), with an anonymous opt-out and optional roles. The paired Production fixtures assert anonymous 401 and authenticated 200 across Express, Fastify, and Hono for all five routes; denial bodies remain empty on .NET and JSON on TypeScript. TypeScript additionally protects `/openapi.json`; see [Discovery access](/arc/backend/typescript/introspection/#production-access).
- **Policy context and authentication schemes.** .NET 22.45.0 evaluates named policies with scoped DI classes, a reflected target, and a command or query context; TypeScript also offers function policies, and its class policies receive an operation definition and an input and execution resource. Node scheme selection uses Arc handlers, not ASP.NET Core scheme composition, and scheme-protected observable queries are rejected at build. `jwtBearer()` is TypeScript-only. The paired 22.45.0 fixture checks named-policy allow and deny on commands and queries, but does not compare policy context objects or scheme selection.
- **Query health.** Caller-scoped and opt-in, instead of .NET's anonymous cross-caller view.
- **Anonymous SSE hub ownership.** Like .NET, anonymous callers can open an SSE hub connection but have no identity that distinguishes them from other anonymous callers. TypeScript additionally binds anonymous controls to the opening peer address when the host supplies one; without an address, callers in the same tenant who know the random connection ID cannot be distinguished. Authenticated connections require the same authenticated identity, and anonymous callers cannot control them.
- **Observable wait bounds.** `waitForFirstResultTimeout` is capped at 120 seconds, and an unrecognized boolean is rejected instead of ignored.
- **Message texts.** Malformed requests say `Malformed request`, and redacted exceptions say `An unexpected error occurred`; Arc on .NET uses different texts. An unreadable `QUERY` body returns an exception envelope on both, with these different redacted texts. Exposing exception details reveals TypeScript's reader error and stack.
- **Preparation and binding.** A model-bound `provide()` passes one value as the first `handle()` argument; several values need `tuple(...)` and `provided(Type)` markers, where .NET infers assignable types. Without generated metadata, standard-mode queries need ordered descriptors.
- **Compiler metadata.** Standard decorators can use generated metadata or explicit tokens; legacy decorators infer only class-valued dependencies from `design:paramtypes`. Generated metadata infers observable declarations from the return type; without it, use `{ observable: true }`.
- **Enum fields.** Use `@field(String)` or `@field(Number)` with `@enumeration(Enum)`; numeric reverse mappings are ignored.
- **Hosting defaults.** The Node host binds loopback by default. File discovery imports a dedicated artifacts folder, and moving a folder changes its derived route.
- **Invalid GUID query arguments.** Both runtimes return 400 `malformedRequest`. .NET 22.45.0 identifies the argument and query in its message and reports the argument member; TypeScript returns `Malformed request` with no members.
- **Structured QUERY argument names.** TypeScript rejects undeclared argument names with `malformedRequest` so typos do not silently change query results; .NET ignores them. Both ignore unknown members of the envelope, paging, and sorting objects, and a direction without a field.
- **QUERY numeric tokens.** JavaScript JSON parsing treats `2.0` and `2e0` as integer 2 and nested `null` paging numbers as missing values. .NET's int32 body reader rejects all three; unlike JavaScript, its JSON reader retains the original numeric token. A top-level `null` body or a `null` envelope member is absent in both implementations.
- **Invalid QUERY sort fields.** TypeScript rejects names outside the declared field-name syntax with 400 `malformedRequest`; the pinned .NET array renderer fails with a redacted 500 for an invalid name such as `name!`. This is a fail-early input guard.
- **Body size limit.** TypeScript's `hosting.maxBodyBytes` rejects oversized QUERY bodies with 400 `malformedRequest`; the pinned .NET fixture has no corresponding configured limit and accepts an otherwise valid large body.
- **Bounded provider reads.** MongoDB and Drizzle read at most their configured maximum page size; when an unpaged result exceeds it, they return a 400 paging-required `rule` on `Size`. A requested page larger than that maximum also returns a 400 rule. Arc on .NET returns all matching rows without a bound (`QueryableQueryRenderer.Execute`, `MongoCollectionExtensions.cs`).
- **Sorting collation.** In-memory string sorting uses `localeCompare`, not .NET invariant-culture collation.

## How the integrations are checked

The integration pages describe behavior. This section records the checks behind it.

### Chronicle checks

The specs run with the published Chronicle TypeScript SDK, `@cratis/chronicle` 6.49.0, and `@cratis/fundamentals` 7.22.0; both load in native Node ESM with NodeNext resolution. The live suite was last verified with SDK 6.10.0; a 6.14.0 attempt could not start the local kernel because its MongoDB connection was refused. The ordinary `yarn test` specs use typed substitutes or the SDK's in-memory `ReadModelScenario` and never start a kernel. An opt-in suite, `bash Source/Chronicle/run-integration.sh`, runs [`Source/Chronicle/Integration/live.test.mjs`](https://github.com/Cratis/Arc.TypeScript/blob/main/Source/Chronicle/Integration/live.test.mjs) against a real development kernel and checks:

- returned-event batches, readback, and tenant isolation;
- a reactor that returns an Arc command, executed in the triggering event's tenant;
- before-first concurrency rejection, and aggregate rehydration, commit, and concurrency rejection;
- operation compensation after a concurrency rejection;
- command-key read models for existing and missing keys;
- a projected read-model query, through a read-model interceptor; raw MongoDB ciphertext for a PII-marked projected read model, and plaintext delivery through Chronicle HTTP snapshots, observable SSE, command injection, and an Arc query reading the materialized MongoDB collection directly;
- all of it through real Express, Fastify, and Hono HTTP adapters.

The suite needs Docker. Its image, `cratis/chronicle:latest-development`, is mutable, so pin a compatible image for reproducible deployment testing. Validator read models (`readModelForValidation`), subject resolution, and `@notAudited` are covered by substitute-based specs, not by the kernel suite. The [Library sample](/arc/backend/typescript/getting-started/library-sample/) has its own kernel run, `bash Samples/Library/run-integration.sh`.

### MongoDB checks

`bash Source/MongoDB/run-integration.sh` starts a task-owned MongoDB 7 replica set in Docker and removes it afterward. The [integration spec](https://github.com/Cratis/Arc.TypeScript/blob/main/Source/MongoDB/for_MongoCollection/when_observing_changes/with_a_replica_set.integration.ts) exercises initial snapshots, insertion, deletion, tenant isolation, dependency injection, and provider paging, and a [second spec](https://github.com/Cratis/Arc.TypeScript/blob/main/Source/MongoDB/for_MongoCollection/when_serving_a_paged_query/with_each_http_adapter.integration.ts) serves sorted pages through Express, Fastify, and Hono. The script exits with 2 when Docker is not available, which means the check did not run. Unit specs cover the codec against .NET-shaped documents, naming policies, burst coalescing, the item cap, and stream failures.

### SQL checks

`yarn vitest run --project @cratis/arc.drizzle` runs the SQLite specs on `sql.js`. The [adapter HTTP spec](https://github.com/Cratis/Arc.TypeScript/blob/main/Source/Drizzle/for_DrizzleReadModels/when_serving_a_sqlite_page/with_each_http_adapter.ts) serves a sorted page through Express, Fastify, and Hono and checks that an unknown sort field answers 400; the [tenant-isolation spec](https://github.com/Cratis/Arc.TypeScript/blob/main/Source/Drizzle/for_DrizzleReadModels/when_paging_across_tenants/with_sqlite.ts) checks `databaseFactory` routing. `bash Source/Drizzle/run-integration.sh` runs the [PostgreSQL spec](https://github.com/Cratis/Arc.TypeScript/blob/main/Source/Drizzle/for_DrizzleReadModels/when_reading/with_postgres.integration.ts) against PostgreSQL 16 and the [MySQL spec](https://github.com/Cratis/Arc.TypeScript/blob/main/Source/Drizzle/for_DrizzleReadModels/when_reading/with_mysql.integration.ts) against MySQL 8.4 in disposable Docker containers. The MySQL check covers databaseFactory tenant isolation, stable SQL counts and sorted pages (including ties), concept/GUID/JSON/date/time codecs, invalid sort field rejection, paging limits, and command read-model lookup by GUID key (including a missing key). The [PostgreSQL command spec](https://github.com/Cratis/Arc.TypeScript/blob/main/Source/Drizzle/for_DrizzleReadModelForCommandResolver/when_injecting/with_postgres.integration.ts) checks node-postgres command lookup with typed GUID and concept keys, tenant-scoped tables, and missing required and optional rows. `run-integration.sh` exits with 2 when Docker is unavailable. Neither suite verifies concurrent writes between count and page.

### Proxy generation checks

The generated proxies compile against `@cratis/arc` and `@cratis/arc.react` 22.45.0 with `@cratis/fundamentals`, in strict `Bundler` mode with `skipLibCheck: false`. `yarn test:client-generation` builds the workspace, generates the Tasks proxies, compiles them, and runs commands, queries with arguments, paging, sorting, observable snapshots, and hub updates against live model-bound Express, Fastify, and Hono servers. Nullable command types and interface-only model mode have compile coverage only, not live-client equivalence.

## Shared Arc page examples

The shared Arc pages show a TypeScript tab beside C#, Kotlin, and Java. Its snippets live in `Documentation/client-snippets/`, and `yarn docs:snippets` compiles each one against this repository's packages with strict settings and standard decorators. Every shared snippet is a real TypeScript example. The in-memory `ChronicleCommandScenario` builds reducer-backed and supported flat projection-backed read models from seeded events and rejects projections outside that boundary with `UnsupportedProjectionOperation`; test those with `ChronicleKernelScenario`. The shared validator examples inject an application-owned repository. Arc for TypeScript validators do not take read models as constructor parameters; read one inside an async rule with `readModelForValidation`. A compiled snippet shows that the API exists with that shape; it is not a parity claim for the page around it.

## How parity is checked

A conformance suite, `yarn test:conformance`, runs paired checks against a .NET host built on the published `Cratis.Arc` 22.45.0 package and Arc for TypeScript mounted in Express (and, for filter checks, Fastify and Hono). Global command and query filter HTTP requests are paired with .NET across Express, Fastify, and Hono; direct WebSocket filter admission and filter-stage traces are TypeScript-only checks because the .NET fixture does not expose a direct WebSocket upgrade or fixture stage counters. It covers command execution, validation-only requests, authorization before validation including validation-only denial, business-rule and malformed-input rejection, tuple response validation, GET and `QUERY` binding, paging, sorting, exception redaction, unsupported methods, correlation IDs, model-bound commands and validation, acronym naming, enum and named-float output, an overridden query path, and a conventional GUID query route with valid and invalid inputs. It also checks named-policy allow and deny, numeric concept GET arguments, validation severity, and observable snapshots with current (200) and pending (202) values. Invalid sorting, GET and structured paging boundaries, malformed `QUERY` bodies (redacted 400, `no-store`, and no handler execution), and int32 page-offset clamping are paired against the published fixture. It also pairs identity details and the display cookie (while explicitly rejecting .NET's unsigned-cookie authentication), header/fixed/verified-claim/subdomain tenant routing, class and method authorization, malformed numeric/enum/concept inputs and execution counters, query validation and exceptions, correlation IDs on 400/403/500/202, and observable first emissions, waits, timeouts, and completion. The query reader's exception envelope matches; its redacted text differs as noted above. Numeric concept GET arguments bind successfully on both runtimes, and both apply GET sorting and reject invalid sort directions. It pins the deliberate differences above and a host-specific difference that is not a choice of Arc for TypeScript: Express answers an unknown path with its own HTML 404 without an Arc correlation header.

The suite needs the .NET 10 SDK and is not part of `yarn ci`. It is a bounded check of those routes, not a claim of full parity.
