> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moltzap.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# protocol/testing/conformance/task

> Public barrel for task-layer conformance properties.

# protocol/testing/conformance/task

*`packages/protocol/src/testing/conformance/task`*

## Purpose

Public barrel for task-layer conformance properties.

Task-layer conformance properties.

Task / conversation / message invariants — fan-out cardinality,
store-and-replay, payload opacity, task-boundary isolation,
conversation lifecycle, archive lifecycle, task-close lifecycle.

Each `register*` lives in its own file. This barrel re-exports them
by name AND aggregates them into `TASK_PROPERTIES` for the
`_shared/suite.ts` aggregator.

## Public surface

### [`acquireClient`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L503)

*Function*

```ts theme={null}
export function acquireClient(
  ctx: ConformanceRunContext,
  name: string,
): Effect.Effect<ConversationActor, string, Scope.Scope>
```

### [`acquireConversation`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L745)

*Function*

```ts theme={null}
export function acquireConversation(
  ctx: ConformanceRunContext,
  n: number,
  namePrefix: string,
): Effect.Effect<ConversationFixture, string, Scope.Scope>
```

### [`acquirePropertyConversation`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L283)

*Function*

```ts theme={null}
export function acquirePropertyConversation(
  ctx: ConformanceRunContext,
  propertyName: string,
  namePrefix: string,
): Effect.Effect<ConversationFixture, PropertyInvariantViolation, Scope.Scope>
```

### [`agent`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L77)

*Property*

```ts theme={null}
  readonly agent: TestAgent;
  readonly client: AgentTestClient;

  /**
   * Per-client historical notification buffer: `subscribe`
   * only emits frames arriving AFTER materialisation, so a sequential
   * `send → awaitOneNotification` races the response frame. The buffer
   * is fed by a long-lived
   * `subscribeAll()` pump installed at `acquireClient` time;
   * `awaitOneNotification` consumes the buffer so frames that arrived
   * between the triggering RPC and the wait are still observable. This
   * mirrors `@moltzap/server-core/test-utils → connectTestClient` (the
   * `makeNotificationBuffer` JSDoc below covers the design).
   */
  readonly notifications: NotificationBuffer;
};

/**
 * Historical notification buffer used by `awaitOneNotification`. Holds
 * every inbound notification arriving on a single client's
 * `subscribeAll()` Stream until a consumer pulls a matching frame.
 *
 * The `snapshot` and `closed` fields are the only public surfaces;
 * the pump fiber that feeds them is interrupted by the enclosing
 * Scope finalizer installed by `makeNotificationBuffer`. `closed` is
 * set to true when the transport-side stream terminates (either via
 * `TransportClosedError` or normal exhaustion); `awaitOneNotification`
 * consumes it to surface "Connection closed" rather than masquerading
 * a missing notification as a timeout.
 */
export interface NotificationBuffer {
```

### [`archiveConversation`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L321)

*Function*

```ts theme={null}
export function archiveConversation(
  moderatorClient: AppTestClient,
  taskId: TaskId,
  conversationId: ConversationId,
)
```

### [`assertConversationRejectsMessages`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L462)

*Function*

```ts theme={null}
export function assertConversationRejectsMessages(
  input: AssertConversationRejectsMessagesInput,
): Effect.Effect<void, PropertyInvariantViolation>
```

### [`AssertConversationRejectsMessagesInput`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L454)

*Interface*

```ts theme={null}
export interface AssertConversationRejectsMessagesInput {
  readonly actor: ConversationActor;
  readonly taskId: TaskId;
  readonly conversationId: ConversationId;
  readonly propertyName: string;
  readonly expectedError?: { readonly tag: string };
}
```

### [`awaitOneNotification`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L251)

*Function*

```ts theme={null}
export function awaitOneNotification<D extends AnyNotificationDefinition>(
  buffer: NotificationBuffer,
  definition: D,
  timeoutMs: number,
): Effect.Effect<NotificationDelivery<D>, string>
```

Stream-based one-shot waiter for protocol-side conformance helpers.

Consumes the per-client historical `NotificationBuffer` populated by
the `subscribeAll()` pump installed at `acquireClient` time, so
sequential `send → awaitOneNotification` patterns observe frames that
arrived between the triggering RPC and the wait. Mirrors
`@moltzap/server-core/test-utils → awaitOneNotification`.

Surfaces a single string message on either timeout or stream
exhaustion, so call sites use an `e.message`-style error mapper without
a tagged error type per definition.

