---
title: JVM feature parity reference
description: Honest implementation status for Arc on Kotlin and Java compared with broader Arc concepts.
---


## Status key

| Status | Meaning |
| --- | --- |
| Implemented | Available and covered by source tests, contract tests, integration tests, or runnable samples. |
| JVM-specific | Supported with an intentionally JVM-native shape. |
| Partial | Usable behavior exists, with the stated boundary still remaining. |
| Not planned | Outside the Spring Boot, model-bound framework direction. |

## Feature matrix

| Area | Status | Current JVM contract |
| --- | --- | --- |
| Model-bound commands | Implemented | `@Command` plus one public instance `handle`; KSP generates reflection-free handlers. |
| Kotlin command async | JVM-specific | `suspend` handlers run in an application-owned, bounded coroutine scope. |
| Java command async | JVM-specific | Generated adapters await `CompletionStage` without blocking request threads. |
| Command `provide` | Implemented | Regular, `suspend`, and `CompletionStage` preparation supports ordered provided values, control short-circuiting, and service fallback without runtime method reflection. |
| Tuple and alternative returns | Implemented | Kotlin `Pair`/`Triple`, `CommandProvidedValues`, `CommandResponseValues`, and `ArcOneOf` alternatives are flattened in declaration order. |
| Aggregate command responses | Implemented | Runtime and KSP recursively flatten `Pair`, `Triple`, `ArcOneOf`, and nested `CommandResult` values in declaration order. Source-visible `@HandlesCommandResponseValues` declarations classify custom server-consumed leaves, and built-in event/control leaves are handled consistently. Exactly one client leaf is projected into runtime, proxy, and OpenAPI metadata; multiple client leaves fail with `ARCKSP0109`, while handled-only commands expose no fake client response. Binary annotations alone remain undiscoverable: the JVM-specific dependency declaration resource and tracked index are required (see [configuration](/arc/backend/kotlin/reference/configuration/#dependency-response-handler-metadata)); `ArcResponseHandlerMetadataFunctionalTest` exercises binary producer/consumer classification. Erased `CommandResponseValues` contents remain untyped metadata. |
| One-shot queries | Implemented | Static Java or `@JvmStatic` companion methods on `@ReadModel`; class-level `@QueryHttpMethod` defaults with method overrides; non-query companion/static helpers ignored unless explicitly query-annotated, while custom instance methods remain invalid; GET and optional RFC QUERY hosting with case-insensitive client argument names and fail-closed case collisions; generated performers inject interspersed service, `QueryRequest`, and `QueryContext` parameters without exposing them as client input. Omitted Kotlin client defaults execute at invocation, while supplied values, including explicit null, retain presence. |
| Concepts | Implemented | Kotlin classes and Java records implementing `ConceptAs<T>` serialize as their underlying scalar or enum value. KSP carries that shape through command, query, model, response, validation, TypeScript, OpenAPI, and Chronicle command-key contracts rather than exposing wrapper objects. |
| Polymorphic derived types | Implemented | `@DerivedType` writes `_derivedTypeId`, and code generation records every base-to-derivative mapping it saw — the declared interface plus each base class — on the generated `ArcArtifactModule` as real class references. The Spring Boot starter registers them into a `DerivedTypeRegistry` bean before Jackson reads anything, and `ArcArtifactModuleRegistry.registerDerivedTypes` does the same for explicit in-process registration; a `DerivedTypeRegistrar` bean adds a hierarchy code generation never processed, such as one that arrives only as a dependency binary. Arc .NET scans every loaded assembly at startup instead, so the JVM needs that registrar where .NET needs nothing. Reading fails closed on an identifier the registry cannot resolve, which matches .NET, and also when the discriminator is absent, where .NET returns `null` — an intentional divergence. |
| Temporal and UUID proxies | Implemented | Direct and concept-backed `LocalDate`, `LocalTime`, and `UUID` generate `DateOnly`, `TimeOnly`, and `Guid` from `@cratis/fundamentals`; UUID-to-`Guid` is an explicit .NET parity decision. Commands and GET query parameters serialize scalar strings, and returned generated models hydrate as class instances. Core and Spring disable `WRITE_DURATIONS_AS_TIMESTAMPS`, so `Duration` reads and writes ISO-8601 text, generates TypeScript `string`, and is OpenAPI `string`/`duration`; it is not Fundamentals `TimeSpan` because Java and C# wire formats differ. Tested `Period` behavior is limited to Core ISO-8601 round-trip and TypeScript `string` generation. `OffsetTime` generates as textual, untyped `string`; its offset-specific semantics are not hydrated into a class. `LocalDateTime`, `Instant`, `OffsetDateTime`, and `ZonedDateTime` remain JavaScript `Date`. |
| Observable queries | Implemented | `ObservableState<T>` is the Java-native counterpart of `MutableStateFlow`: a `Flow.Publisher<T>` that holds a current value, so a Java observable query answers a snapshot `GET` from it exactly as a Kotlin query returning a `StateFlow` does. Without it a Java application could only publish through a plain publisher, which has no current value and is therefore reported as not-ready on every snapshot however promptly it emits. `ObservableStateTest` and `ObservableStateJavaConformanceTest` cover replay, conflation, demand, cancellation and the `asKotlinFlow` unwrap. Primary reactive types are Kotlin `Flow<T>` / `Flow<List<T>>` and JDK `Flow.Publisher<T>` / `Publisher<List<T>>`; the optional `arc-rxjava3` artifact also accepts RxJava 3 `Observable<T>`, `ObservableSource<T>`, and `Subject<T>`. Arc .NET uses `IObservable<T>` / `ISubject<T>`; the JDK primary equivalents are `Flow.Publisher<T>` and `MutableStateFlow` / `SubmissionPublisher` respectively, requiring no external dependency. `reactor.core.publisher.Flux` is rejected to preserve the Spring-free `Source` boundary; `org.reactivestreams.Publisher` is rejected because it is superseded by the JDK type. Observable performers use revision ordering, full/delta transfer with the omitted-mode legacy snapshot plus change set, renderers, interceptors, and per-emission guards; keyless or invalid-key collection deltas use Arc .NET-compatible serialized JSON set identity and surface field changes as remove plus add; infrastructure parameters are injected rather than subscription-bound, and omitted Kotlin client defaults remain omitted through every binder. |
| Observable HTTP and hubs | Implemented | Bounded GET and enabled RFC QUERY HTTP snapshots that serve a `StateFlow` source's current value with 200 and report a source without one as not-ready with 202, direct GET SSE/WebSocket, multiplexed SSE/WebSocket hubs, revisions, heartbeats, caller/tenant capture, and terminal authorization behavior. `cratis.arc.observable-queries.allowed-origins` names the browser origins allowed to open a WebSocket; empty keeps Spring's same-origin default, which a deployment wants and which makes every handshake from a separate dev server fail with a `403` a browser reports only as a socket that never opens. `ArcObservableQueryWebSocketOriginTests` reads the origins off the handler mapping Spring built. Fixed multiplexed routes are connection-anonymous while successful credentials are captured; every subscription is independently authorized and isolated. WebSocket support remains optional by classpath and configuration. |
| Query paging and sorting | Implemented | GET reserved parameters, structured QUERY bodies, `QueryPage`, calculated paging metadata, and iterable fallback rendering. `QueryPagingSortingExecutionTest`, `QueryPagingSortingJavaConformanceTest`, and `ArcQueryPagingSortingHostingTests` execute nonempty data through the default pipelines: iterable results sort before zero-based paging and retain the pre-page total even when descriptor flags are false; provider-owned `QueryPage` items/order/totals remain unchanged. Original arrays are normalized for output but bypass iterable sorting/paging/counting. `QueryablePropertyAccessTest`, `QueryablePropertyAccessJavaConformanceTest`, and `ArcQueryPropertyAccessHostingTests` cover public-only accessor selection, singleton/mixed-type rejection, Kotlin declaration visibility across Java inheritance, public bean/record getter semantics, and cancellation/fatal propagation. Private storage is not read as a substitute for a public accessor; inaccessible and absent keys fail without a sorted payload and host exception details remain redacted. This is a JVM visibility safeguard, not a serialization-annotation or per-field authorization policy. Generated convenience methods remain separately capability-driven; no automatic array paging or general .NET backend equality is claimed. |
| Query extension points | Implemented | Ordered `QueryRendererFor<T>` and `InterceptReadModel<T>` contracts apply to one-shot and observable results; `GuardObservableQueryEmission` rechecks each observable emission, and a suppressed emission leaves first-delivery status to the next delivered one. Configured renderers match the original value and own data/paging; the automatic iterable renderer is a fallback only when none match. Explicit `QueryableQueryRenderer` stages consume current data and preserve null/non-iterable projections, never restoring original rows. `QueryRendererOwnershipTest`, its Java conformance counterpart, and `ArcQueryRendererOwnershipHostingTests` cover discarded rows, projections, provider totals/no premature source enumeration, explicit ordering, cancellation, and both query transports. Existing application renderers—including identity/logging renderers—must explicitly opt into in-memory processing where wanted; this is a JVM behavioral correction, not a claim of .NET renderer equivalence. |
| Query health | Implemented | `QueryHealthTracker` exposes snapshots and a `Flow`; `/.cratis/queries/health` exposes the current connection/subscription health. Intentional divergence: Arc .NET declares the health read model `[AllowAnonymous]`, while the JVM host requires an authenticated caller on both `GET` and `QUERY` whenever authentication handlers are registered, because the snapshot reports connection and subscription identifiers, remote IP addresses, user agents, and user identities. Applications with no authentication handler are unaffected. |
| Spring Data JPA | JVM-specific | Repository injection, generated `QueryRequest`/`Pageable`/`Sort` injection, exact `Page<T>` normalization, `DECLARED` contextual command read-model ownership, tenant-certified persistence units, and cold/shared observable `Flow` snapshots with demand-aware Java publishers. JPA notifications are explicit and in-process by default. Imperative command transactions are fixed-store, thread-bound opt-ins. |
| Spring Data MongoDB | JVM-specific | Repository injection, generated `QueryRequest`/`Pageable`/`Sort` injection, exact `Page<T>` normalization, `FALLBACK` contextual command read-model ownership, tenant-certified operations, and cold/shared observable `Flow` snapshots backed by reconnecting change streams with demand-aware Java publishers. Change streams require a replica set or sharded cluster. Imperative command transactions are fixed-store, thread-bound opt-ins. |
| Command and query-model validation | Implemented | Arc `CommandValidator` and `QueryValidator` contracts, severity thresholds, command validate routes, and stable envelopes apply in the real pipelines. When a Spring `Validator` bean exists, Jakarta validation automatically covers command and client-supplied typed one-shot/observable query-argument graphs; nested `@Valid` collections/maps and cycles retain stable member paths, while infrastructure parameters are neither required nor client-validated. An omitted Kotlin default has no pre-invocation value, so executable violations for that slot are ignored and the default executes at the model boundary. |
| Concept validation | Implemented | Reusable `ConceptValidator<TConcept>` rules apply across command and query object/record/collection/map graphs when supplied to the default validation filters. Spring auto-discovers ordered concept-validator beans alongside command/query validators, while replacement default filter beans remain authoritative (`ArcConceptValidationTests`, `ConceptValidationJavaConformanceTest`, and `ArcConceptValidationHostingTests` in `Integrations/SpringBoot`). Imperative bean rules remain server-only, separate from generated Jakarta validation metadata. |
| Shared fluent model validation | JVM-specific | `FluentModelValidator<T>` supports thirteen bounded literal rules, Kotlin/ordinary Java constructor authoring, generated module registration and concrete acyclic nested client composition. `ContractTests/FluentValidationContractTest`, `runtime.fluent.contract.ts` and `ArcFluentValidationNativeFunctionalTest` prove generated registration, real JVM/client rejection and indexed library invalidation. Dynamic/async predicates, warning severity, polymorphic/cyclic graphs and shared-model GET/observable transport remain unsupported; legacy annotation credit-card constraints remain server-only. See [shared validation](/arc/backend/kotlin/guides/validation/). |
| Member validation opt-out | JVM-specific | `@IgnoreValidation` cuts a logical member edge before getter/extractor access, including direct rules and descendant validation, without pruning authored fluent fingerprints or wire/binding metadata. `Source/IgnoreValidationTest`, `Integrations/SpringBoot/ArcIgnoreValidationHostingTests`, `ContractTests/IgnoreValidationContractTest`, `IgnoreValidationJavaContractTest`, and `runtime.ignore-validation.contract.ts` cover runtime, real Jakarta/HTTP, generated scenarios and real client/server behavior. `ArcFluentValidationNativeFunctionalTest` proves annotation/dependency edits, recovery and fresh-output equivalence. Owner imperative/class/group-sequence callbacks and executable parameter constraints remain active. Runtime bean-only getters are an explicit expansion; active shared graph limits and the fail-closed binary-record boundary remain. Manifest 8 requires producer/consumer regeneration; custom opaque validators require explicit factory integration. See [the bounded contract](/arc/backend/kotlin/reference/validation/#ignore-a-validation-member-edge). |
| Validation metadata | Implemented | KSP preserves exactly representable Jakarta constraints, recursive validation, and inherited concept rules in manifests/runtime descriptors. TypeScript validators merge concept and owning-member rules; unrepresentable client rules fail with `ARCKSP0301`. `Phone` and `Url` have client rules; credit-card constraints remain server-only because the pinned client runtime lacks one. JVM annotation coverage is intentionally broader than .NET DataAnnotations (Required, StringLength, MinLength, MaxLength, Range, RegularExpression, EmailAddress, Phone, Url, CreditCard): Hibernate `@Range`, Hibernate `@Length`, and Jakarta `@Digits` are additionally supported on the JVM. Annotation and DSL rules deliberately union rather than following `ValidationRulesExtractor.MergeValidationRules` precedence, because on the JVM both Jakarta and the DSL execute server-side — precedence would make the generated client weaker than the server. See [conjunction, duplication and contradictions](/arc/backend/kotlin/reference/validation/#conjunction-duplication-and-contradictions). |
| Authorization | Implemented | Anonymous, policy, role, and scheme metadata works through Arc pipelines and Spring principal capture. Operation-level metadata — `@AllowAnonymous`, `@Authorize` or `@Roles` — replaces the class declaration wholesale, matching Arc .NET's `AuthorizationEvaluator.IsAuthorized(MethodInfo)`, which resolves the method's own metadata first and falls back to the declaring type only when the method declares none. An operation therefore both narrows and opens: a `@Authorize` read model can expose one `@AllowAnonymous` query, which is what a login screen needs, and an `@AllowAnonymous` class can close one operation with `@Roles`. `ArcSymbolProcessorAuthorizationPrecedenceCompilationTest` covers both directions through generated metadata and the real `AuthorizationEvaluator`, and the Kotlin sample's `AuthenticationQueryItem` exercises the widening case over HTTP. Remaining intentional divergence, narrower than before: `@AllowAnonymous` combined with `@Authorize`/`@Roles` **on the same declaration** is a compile-time `ARCKSP0108` error, where .NET silently prefers anonymous. |
| Authentication | Implemented | Ordered coroutine `AuthenticationHandler` and Java `AsyncAuthenticationHandler` chains run before Arc endpoints; the first handler that recognizes the request decides, a recognized failure is terminal and cannot be overridden by a later handler, and anonymous is the outcome only when no handler recognized the request. Failures are generic, the chosen principal is propagated, and the identity cache cookie is excluded from credentials. Multiplexed observable transport connections may remain anonymous, but protected query subscriptions still fail through the query authorization pipeline. |
| Host correlation | Implemented | A servlet filter on `/*` establishes one correlation identifier per request for every route in the host, Arc-owned or not, matching the placement of the Arc .NET `CorrelationIdMiddleware`. It is ordered ahead of Spring Security's filter chain and the Arc authentication filter, reuses an inbound `X-Correlation-ID` only when it is a UUID, re-emits the canonical value as the request and response header, exposes it through `ArcCorrelation.of(request)`, and binds it to SLF4J MDC for the servlet thread only. Coroutine-visible correlation still comes from `CommandContext`, `QueryContext`, and the observability starter's thread-context element. |
| Introspection | Implemented | `/.cratis/commands` and `/.cratis/queries` return deterministic generated route, schema, authorization, transport, paging, and documentation metadata and omit infrastructure-owned query parameters. Defaulted client parameters report `hasDefault`, are absent from schema `required`, and expose no expression or invented value. UUID and supported terminal textual `java.time` values (`LocalDate`, `LocalTime`, `LocalDateTime`, `Instant`, `OffsetDateTime`, `ZonedDateTime`, `OffsetTime`, `Duration`, and `Period`) are scalar `string` schemas, including collection elements, rather than recursively described objects. |
| Identity | Implemented | Coroutine or Java asynchronous details provider, `/.cratis/me`, schema generation, client-readable identity cookie, and optional-provider startup validation. |
| Trusted platform identity headers | JVM-specific | Default-off Spring Security `AuthenticationConverter` and once-per-request chain filter consume the three `x-ms-client-principal` headers only through an explicit trusted-ingress policy (default deny). Canonical ID, name, roles, and provider collision handling follow the inspected `Arc.Core/Identity/MicrosoftIdentityPlatformAuthenticationHandler.cs` at Arc .NET `03200c1c52020e60e5d55c5ed38b5b189a899504`; stricter bounded parsing and partial-submission rejection are deliberate JVM boundaries, not raw handler equivalence. SpringBoot's `ArcPlatformAuthenticationConverterTests`, `ArcPlatformIdentityAutoConfigurationTests`, `ArcPlatformIdentityHostingTests`, `ArcPlatformIdentityDisabledTests`, `ArcPlatformAuthenticationFilterTests`, and compiled `PlatformIdentityJavaConformanceTest`/`PlatformApplicationChainJavaConformanceTest` prove parsing, optionality/backoff, real `/.cratis/me`, role/scheme/claim authorization, CSRF, existing identity preservation, and once-only execution. Application chains remain authoritative; the opt-in default protects every route. Unsigned base64 never proves sender identity; deployment ingress isolation/authentication remains the application's responsibility. |
| Users and tenants | Implemented | Anonymous `/.cratis/users` and `/.cratis/tenants` aggregate ordered coroutine and Java asynchronous providers, deduplicate by identifier, and return redacted failures. |
| Tenancy | Implemented | Fixed/header/query/claim/subdomain/development resolvers, ordered composition, fail-closed required mode, claim-membership checks, request/subscription capture, and application override beans without thread-local state. |
| Kotlin ergonomics | JVM-specific | Reified service lookup; result `fold`/`getOrThrow`/`onSuccess`/`validationOrNull`; ordered response factories; and property views for Java-method contracts are Kotlin-only conveniences that preserve the Java ABI. |
| Java Core adapters | JVM-specific | Blocking and `CompletionStage` adapters cover command/query filters, authorization filters and policies, validators, command scopes and response handlers, and manual artifacts. `JavaAsyncScope` provides cancellable command/query/authentication/observable/health facades over a caller-owned executor. Caller-thread `BlockingCommandPipeline` execute/validate and `BlockingQueryPipeline` perform facades require explicit per-call or constructor-bound options; Spring supplies backing-off unbound beans. `Source`'s `BlockingPipelineTest`, `BlockingRealPipelineInterruptionTest`, and `BlockingPipelineJavaConformanceTest`, plus `Integrations/SpringBoot`'s `ArcBlockingPipelineTests` and `BlockingPipelineJavaConformanceTest`, cover context/results, validate nonexecution, cancellation/interruption cleanup, migrated bounded-scope/reentry rejection, and Java service injection. Blocking invocations normalize directly observed callback `InterruptedException` (including propagated worker exceptions) to cancellation after cleanup and set the caller interrupt flag; this does not prove physical caller interruption, and swallowed interruption is undetectable. Legacy coroutine and guard-only calls retain their behavior. These are opt-in blocking calls, not another async bridge: no hidden timeout or ambient identity, no arbitrary external-coroutine detection, and no guarantee that cancelling a stage stops external work; see [Java calling limits](/arc/backend/kotlin/get-started/java/#blocking-interruption-and-limits). |
| TypeScript one-shot proxies | Implemented | Commands, queries, models, interfaces, derived types, enums, flags, paging hooks, validators, authorization metadata, and Kotlin/Java concepts erased to their underlying client types compile in strict mode against real `@cratis` packages. Query interfaces, descriptors, required arguments, properties, routes, validators, hooks, and imports include only client parameters; service, `QueryRequest`, and `QueryContext` parameters are omitted. Defaulted Kotlin parameters generate optional fields and call arguments and are excluded from `requiredRequestParameters` without copying a server literal. Strict contracts enable `verbatimModuleSyntax`, and generated interfaces use type-only imports where appropriate. Aggregate command metadata selects the single client leaf's exact type and enumerable shape; handled-only commands use the response-less command contract. Concept validation rules merge with owning command/query rules. The `DateOnly`/`TimeOnly`/`Guid` change is source-breaking for consumers that assigned `Date` or scalar strings. |
| TypeScript observable proxies | Implemented | Enumerable and single-result observable classes, React hooks, paging/sorting/change-stream helpers, conditional queries, validation, transport, and HTTP preference metadata omit infrastructure parameters; Kotlin defaults are optional capability metadata without emitted values. For both query transports, named sorting helpers use return-model properties (including represented class-base properties), not request arguments; capability flags remain authoritative. `QuerySortHelperTest` and `ArcProxyMappingRuntimeTest` cover parameterless/parameterized queries, inherited fields, request-field exclusion, collision-safe helper storage and actual sorting actions; `GeneratedTypeScriptProxiesTest` asserts the real KSP-produced Kotlin/Java Spring Data clients select returned `value` rather than request `label`. The pinned .NET model-bound generator derives helper names from parameters, so this is a documented JVM correctness divergence. Provider-specific field support and unrepresented interface inheritance are not inferred. |
| .NET-derived proxy differential gate | Implemented | `:GradlePlugin:test` compares sorted paths for all regular output files, then untouched JVM bytes (including headers) against the prepared repository-local expected fixture. Expected-only preparation validates 16 source identities against a literal table and fixture descriptors, reconstructs uppercase SHA-256 headers independently from expected bodies, and leaves three indexes headerless. Queries use declaring-model identities. The [complete preparation inventory](/arc/backend/kotlin/guides/typescript-proxies/#expected-only-differential-preparation) includes expected LF/trailing-whitespace handling, FixtureModel quote/indent preparation, CreateFixtures quote/import/layout/hook preparation and exact-site suppression, and five literal type-only import rewrites for `verbatimModuleSyntax`. Historical namespace/query-name casing and removed timestamps/hashes remain embedded capture-time transformations. `SetCommandValues`, `ClearCommandValues`, and query helper types such as `PerformQuery`, `SetSorting`, `SetPage`, `SetPageSize`, and `ChangeSet` become type-only imports. At `Commands/CreateFixtures.ts`, one additional expected-side correction changes `Command<ICreateFixtures, FixtureModel>` to `Command<ICreateFixtures, FixtureModel[]>`; .NET already calls `super(FixtureModel, true)`, so the scalar generic contradicts its enumerable runtime behavior. Only `Models/Observe.ts` also receives one exactly anchored expected-only formatting change: the zero-space blank line immediately before `ObserveParameters.filter: string;` becomes four spaces; `ObserveOne.ts` is excluded. `ExpectedSortHelperPreparation` additionally replaces the exact helper pairs in `Models/All.ts`, `Models/Search.ts`, and `Models/Observe.ts` with a literal return-field inventory after verifying unique anchors and fixed original block hashes; only All gains SortingActions imports, and the helper constructor no longer exposes its owner as `query`. Request parameters, routes, hooks and capability flags remain unchanged. This is an explicit semantic correction for the JVM's returned-row helper behavior, not raw .NET output parity. Missing/duplicate correction anchors and misplaced suppressions fail preparation. Actual byte/path mutation tests include a changed body with a valid recomputed hash. `Contracts/Shape.ts` is a class, not interface-emission proof. No normalization transforms JVM output. Capture SDK/tool versions remain unverified. The fixture currently contains no `Guid`, `DateOnly`, or `TimeOnly`, so focused generator and contract tests cover that mapping. This remains a drift gate for the normalized fixture, not an exact raw .NET-output comparison; capture-time fixture preparation is not yet reproducible tooling. |
| TypeScript proxy and runtime gates | Implemented | `:ContractTests:typeScriptBuild` installs the locked real `@cratis` packages, verifies deterministic regeneration, and compiles generated proxies in strict mode with `verbatimModuleSyntax` and type-only interface dependencies. The runtime harness has five wired unit tests plus 33 behavioral runtime tests: four ignore-validation tests, four shared-fluent tests and 15 general tests in separate UTC processes, five calendar tests in separate UTC, and five in separate `America/Los_Angeles` processes. Parsed TAP summaries require exact test/pass totals and zero fail, cancelled, skipped, or todo results; Spring spawn errors fail cleanly. The behavioral gate verifies validation, typed and hydrated command responses, safe malformed envelopes, correlation, GET/QUERY, paging/sorting, identity, multiplexed/direct WebSocket, direct SSE, scalar calendar/UUID transport, timezone stability, and `TimeOnly` millisecond truncation; `:ContractTests:check` depends on it. |
| Chronicle event transactions | Implemented | Returned events are staged until the final command result succeeds and committed as ordered `appendMany` batches per selected store. Generated command event metadata supplies optional source type, stream type, stream ID, and subject defaults to immediate and staged appends; explicit routed values win and command causation is appended. A collection may mix plain events routed by the captured `CommandContext.commandKey` with explicit `EventForEventSourceId` values; item order and explicit source IDs are preserved and malformed mixtures fail before append. `ChronicleCommandKeyRoutingTests` and its Java conformance counterpart prove stateful key providers are not resolved a second time, including null-key rejection and explicit-route preservation. Separate enrollments from one execution frame reuse one generated command causation link. `ChronicleStagedCausationTests` exercises the pinned real SDK preflight with mocked gRPC transport: different explicit or nested-frame chains remain rejected under its single-chain batch contract, not flattened or split. This does not prove real-kernel acceptance or heterogeneous nested-command lineage support. Failed commands discard staged events. No cross-store distributed transaction is provided. |
| Chronicle concurrency | Implemented | `EventsWithConcurrencyScopes` carries ordered routed events and exact per-source Chronicle scopes through Kotlin and Java builders; violations map to machine-readable validation feedback. |
| Chronicle read models | Implemented | Chronicle-discovered read models are declared to the command resolver registry, resolved by generated command key and tenant store, and released through a query interceptor before one-shot or observable results leave the pipeline. |
| Chronicle command side effects | Implemented | Reactors can explicitly hand registered command values to `ChronicleCommandSideEffectHandler`; nested aggregates run sequentially through the real pipeline and stop on failure. Causing identity is preserved without roles unless the reactor declares exact system roles. |
| Chronicle scenarios | Implemented | A `ServiceLoader` extender gives `CommandScenario` an in-memory event log, ordered given history, append assertions, and deterministic constraint/concurrency rejection, with Kotlin extensions and Java static bridges. No Chronicle kernel is started. |
| OpenAPI | Implemented | The optional starter generates and caches OpenAPI 3.1 from artifact metadata, including reusable underlying scalar/format/enum schemas for Kotlin and Java concepts, and omits infrastructure-owned query parameters. Kotlin defaulted client parameters are non-required and carry no invented OpenAPI default. UUID, date, time, and duration wire values are scalar strings with `uuid`, `date`, `time`, and `duration` formats. Command result schemas expose only the unique client response leaf from ordered aggregate metadata and omit `response` for handled-only commands. The starter serves `/v3/api-docs` plus `/.cratis/openapi.json`; application beans/routes win. RFC QUERY is omitted because OpenAPI Path Items do not define it. Imperative concept validators are runtime behavior, not OpenAPI keywords. |
| Observability | Implemented | The optional starter decorates command execute/validate, one-shot and observable query open/subscription/emission, authentication, and identity-details execution with Micrometer observations. Stable low-cardinality tags exclude tenant, user, command values, and query arguments; correlation uses observation context plus optional OpenTelemetry baggage and SLF4J MDC. |
| Source documentation | Implemented | KSP reads Kotlin KDoc and Java Javadoc for commands, query methods, client query parameters, model types and properties, interfaces and properties, and enum declarations, and the manifest carries them as single-line summaries that runtime introspection and generated TypeScript JSDoc render. A member falls back to a Kotlin `@property` or Java `@param` tag; enum members, setters, backing fields, runtime query fields, and barrel files are deliberately undocumented, and OpenAPI keeps conventional descriptions. Only the first paragraph is captured, bounded at 512 Unicode code points. Comparable Arc .NET behavior has not been demonstrated here and is not claimed. |
| KSP diagnostics | Implemented | Stable `ARCKSP` codes cover configuration, commands, queries, proxy shapes, Jakarta validation metadata, enum values, interoperability warnings, and unclassified failures. |
| Measured cross-runtime proxy agreement | Partial | `ArcGradlePluginFunctionalTest` generates JVM proxies for Kotlin declarations mirroring the captured .NET fixture and compares them file by file against `differential/captured`, with both generators at `segmentsToSkip` 0. Confirmed from real output on both sides rather than from JVM-side assertion: the generated artifact sets match; routes match exactly; `Address.ts` and `OrderKind.ts` are byte-identical apart from the namespace casing each runtime echoes into the header `Source` field, with identical content hashes, which the test asserts so it cannot silently regress; and `Guid`, `DateOnly`, `TimeOnly`, `DateTimeOffset`/`OffsetDateTime`, enum, and nested-model mappings agree. Cosmetic divergences remain: .NET sorts members alphabetically while the JVM preserves declaration order, .NET emits one import per `@cratis/fundamentals` type while the JVM combines them, and the JVM emits type-only imports for `verbatimModuleSyntax`. Generated paging/sorting remains capability-driven on the JVM: `QueryPage` and exact Spring `Page` returns also advertise paging without adapter parameters. Core's default renderer already sorts/pages runtime `Iterable` values independently of those flags, but KSP does not advertise that in-memory capability. Arc .NET's enumerable helper generation is not proof of server behavior: at `v22.14.0` its default renderer handles runtime `IQueryable`, not an arbitrary list or array. The inspected implementation and documentation establish this distinction; the empty capture fixture itself cannot prove pagination. `CapturedProxyContract` now checks exact relative paths (not basenames), capture checksums, fixed header identities, model/enum full bytes after expected-header-only preparation, and independent literal command/query contracts for routes, members, constructors, collection shape, parameters and methods. `CapturedProxyContractTest` mutates those contracts and file inventories to prove mismatches fail, including duplicate basenames and renewed hashes. **This is Partial**: command/query comparison is a bounded token contract with explicit import/order and capability exceptions, not raw byte equality, type-soundness of ignored hook calls, or general equivalence. JVM output bytes are never rewritten. |
| Reproducible Arc .NET proxy capture | Partial | `GradlePlugin/src/test/resources/differential/capture/capture.sh` regenerates real Arc .NET proxy output from published NuGet packages at pinned `Cratis.Arc` and `Cratis.Arc.ProxyGenerator` 22.14.0, matching Arc .NET's `v22.14.0` tag. It never reads, builds, or copies from a sibling checkout. The hardened harness pins SDK 10.0.400, both reflection/runtime frameworks at 10.0.11, the locked NuGet graph and archive/payload hashes; it preserves raw bytes and writes format-2 provenance with input hashes. Output must be a new lifecycle-managed `.ai-work` destination; existing paths and symlinks are refused and publication is atomic without replacement. `test_capture.py` covers corruption, exact normalization, failures and output safety. Two fresh normalized trees were verified equal to each other and the checked-in seven-file comparison fixture; complete raw trees/manifests are intentionally not byte-identical because they retain timestamps. Exactly one normalization is applied, to .NET output only: the generator's wall-clock `Time:` header field, which the JVM generator does not emit and which otherwise makes the capture differ from itself every run. The newly authored fixture carries `Guid`, `DateOnly`, and `TimeOnly`, confirming from real .NET output rather than assertion that Arc .NET maps them to `Guid`/`DateOnly`/`TimeOnly` from `@cratis/fundamentals`, camel-cases enum members behind a `Number` descriptor, and imports nested models relatively. **This is Partial**: the older hand-prepared `differential/dotnet` drift gate remains separate and unchanged. The seven-file captured contract check above is narrower than a whole-generator or server equivalence proof. `:GradlePlugin:verifyCapturedProxyBaseline` now runs before the ordinary GradlePlugin tests and checks the reviewed seven-file baseline against its input hashes and SDK/runtime/package/tool pins, with mutation tests for stale scripts/locks, byte changes even after renewed snapshot hashes, metadata drift, symlinks and path inventories. This offline consistency gate needs no .NET installation, network, package-cache reads or retained `.ai-work` capture. `verify_baseline.py --candidate` requires a full raw/normalized capture and matching current inputs before emitting a review candidate. The receipt is not an attestation: its evidence digest does not by itself prove tool execution, and coordinated changes still require review. Fresh capture/provenance verification remains explicit, not a hidden network operation in ordinary JVM tests, and Linux capture execution has not been verified. No raw .NET output equivalence follows from this harness. |
| External TypeScript package mappings and type overrides | Implemented | `proxies { mapType(...) }` maps a JVM type to a TypeScript type with an optional npm package, and `mapPackage(...)` maps every model type under a JVM package to an npm package it is imported from by simple name. Mappings are consulted ahead of the generator's built-in type map, so an entry corrects an existing mapping as well as declaring an unknown one; concepts unwrap first, so the underlying type is what a mapping matches, as in Arc .NET's `TypeExtensions.GetTargetType`. A mapped type is excluded from emission, matching .NET's `IsFromMappedAssembly` filter, so a local declaration and an external import never collide. The longest matching package wins. Blank components are named in warnings; unsafe or unrepresentable nonblank mappings and import collisions fail before output writes. Unpackaged overrides are limited to `string`, `number`, `boolean`, `object`, and `Date` with actual runtime constructors; manifest interfaces and numeric enums retain `Object`/`Number` descriptors and type-only imports. External classes require compatible Fundamentals field metadata; mappings never change server JSON. External map-value and polymorphic-base/derivative hydration remain unsupported. The standalone CLI takes the same values as repeatable `--type-to-typescript` and `--package-to-npm` options, with the same bounded three-part split. `ArcProxyTypeMappingTest` covers resolution, diagnostics, collision rejection and stale-file transitions. `ArcProxyMappingRuntimeTest` strictly compiles generated clients against the locked packages and executes primitive overrides, nested/list/interface/enum hydration and mapped command/query responses through a local HTTP fixture. `ProxyMappingsJavaConformanceTest` executes the public Gradle task/DSL from Java. Dependency declaration checking uses the repository's existing `skipLibCheck` setting; generated TypeScript remains checked. The JVM keys package mappings on a JVM package prefix because it has no assembly identity to key on; .NET's `--exclude-type`, `--exclude-namespace`, and `--namespace-root` options have no equivalent and none is claimed. |
| Artifact roots without commands or queries | JVM-specific | `@ExportedType` makes a public top-level concrete class, enum class, interface, or concept an explicit artifact root; unsupported targets fail with `ARCKSP0306`, covered by `ArcSymbolProcessorExportedTypeCompilationTest` and Kotlin/Java negative fixtures. Public concrete source identity providers and typed factory returns now automatically contribute supported details roots, including inherited generic specialization and anonymous providers behind typed factories. `ArcSymbolProcessorIdentityCompilationTest` covers Kotlin, ordinary compiled Java and later rounds; `ArcIdentityDiscoveryFunctionalTest` covers native correction, addition/removal and fresh-output equivalence. `GeneratedIdentityArtifactsTest`, `IdentityArtifactsJavaContractTest` and `GeneratedTypeScriptProxiesTest` cover the module, artifact manifest and generated client. The Kotlin sample generates `SampleIdentityDetails.ts` without an explicit export annotation. Identity-only compilations still emit the module, service entry and empty command/query lists. Erased, wildcard/star, unspecialized, inaccessible or unsupported details boundaries fail with `ARCKSP0307`. Discovery reads declarations, not bodies or runtime beans; dependency-only providers are not scanned wholesale, though source-visible bindings can use dependency generic signatures. Explicit export remains a fallback for supported source DTOs without such a declaration. No .NET output equivalence, assembly scanning, bulk DTO export or `--library-mode` equivalent is claimed. |
| Binary compatibility | Implemented | Checked `.api` baselines and `apiCheck` cover published runtime modules, integrations, testing, `arc-ksp`, and `arc-gradle-plugin`; changes require an intentional baseline update. Manifest format 8 adds explicit property validation-ignore metadata after format 7's optional typed command event metadata, while retaining recursive type shapes, canonical query parameter sources, legacy JVM programmatic constructors, and source documentation. `IgnoreValidationMetadataJavaConformanceTest` calls the earlier property constructors and round-trips the explicit flag; `IgnoreValidationMetadataTest` rejects prior formats and missing flags. Rebuild metadata producers and consumers together. Earlier command constructor descriptors, including Kotlin default-argument bridges, remain available. |
| Runtime hardening | Implemented | Bounded coroutine admission/queueing, request bodies, timeouts, scope completion, observable connections/subscriptions/buffers/messages/tombstones, safe error redaction, and 413/429/503 fail-closed responses are implemented. |
| Testing | Implemented | Kotlin scenarios and blocking/asynchronous Java bridges exercise real command, query, and observable pipelines with services, filters, validators, authorization, renderers, interceptors, guards, and tenant context. Command-side read models can be pinned to a known state, optionally per command key, through Arc's own ownership registry rather than a store. A Java-authored temporal contract executes a generated Java command and query through the public `JavaAsyncScope` and real pipelines. Chronicle adds its in-memory scenario extender rather than a separate fake pipeline. |
| Roslyn analyzers | JVM-specific | KSP compile-time diagnostics are the JVM substitute; Roslyn does not apply. |
| Controllers | Not planned | Arc generates model-bound Spring MVC endpoints. |
| Non-Spring hosting | Not planned | Arc targets Spring Boot; the Spring-free compiler/Gradle boundary does not promise another host. |
| Static file / SPA fallback hosting | Not planned | Use Spring Boot static-resource serving and application-configured Spring MVC fallback facilities, not Arc hosting APIs. |
| `@FromRequest` | Not planned | Existing `QueryRequest`/`QueryContext` injection and Spring binding cover the supported request inputs; no arbitrary request-injection API is promised. |
| `@IgnoreAutoRegistration` | JVM-specific | Command/query generation entry points are annotated declarations (`@Command` and `@ReadModel`), so those entry points need no opt-out annotation. Identity details additionally become automatic roots through public concrete source providers and typed factory returns, as covered by `ArcSymbolProcessorIdentityCompilationTest`; this discovery does not register runtime beans. Reachable-type traversal and diagnostic discovery also occur; this does not claim all discovery is annotation-only. `ArcSymbolProcessor.process` defines these entry points. In `CodeGeneration/KSP`, `ArcSymbolProcessorCommandEventMetadataCompilationTest` and `ArcSymbolProcessorQueryDefaultsCompilationTest` cover annotated command/query generation; `ArcSymbolProcessorNegativeCompilationTest` covers the missing-command warning. |
| `@GenerateOneOf` | Not planned | Runtime `ArcOneOf` alternatives already exist; generating union types is a separate capability and is not planned. |
| Screenplay | Not planned | No JVM equivalent is provided; Screenplay is outside this product's scope. Existing in-process scenarios are not Screenplay parity. |
| Transparent query and Spring Data framework parameters | Implemented | Generated query performers inject exact `QueryRequest`, `QueryContext`, Spring Data Commons `Pageable`, and `Sort` values in declaration order, normalize exact non-null Spring `Page<T>` returns, and emit explicit paging/sorting capability flags. Command handlers resolve exact JPA/Mongo read-model parameters through ownership arbitration and captured tenant context; owned absence maps to Kotlin null, Java `Optional.empty()`, or deterministic `dependencyUnavailable` validation for required parameters without changing ordinary-service and resolver exception behavior. |
| Cross-store transactions | Not planned | Chronicle, JPA, and MongoDB scopes cannot form one distributed atomic transaction; applications must design for partial completion and compensation. |
| Paired command/query HTTP conformance | Partial | Explicit `:ContractTests:httpConformanceTest` runs nine common cases against three real processes: a newly authored ASP.NET task board from published Arc 22.14.0 (SDK 10.0.400, runtime 10.0.11, locked package/archive checks), plus the existing generated Kotlin and ordinary-Java Spring task boards. `ContractTests/HttpConformance/contract.py` asserts two distinct create IDs and typed responses, GET/QUERY identifier binding, complete enumerable snapshots, validate-route nonexecution, completion response/state, malformed-command 400 validation without mutation/parser details, and 404 status. Success flags/correlation UUIDs and QUERY cache policy are checked. Raw bodies are retained, not rewritten. The gate is opt-in, database-free, loopback-only, bounded and outside ordinary build/check. Harness tests cover mutation detection and process cleanup. This does not prove equivalent validation rules, authentication/authorization rejection, null/default handling, temporal precision, paging requests, streaming, persistence or aggregate lifecycle. Paging counts and framework 404 bodies demonstrably differ and remain outside shared equality assertions; overall parity is still Partial. |
| Full Arc .NET parity | Partial | The semantically normalized .NET-derived proxy fixture covers selected generated shapes, but neither that fixture nor the project claims exact raw-output compatibility or every Arc .NET feature, analyzer, persistence seam, or hosting model. |

## Ordered P0 parity backlog

1. **Calendar and UUID proxy fidelity — complete.** `LocalDate`/`LocalTime`/`UUID` now use `DateOnly`/`TimeOnly`/`Guid`, with scalar command and GET transport, generated-model hydration, strict import contracts, and timezone-separated runtime coverage.
2. **Tenant-safe Spring Data command read models — implemented.** Generated Kotlin/Java handlers resolve exact mapped read models through JPA `DECLARED` and MongoDB `FALLBACK` ownership. Tenant routing is certified and fail-closed; compatibility adapters remain fixed-store only.
3. **Nested Chronicle transaction ownership — complete.** Nested structured executions share one explicit root staging area with no savepoints; ignored child failure/cancellation makes the root rollback-only, late joins fail, and the root emits one ordered `appendMany` only after local scopes succeed.

The completed ownership slices do not create a distributed transaction. Imperative JPA and MongoDB scopes remain thread-bound opt-ins. MongoDB may commit before JPA fails, and both local stores may commit before Chronicle fails or has an indeterminate external outcome. Applications must continue to design for reconciliation, idempotency, and compensation.

## Remaining temporal client limits

Raw `08:09:10.1235567` hydrates through the pinned `TimeOnly` as `08:09:10.123`; because rounding would yield `.124`, the runtime contract proves truncation rather than rounding. Arc accepts and emits `LocalTime` values with up to seven fractional digits for 100 ns compatibility. Deserialization rejects eight or nine fractional digits, and serialization rejects values finer than 100 ns rather than rounding or truncating them. This server binding is distinct from the shared `@cratis/arc` generated-client limitation: explicit RFC QUERY bodies pass `DateOnly` or `TimeOnly` component objects to native `JSON.stringify` because those classes have no `toJSON()`. Prefer GET until upstream serialization uses the typed serializer or `toJSON()`. `Guid` is unaffected because it has `toJSON()`, and the JVM server continues to require scalar date/time strings.

JavaScript `Date` also cannot preserve every remaining JVM temporal distinction: mapping `LocalDateTime` invents a zone, while mapping `OffsetDateTime` or `ZonedDateTime` loses original offset or zone identity.

## Server-side temporal precision

`LocalTime` is the only temporal type Arc guards at the 100 ns boundary .NET counts in. Every other type goes through `JavaTimeModule` as ISO-8601 text and keeps whatever the JVM holds, which for the date-time types and `Duration` is a full nanosecond — finer than a .NET tick can carry. The table states what the Kotlin mapper does; each row is demonstrated by a test.

| JVM type | Arc wire value | Precision the JVM server keeps | Precision the .NET counterpart supports |
| --- | --- | --- | --- |
| `LocalTime` | `HH:mm:ss` with up to seven fractional digits | Exactly 100 ns. A finer value is refused on write, and eight or nine fractional digits are refused on read. | `TimeOnly` writes the round-trip format, which is seven fractional digits, or 100 ns ticks. |
| `LocalDate` | `yyyy-MM-dd` | No sub-day component exists to lose. | `DateOnly` writes the same round-trip date. |
| `Instant`, `ZonedDateTime`, `LocalDateTime` | ISO-8601 text | Full nanoseconds, so nine fractional digits survive a round trip. | `DateTime` and `DateTimeOffset` have no Arc converter and use the `System.Text.Json` default, which round-trips at most seven. |
| `OffsetDateTime` | ISO-8601 text with an offset | Full nanoseconds are written and read, but a read normalizes the value to UTC, so the original offset does not survive even though the instant does. | Same seven-digit ceiling. |
| `Duration` | ISO-8601 text | Full nanoseconds. | `TimeSpan` has no Arc converter and uses the `System.Text.Json` default, which is 100 ns ticks. |
| `UUID` | Lowercase dashed text | Exact. A read accepts upper case and normalizes it. | `Guid` has no Arc converter and uses the `System.Text.Json` default dashed form. |

A JVM value with more than seven fractional digits is therefore representable on the Arc wire for every type except `LocalTime`, and a .NET peer reading it cannot hold the extra precision. Arc does not detect or reject that today outside `LocalTime`. Applications that must interoperate at exact precision should keep date-time values at or coarser than 100 ns themselves, or model the value as a `LocalTime` where the guard already exists.
