Skip to main content

protocol/testing/conformance/network

packages/protocol/src/testing/conformance/network

Purpose

Public barrel for network-layer conformance properties. Network-layer conformance properties. Connection / presence / subscription invariants — Connect lifecycle, server-derived presence (PresenceSubscribe fan-out + presence/changed notifications), reconnect semantics, same-state collapse. Presence is server-derived from LeaseRegistry lifecycle plus WS connect/disconnect; PresenceService implements LeaseTransitionObserver and broadcasts presence/changed to subscribers. There is no client-driven presence/update RPC. Each register* lives in its own file. This barrel re-exports them by name AND aggregates them into NETWORK_PROPERTIES for the _shared/suite.ts aggregator.

Public surface

acquireClient

Function
export function acquireClient(
  ctx: ConformanceRunContext,
  propertyName: string,
  name: string,
): Effect.Effect<
  { agent: TestAgent; client: TestClient },
  PropertyInvariantViolation,
  Scope.Scope
>

acquireCloseableClient

Function
export function acquireCloseableClient(
  ctx: ConformanceRunContext,
  propertyName: string,
  agent: TestAgent,
  label: string,
): Effect.Effect<CloseableTestClient, PropertyInvariantViolation, Scope.Scope>

countPresenceChangedFor

Function
export function countPresenceChangedFor(
  client: TestClient,
  agentId: AgentId,
): Effect.Effect<number>

NETWORK_PROPERTIES

Variable
export const NETWORK_PROPERTIES: ReadonlyArray<
  (ctx: ConformanceRunContext) => void
> = [
  registerConnectBroadcast,
  registerDisconnectBroadcast,
  registerReconnectStorm,
  registerSameStateNoDoubleFire,
  registerMultiSubscriberFanOut,
  registerSubscribeAfterConnect,
]
All network-layer property registrars in legacy walk order (mirroring legacy presence.ts registration sequence).

PRESENCE_CATEGORY

Variable
export const PRESENCE_CATEGORY = "presence" as const

PRESENCE_DEFAULT_CAPTURE_CAPACITY

Variable
export const PRESENCE_DEFAULT_CAPTURE_CAPACITY = 256

PRESENCE_DEFAULT_TIMEOUT_MS

Variable
export const PRESENCE_DEFAULT_TIMEOUT_MS = 5000

PresenceChangedPayload

Interface
export interface PresenceChangedPayload {
  readonly agentId: string;
  readonly status: PresenceStatus;
}

PresenceStatus

TypeAlias
export type PresenceStatus = "online" | "working" | "offline";

export interface PresenceChangedPayload {
  readonly agentId: string;
  readonly status: PresenceStatus;
}

presenceStatusesFor

Function
export function presenceStatusesFor(
  client: TestClient,
  agentId: AgentId,
): Effect.Effect<ReadonlyArray<PresenceStatus>>

presenceViolation

Function
export function presenceViolation(
  name: string,
  reason: string,
): PropertyInvariantViolation

registerAgent

Function
export function registerAgent(
  ctx: ConformanceRunContext,
  propertyName: string,
  name: string,
): Effect.Effect<TestAgent, PropertyInvariantViolation>

registerConnectBroadcast

Function
export function registerConnectBroadcast(ctx: ConformanceRunContext): void

registerDisconnectBroadcast

Function
export function registerDisconnectBroadcast(ctx: ConformanceRunContext): void

registerMultiSubscriberFanOut

Function
export function registerMultiSubscriberFanOut(
  ctx: ConformanceRunContext,
): void

registerReconnectStorm

Function
export function registerReconnectStorm(ctx: ConformanceRunContext): void

registerSameStateNoDoubleFire

Function
export function registerSameStateNoDoubleFire(
  ctx: ConformanceRunContext,
): void

registerSubscribeAfterConnect

Function
export function registerSubscribeAfterConnect(
  ctx: ConformanceRunContext,
): void

subscribePresence

Function
export function subscribePresence(
  subscriber: TestClient,
  agentId: AgentId,
  propertyName: string,
): Effect.Effect<void, PropertyInvariantViolation>

waitForPresenceWithStatus

Function
export function waitForPresenceWithStatus(
  client: TestClient,
  expected: PresenceChangedPayload,
  propertyName: string,
  timeoutMs: number = PRESENCE_DEFAULT_TIMEOUT_MS,
): Effect.Effect<void, PropertyInvariantViolation>
Wait for the next presence/changed notification whose payload matches expected.agentId + expected.status. TestClient.subscribe(def) filters by descriptor only, so we consume the broad-union subscribeAll() Stream with a per-payload predicate and timeout it ourselves (#645: replaces the legacy polling client.notifications Stream).

Files

  • _helpers.ts
  • index.ts
  • presence-connect-broadcast.ts
  • presence-disconnect-broadcast.ts
  • presence-multi-subscriber-fan-out.ts
  • presence-reconnect-storm.ts
  • presence-same-state-no-double-fire.ts
  • presence-subscribe-after-connect.ts