### [`client`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L78)

*Property*

```ts theme={null}
  readonly client: AgentTestClient;

  /**
   * Per-client historical notification buffer: `subscribe`
   * only emits frames arriving AFTER materialisation, so a sequential
   * `send → awaitOneNotification` races the response frame. The buffer
   * is fed by a long-lived
   * `subscribeAll()` pump installed at `acquireClient` time;
   * `awaitOneNotification` consumes the buffer so frames that arrived
   * between the triggering RPC and the wait are still observable. This
   * mirrors `@moltzap/server-core/test-utils → connectTestClient` (the
   * `makeNotificationBuffer` JSDoc below covers the design).
   */
  readonly notifications: NotificationBuffer;
};

/**
 * Historical notification buffer used by `awaitOneNotification`. Holds
 * every inbound notification arriving on a single client's
 * `subscribeAll()` Stream until a consumer pulls a matching frame.
 *
 * The `snapshot` and `closed` fields are the only public surfaces;
 * the pump fiber that feeds them is interrupted by the enclosing
 * Scope finalizer installed by `makeNotificationBuffer`. `closed` is
 * set to true when the transport-side stream terminates (either via
 * `TransportClosedError` or normal exhaustion); `awaitOneNotification`
 * consumes it to surface "Connection closed" rather than masquerading
 * a missing notification as a timeout.
 */
export interface NotificationBuffer {
```

### [`CONVERSATION_FAMILY_PROPERTIES`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/conversation-family.ts#L453)

*Variable*

```ts theme={null}
export const CONVERSATION_FAMILY_PROPERTIES: ReadonlyArray<
  (ctx: ConformanceRunContext) => void
> = [
  registerTaskCreate,
  registerTaskRequestReject,
  registerTaskLeave,
  registerConversationCreateAndList,
]
```

### [`ConversationActor`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L76)

*TypeAlias*

```ts theme={null}
export type ConversationActor = {
  readonly agent: TestAgent;
  readonly client: AgentTestClient;

  /**
   * Per-client historical notification buffer: `subscribe`
   * only emits frames arriving AFTER materialisation, so a sequential
   * `send → awaitOneNotification` races the response frame. The buffer
   * is fed by a long-lived
   * `subscribeAll()` pump installed at `acquireClient` time;
   * `awaitOneNotification` consumes the buffer so frames that arrived
   * between the triggering RPC and the wait are still observable. This
   * mirrors `@moltzap/server-core/test-utils → connectTestClient` (the
   * `makeNotificationBuffer` JSDoc below covers the design).
   */
  readonly notifications: NotificationBuffer;
};
```

### [`ConversationFixture`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L60)

*Interface*

```ts theme={null}
export interface ConversationFixture {
  readonly owner: ConversationActor;
  readonly participants: ReadonlyArray<ConversationActor>;
  readonly taskId: TaskId;
  readonly conversationId: ConversationId;

  /**
   * The app-principal `AppConnection` bound as the conversation's
   * moderator. App-admin RPCs (archive, unarchive, addParticipant,
   * removeParticipant, close) head their `requires` with `AppPrincipal`, so
   * they route through THIS client, not the agent `owner`. `owner` (an agent)
   * drives `agent/task/request` + `agent/message/send`.
   */
  readonly moderatorClient: AppTestClient;
}
```

### [`DELIVERY_CATEGORY`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L55)

*Variable*

```ts theme={null}
export const DELIVERY_CATEGORY = "delivery" as const
```

### [`DELIVERY_DEFAULT_PROPERTY_NUM_RUNS`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L57)

*Variable*

```ts theme={null}
export const DELIVERY_DEFAULT_PROPERTY_NUM_RUNS = 3
```

### [`DELIVERY_DEFAULT_TIMEOUT_MS`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L56)

*Variable*

```ts theme={null}
export const DELIVERY_DEFAULT_TIMEOUT_MS = 5000
```

### [`deliveryViolation`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L227)

*Function*

```ts theme={null}
export function deliveryViolation(
  name: string,
  reason: string,
): PropertyInvariantViolation
```

### [`firstParticipant`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L293)

*Function*

```ts theme={null}
export function firstParticipant(
  fixture: ConversationFixture,
  propertyName: string,
): Effect.Effect<ConversationActor, PropertyInvariantViolation>
```

### [`fixtureN`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L279)

*Function*

```ts theme={null}
export function fixtureN(requested: number): number
```

