Skip to content

Parity Coverage Report ​

This page reports the current coverage of the cross-transport parity invariant. It is updated manually when parity scenarios are added or removed; the underlying numbers can be regenerated from the parity test files at any time.

This is a source inventory, not a record of a successful test run. Run the parity suite on the revision you intend to validate.

Scenarios by group ​

GroupSurfaceFileScenarios
3Server-side interceptor ordering (3.1), header injection through a symmetric server interceptor (3.2), successful-call smoke checks for timeout (3.3a), retry (3.3b), bulkhead (3.3c), circuit-breaker (3.3d), logger (3.3e), serializer (3.3f)packages/testing/tests/parity/interceptors.parity.test.ts8
3aProto-declared validation on the shipped chain createDefaultInterceptors() with real buf.validate annotations (success, single-rule violation, aggregated violations, client-streaming validation, no-bypass API). Violations are compared as ConnectError.details: wire bytes plus decoded field path, rule id, and messagepackages/testing/tests/parity/validation.parity.test.ts5
3bProto-declared authn and authz on the shipped createErrorHandlerInterceptor + createJwtAuthInterceptor + createProtoAuthzInterceptor chain with real connectum.auth.v1 options (success with scope and verified subject in the handler, unauthenticated, permission denied, public method served anonymously, no-bypass API)packages/auth/tests/parity/authorization.parity.test.ts5
3cVerified identity inside server-streaming and bidi handlers (before the first suspension, after an await, after a yield, in finally)packages/auth/tests/parity/auth-stream-identity.parity.test.ts1
4Streaming & cancellation (unary, server-stream, client-stream, bidi, unary cancel, stream mid-cancel, handler cleanup after abort, handler cleanup after break + abort)packages/testing/tests/parity/streaming.parity.test.ts8
5Error mapping (ConnectError(NotFound), plain Error → internal, interceptor-thrown error)packages/testing/tests/parity/errors.parity.test.ts3
6HTTP / local coexistence (concurrent observation by one interceptor; server.start() not required for local invoke)packages/testing/tests/parity/coexistence.parity.test.ts + packages/core/tests/integration/localTransport.test.ts2
7aOTEL tracing & metrics (unary spans, streaming events, error spans, metrics labels, trace-context propagation, instrument subset, connectum.transport attribute, message sizes of a unary call and of a stream, streaming call duration, error attributes of a failed stream)packages/otel/tests/parity/otel.parity.test.ts11
7bOTEL telemetry through the driver and the default comparison (three scenarios in a row, each recording a client and a server span and one call per duration histogram, following the collector recipe; one test pins what happens when a scenario skips shutdownProvider())packages/otel/tests/parity/parityDriver.parity.test.ts3
8Request admission (rejecting requestGate, requestGate throwing a plain Error, admitting requestGate, readMaxBytes over the limit, readMaxBytes at the limit, server.stop() aborting an in-flight call)packages/testing/tests/parity/requestAdmission.parity.test.ts6
9gRPC Server Reflection (one bidi stream with every request kind: listing, import closure, per-stream "already sent" state, symbol and extension lookup, error answers; the reflection service described by symbol; a bounded error message)packages/testing/tests/parity/reflection.parity.test.ts3
10Headers, trailers and ConnectError metadata reported exactly as the client sees them, without filtering protocol headers (response headers, trailers, error metadata)packages/testing/tests/parity/clientView.parity.test.ts3
11Catalog-routed ctx.call / ctx.stream on a catalog generated by buf and protoc-gen-connectum-catalog, in three topologies (target on the same server; target on another server through remoteResolver; two remote hops): unary, server-stream, client-stream and bidi calls, a Connect error of the target (unary, after streamed messages, client-stream, bidi), cancellation of a unary call and of a server stream, plus five calls without a route (a catalog service nobody serves, an unknown service, an unknown method, a streaming method called with ctx.call, a server without a catalog) and a remote service that is down. Expected results are literals from the documented contract, checked on both transports before they are comparedpackages/testing/tests/parity/catalog.parity.test.ts36
Total94