### [`moderateAs`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L714)

*Function*

```ts theme={null}
export function moderateAs(
  ctx: ConformanceRunContext,
  owner: ConversationActor,
  namePrefix: string,
): Effect.Effect<ModeratedHandle, string, Scope.Scope>
```

Wire a SEPARATE app principal as moderator: HTTP-register the manifest

* `appKey`-Connect an `AppTestClient` whose implicit registration binds it
  as the app's moderator endpoint. The grant-all `DispatchAuthorize` +
  accept `TaskCreate` + forward-all `MessagesAuthorize` callbacks run on
  THAT app connection (all are server-initiated, app-principal
  round-trips). The agent `owner` drives `agent/task/request` + `agent/message/send`.

Participant tracking stays on `owner.client` (an agent + conversation
participant): the `app/conversation/created` + participants/added/removed
notifications are agent broadcasts that CANNOT reach an `AppConnection`.
The shared in-process `participantsRef` bridges the owner's subscriber to
the app's forward-all callback.

### [`ModeratedHandle`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L678)

*Interface*

```ts theme={null}
export interface ModeratedHandle {
  readonly appId: Schema.Schema.Type<typeof AppIdSchema>;

  /**
   * The app-principal `AppConnection` bound as moderator. App-admin RPCs (their
   * `requires` head is `AppPrincipal`) route through this client.
   */
  readonly client: AppTestClient;

  /**
   * Block until the moderator has observed `expectedAgentIds` as
   * participants of `conversationId` via
   * `app/conversation/updateed` notifications. Bridges
   * the gap between the create RPC returning and the notification
   * arriving on the moderator's subscriber.
   */
  readonly awaitConversationReady: (
    conversationId: ConversationId,
    expectedAgentIds: ReadonlyArray<Schema.Schema.Type<typeof AgentId>>,
  ) => Effect.Effect<void, string>;
}
```

### [`NotificationBuffer`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L107)

*Interface*

```ts theme={null}
export interface NotificationBuffer {
  readonly snapshot: Ref.Ref<
    ReadonlyArray<NotificationDelivery<AnyNotificationDefinition>>
  >;
  readonly closed: Ref.Ref<boolean>;
}
```

Historical notification buffer used by `awaitOneNotification`. Holds
every inbound notification arriving on a single client's
`subscribeAll()` Stream until a consumer pulls a matching frame.

The `snapshot` and `closed` fields are the only public surfaces;
the pump fiber that feeds them is interrupted by the enclosing
Scope finalizer installed by `makeNotificationBuffer`. `closed` is
set to true when the transport-side stream terminates (either via
`TransportClosedError` or normal exhaustion); `awaitOneNotification`
consumes it to surface "Connection closed" rather than masquerading
a missing notification as a timeout.

### [`notifications`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L91)

*Property*

```ts theme={null}
  readonly notifications: NotificationBuffer;
};

/**
 * Historical notification buffer used by `awaitOneNotification`. Holds
 * every inbound notification arriving on a single client's
 * `subscribeAll()` Stream until a consumer pulls a matching frame.
 *
 * The `snapshot` and `closed` fields are the only public surfaces;
 * the pump fiber that feeds them is interrupted by the enclosing
 * Scope finalizer installed by `makeNotificationBuffer`. `closed` is
 * set to true when the transport-side stream terminates (either via
 * `TransportClosedError` or normal exhaustion); `awaitOneNotification`
 * consumes it to surface "Connection closed" rather than masquerading
 * a missing notification as a timeout.
 */
export interface NotificationBuffer {
```

Per-client historical notification buffer: `subscribe`
only emits frames arriving AFTER materialisation, so a sequential
`send → awaitOneNotification` races the response frame. The buffer
is fed by a long-lived
`subscribeAll()` pump installed at `acquireClient` time;
`awaitOneNotification` consumes the buffer so frames that arrived
between the triggering RPC and the wait are still observable. This
mirrors `@moltzap/server-core/test-utils → connectTestClient` (the
`makeNotificationBuffer` JSDoc below covers the design).

### [`registerArchiveLifecycle`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/archive-lifecycle.ts#L30)

*Function*

```ts theme={null}
export function registerArchiveLifecycle(ctx: ConformanceRunContext): void
```

### [`registerConversationCreateAndList`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/conversation-family.ts#L407)

*Function*

```ts theme={null}
export function registerConversationCreateAndList(
  ctx: ConformanceRunContext,
): void
```

### [`registerConversationLifecycle`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/conversation-lifecycle.ts#L34)

*Function*

```ts theme={null}
export function registerConversationLifecycle(
  ctx: ConformanceRunContext,
): void
```

### [`registerFanOutCardinality`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/fan-out-cardinality.ts#L28)

*Function*

```ts theme={null}
export function registerFanOutCardinality(ctx: ConformanceRunContext): void
```

### [`registerPayloadOpacity`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/payload-opacity.ts#L21)

*Function*

```ts theme={null}
export function registerPayloadOpacity(ctx: ConformanceRunContext): void
```

### [`registerStoreAndReplay`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/store-and-replay.ts#L31)

*Function*

```ts theme={null}
export function registerStoreAndReplay(ctx: ConformanceRunContext): void
```

### [`registerTaskBoundaryIsolation`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/task-boundary-isolation.ts#L56)

*Function*

```ts theme={null}
export function registerTaskBoundaryIsolation(
  ctx: ConformanceRunContext,
): void
```

### [`registerTaskCloseLifecycle`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/task-close-lifecycle.ts#L35)

*Function*

```ts theme={null}
export function registerTaskCloseLifecycle(ctx: ConformanceRunContext): void
```

### [`registerTaskCreate`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/conversation-family.ts#L127)

*Function*

```ts theme={null}
export function registerTaskCreate(ctx: ConformanceRunContext): void
```

### [`registerTaskLeave`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/conversation-family.ts#L327)

*Function*

```ts theme={null}
export function registerTaskLeave(ctx: ConformanceRunContext): void
```

### [`registerTaskRequestReject`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/conversation-family.ts#L265)

*Function*

```ts theme={null}
export function registerTaskRequestReject(ctx: ConformanceRunContext): void
```

### [`sendText`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L305)

*Function*

```ts theme={null}
export function sendText(
  actor: ConversationActor,
  taskId: TaskId,
  conversationId: ConversationId,
  text: string,
)
```

### [`TASK_PROPERTIES`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/index.ts#L51)

*Variable*

```ts theme={null}
export const TASK_PROPERTIES: ReadonlyArray<
  (ctx: ConformanceRunContext) => void
> = [
  registerFanOutCardinality,
  registerStoreAndReplay,
  registerPayloadOpacity,
  registerTaskBoundaryIsolation,
  registerConversationLifecycle,
  registerTaskCloseLifecycle,
  registerArchiveLifecycle,
  ...CONVERSATION_FAMILY_PROPERTIES,
]
```

All task-layer property registrars: delivery subset first, then the
`app/conversation/*` family.

### [`unarchiveConversation`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L333)

*Function*

```ts theme={null}
export function unarchiveConversation(
  moderatorClient: AppTestClient,
  taskId: TaskId,
  conversationId: ConversationId,
)
```

### [`waitForArchivedEvent`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L397)

*Function*

```ts theme={null}
export function waitForArchivedEvent(
  observer: ConversationActor,
  conversationId: ConversationId,
  _byAgentId: AgentId,
  propertyName: string,
): Effect.Effect<void, PropertyInvariantViolation>
```

### [`waitForConversationCreatedNotification`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L345)

*Function*

```ts theme={null}
export function waitForConversationCreatedNotification(
  observer: ConversationActor,
  conversationId: ConversationId,
  propertyName: string,
): Effect.Effect<void, PropertyInvariantViolation>
```

### [`waitForMessageReceivedNotification`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L371)

*Function*

```ts theme={null}
export function waitForMessageReceivedNotification(
  observer: ConversationActor,
  conversationId: ConversationId,
  propertyName: string,
): Effect.Effect<void, PropertyInvariantViolation>
```

### [`waitForUnarchivedEvent`](https://github.com/chughtapan/moltzap/blob/main/packages/protocol/src/testing/conformance/task/_helpers.ts#L427)

*Function*

```ts theme={null}
export function waitForUnarchivedEvent(
  observer: ConversationActor,
  conversationId: ConversationId,
  _byAgentId: AgentId,
  propertyName: string,
): Effect.Effect<void, PropertyInvariantViolation>
```

## Files

* `_helpers.ts`
* `archive-lifecycle.ts`
* `conversation-family.ts`
* `conversation-lifecycle.ts`
* `fan-out-cardinality.ts`
* `index.ts`
* `payload-opacity.ts`
* `store-and-replay.ts`
* `task-boundary-isolation.ts`
* `task-close-lifecycle.ts`