Of these, 79 scenarios (groups 3, 3a, 3b, 3c, 4, 5, 7b, 8, 9, 10, 11, except the two no-bypass checks of groups 3a and 3b, which are standalone tests) go through the unified transportParityTest() driver in @connectum/testing/parity and produce a structural diff between HTTP and local. The 11 OTEL scenarios and 2 coexistence scenarios are written as paired test() cases that drive both transports explicitly and assert equality of observable signals — semantically equivalent to the driver, but expressed in long form because they need bespoke exporter setup (OTEL) or asymmetric assertions (coexistence).

Coverage analysis ​

Observable behaviours that a service can produce, and their current parity coverage:

Observable behaviourCovered
Response payload (unary)✅ groups 3a / 3b / 5
Response payload (streaming)✅ group 4
Response headers / trailers✅ groups 3 and 10 (via driver diff; protocol headers are dropped before comparing)
ConnectError code / message✅ groups 3a / 3b / 5
ConnectError metadata / details✅ groups 3a / 3b
Streaming message order✅ group 4
Cancellation propagation✅ group 4 (5, 6)
Handler-side cleanup after cancellation (finally, context.signal)✅ group 4 (7, 8)
Interceptor chain order✅ group 3
Validation interceptor outcomes✅ group 3a
Auth/authz interceptor outcomes✅ groups 3b / 3c
OTEL span attributes / status✅ group 7a
OTEL span events (streaming)✅ group 7a
OTEL trace-context propagation✅ group 7a
OTEL metrics (names, labels, values; duration histograms by observation count)✅ groups 7a and 7b
Coexistence (one server, two transports)✅ group 6
Server lifecycle (local before start())✅ group 6.2
Request admission (requestGate, readMaxBytes)✅ group 8
Server shutdown aborts in-flight calls✅ group 8
Protocol answers (gRPC Server Reflection)✅ group 9
Catalog-routed calls (ctx.call, ctx.stream; same server, another server, two remote hops)✅ group 11

Behaviours not covered by parity (by design, see parity-invariant.md): TLS, HTTP/2 framing, content-encoding negotiation, :authority / real-host req.url, gzip — these are wire-only and have no in-process analogue. The diagnostic text of a readMaxBytes rejection is the one documented message exception; group 8 still compares its code and limit.

The table names the surfaces exercised by these scenarios; it does not measure the fraction of all possible service behavior covered. In particular, the interceptor smoke cases compare successful response payloads, not timeout, retry, breaker, or bulkhead failure behavior. The logger case does not compare sink output. Use the scenario implementations and the latest suite output to assess a change.

How to add a scenario ​

  1. Pick the right file in packages/testing/tests/parity/ (or packages/otel/tests/parity/ for observability, or packages/auth/tests/parity/ for authentication and authorization, which cannot live in @connectum/testing because that package would then depend on @connectum/auth, which already depends on it).

  2. For most cases, wrap the scenario with transportParityTest:

    typescript
    transportParityTest("group N.M: short title", {
      services: [myRoutes],
      scenario: async ({ transport }) => {
        const client = createClient(MyService, transport);
        return { response: await client.myMethod({ /* ... */ }) };
      },
    });

    A scenario in packages/otel/tests/parity/ that asserts spans or metrics from @connectum/otel interceptors adds telemetry: { shutdownProvider } (shutdownProvider comes from @connectum/otel) and sets OTEL_TRACES_EXPORTER=none and OTEL_METRICS_EXPORTER=none:

    typescript
    transportParityTest("group 7a: short title", {
      services: [myRoutes],
      interceptors: [createOtelInterceptor()],
      telemetry: { shutdownProvider },
      scenario: async ({ transport, spans }) => {
        const client = createClient(MyService, transport);
        await client.myMethod({ /* ... */ });
        return { spans: spans.flush() };
      },
    });

    Without it, only the first scenario in a process records spans; the later ones compare two empty lists and pass. See Spans and metrics of @connectum/otel in a test.

  3. From the framework repository root, run bash ./scripts/parity-suite.sh locally.

  4. Update the table above.