import { act } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { createFakeChatSocket, type EmittedEvent } from './test-support/fake-chat-socket';
import {
  MAX_COMMAND_RESULTS,
  MAX_EXECUTED_APPROVAL_IDS,
  MAX_MANIFEST_ITEMS,
  MAX_MESSAGES,
  MAX_STREAM_CHARS,
  MAX_TOOLS,
} from './limits';

const { getSocketMock, destroySocketMock } = vi.hoisted(() => ({
  getSocketMock: vi.fn(),
  destroySocketMock: vi.fn(),
}));

vi.mock('@/lib/socket', () => ({
  getSocket: getSocketMock,
  destroySocket: destroySocketMock,
}));

import type { ChatSendProtocol, HarnessSelection } from '@mosaicstack/types';
import { useChatConnection, type ChatConnectionValue } from './use-chat-connection';

let fake: ReturnType<typeof createFakeChatSocket>;
let latest: ChatConnectionValue | null;
let root: Root | null;
let container: HTMLElement | null;

function Harness(): null {
  latest = useChatConnection();
  return null;
}

/**
 * Task Five, Step Two (web send path) red-first support. These probe the FUTURE
 * pi-rpc send contract against the CURRENT implementation, so the desired API is
 * expressed here as a localized cast — production types stay untouched until Step
 * Three. The reds fail on behaviour (legacy `message` emitted instead of
 * `turn:send`; no nested selection; no idempotency key; void return; no
 * conversation-id gating), never on a missing module or type.
 */
interface HarnessTurnSendInput {
  readonly content: string;
  readonly selection: HarnessSelection;
}
type HarnessSendMessage = (input: HarnessTurnSendInput) => boolean;

function harnessSend(): HarnessSendMessage {
  return latest?.actions.sendMessage as unknown as HarnessSendMessage;
}

/**
 * Task Five MAJOR-1 (browser send-protocol negotiation) support. The Gateway
 * advertises how this connection may send via a server-to-client-only
 * `chat:send-capability` (already part of the typed `ServerToClientEvents`
 * contract, so this uses the fake's typed `serverEmit` — no cast); the hook
 * holds the advertised protocol and routes `sendMessage` through an exhaustive
 * switch on it, never inferring it from conversation/selection. When no listener
 * is registered yet (CURRENT impl), the emit is an inert no-op, so the reds
 * below fail on BEHAVIOUR — the current send path still infers a protocol and
 * emits regardless of any advertisement — not on a missing module or type.
 */
function advertiseCapability(protocol: ChatSendProtocol, connectionId: string): void {
  fake.serverEmit('chat:send-capability', { protocol, connectionId });
}

/**
 * Install a controllable `crypto.randomUUID` on the global crypto object and
 * return a restore fn. Uses defineProperty on the instance so it works whether
 * or not the native method is configurable (it lives on the prototype, so an own
 * property simply shadows it).
 */
function installRandomUUID(fn: () => string): () => void {
  const g = globalThis as { crypto?: { randomUUID?: () => string } };
  if (!g.crypto) {
    Object.defineProperty(g, 'crypto', { configurable: true, writable: true, value: {} });
  }
  const cryptoObj = g.crypto as { randomUUID?: () => string };
  const original = Object.getOwnPropertyDescriptor(cryptoObj, 'randomUUID');
  Object.defineProperty(cryptoObj, 'randomUUID', {
    configurable: true,
    writable: true,
    value: fn,
  });
  return () => {
    if (original) {
      Object.defineProperty(cryptoObj, 'randomUUID', original);
    } else {
      Reflect.deleteProperty(cryptoObj, 'randomUUID');
    }
  };
}

/**
 * Force `crypto.randomUUID` to read as ABSENT by shadowing it with an own
 * `undefined` property. The native method lives on `Crypto.prototype`, so a
 * bare delete of the (non-existent) own property would leave the inherited
 * method visible — the shadow is what actually makes the call site see no
 * secure generator. Returns a restore fn.
 */
function removeRandomUUID(): () => void {
  const g = globalThis as { crypto?: { randomUUID?: () => string } };
  if (!g.crypto) {
    Object.defineProperty(g, 'crypto', { configurable: true, writable: true, value: {} });
  }
  const cryptoObj = g.crypto as { randomUUID?: () => string };
  const original = Object.getOwnPropertyDescriptor(cryptoObj, 'randomUUID');
  Object.defineProperty(cryptoObj, 'randomUUID', {
    configurable: true,
    writable: true,
    value: undefined,
  });
  return () => {
    if (original) {
      Object.defineProperty(cryptoObj, 'randomUUID', original);
    } else {
      Reflect.deleteProperty(cryptoObj, 'randomUUID');
    }
  };
}

/**
 * Task Five, Step Two group 4/5 support — the FUTURE `turn:ack` receipt surface
 * and the FUTURE fixed idempotency/rejection notice, expressed as a localized
 * read-only view over `state`. Production `ChatConnectionState` gains
 * `turnReceipt` at Step Three; the cast keeps production types untouched until
 * then, so a success assertion against it fails on BEHAVIOUR (no turn:ack
 * handler runs), never on a missing module. `error` already exists on state.
 */
interface HarnessTurnReceiptView {
  readonly idempotencyKey: string;
  readonly receiptId: string;
  readonly selection: HarnessSelection;
}
interface HarnessTurnStateView {
  readonly turnReceipt: HarnessTurnReceiptView | null | undefined;
  readonly error: string | null;
}
function harnessTurnState(): HarnessTurnStateView {
  return latest?.state as unknown as HarnessTurnStateView;
}

/**
 * Emit a server `turn:ack` the CURRENT hook has no listener for — a safe no-op
 * today (the fake iterates an empty handler set), so the group-4 reds fail
 * because nothing is surfaced, not because this throws. The event name is cast
 * past the compile-time `ServerToClientEvents` contract exactly as the
 * `turn:send` client cast is; the typed event map lands at Step Three.
 */
function serverEmitTurnAck(payload: unknown): void {
  fake.serverEmitRaw('turn:ack' as unknown as Parameters<typeof fake.serverEmitRaw>[0], payload);
}

beforeAll(() => {
  Object.defineProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT', {
    configurable: true,
    value: true,
  });
});

afterAll(() => {
  Reflect.deleteProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT');
});

beforeEach(async () => {
  fake = createFakeChatSocket();
  getSocketMock.mockReset().mockReturnValue(fake.socket);
  destroySocketMock.mockReset();
  latest = null;
  container = document.createElement('div');
  document.body.append(container);
  root = createRoot(container);
  await act(async () => {
    root?.render(<Harness />);
  });
});

afterEach(async () => {
  await act(async () => {
    root?.unmount();
  });
  document.body.replaceChildren();
  root = null;
  container = null;
});

describe('useChatConnection', () => {
  // Task Five MAJOR-1: the send path is PROTOCOL-driven — `sendMessage` routes
  // only on the negotiated `chat:send-capability`, never on inferred
  // conversation/selection state. These pre-existing cases exercise the legacy
  // `message` branch, so the connection is advertised `legacy-message` once here
  // (server-to-client, for this exact socket id) after the mount registers its
  // listener. Sub-describes that need the pi turn-runtime reset the generation
  // and re-advertise `turn-send`; the capability describe resets to the
  // unadvertised `unavailable` baseline and drives the protocol itself.
  beforeEach(async () => {
    await act(async () => {
      advertiseCapability('legacy-message', fake.socket.id);
    });
  });

  it('establishes the active conversation from the first message:ack when message omitted conversationId', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    expect(latest?.state.conversationId).toBe('c1');
    expect(latest?.state.ack).toEqual({ conversationId: 'c1', messageId: 'm1' });
  });

  it('ignores a message:ack for a different conversation once one is already active', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c2', messageId: 'm2' });
    });

    expect(latest?.state.conversationId).toBe('c1');
    expect(latest?.state.ack).toEqual({ conversationId: 'c1', messageId: 'm1' });
  });

  it('accumulates streamed agent:text chunks in order for the active conversation', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    await act(async () => {
      fake.serverEmit('agent:text', { conversationId: 'c1', text: 'Hel' });
      fake.serverEmit('agent:text', { conversationId: 'c1', text: 'lo' });
    });

    expect(latest?.state.streaming).toBe(true);
    expect(latest?.state.text).toBe('Hello');
  });

  it('filters out agent:text events for a conversation that is not active', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:text', { conversationId: 'c1', text: 'Hi' });
    });
    await act(async () => {
      fake.serverEmit('agent:text', { conversationId: 'other', text: 'nope' });
    });

    expect(latest?.state.text).toBe('Hi');
  });

  it('accumulates streamed agent:thinking text for the active conversation', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    await act(async () => {
      fake.serverEmit('agent:thinking', { conversationId: 'c1', text: 'step one. ' });
      fake.serverEmit('agent:thinking', { conversationId: 'c1', text: 'step two.' });
    });

    expect(latest?.state.thinking).toBe('step one. step two.');
  });

  it('tracks a tool call from start through a successful end', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    await act(async () => {
      fake.serverEmit('agent:tool:start', {
        conversationId: 'c1',
        toolCallId: 't1',
        toolName: 'search',
      });
    });
    expect(latest?.state.tools).toEqual([
      { toolCallId: 't1', toolName: 'search', status: 'running' },
    ]);

    await act(async () => {
      fake.serverEmit('agent:tool:end', {
        conversationId: 'c1',
        toolCallId: 't1',
        toolName: 'search',
        isError: false,
      });
    });
    expect(latest?.state.tools).toEqual([
      { toolCallId: 't1', toolName: 'search', status: 'success' },
    ]);
  });

  it('tracks a tool call that ends in error', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:tool:start', {
        conversationId: 'c1',
        toolCallId: 't1',
        toolName: 'shell',
      });
    });
    await act(async () => {
      fake.serverEmit('agent:tool:end', {
        conversationId: 'c1',
        toolCallId: 't1',
        toolName: 'shell',
        isError: true,
      });
    });

    expect(latest?.state.tools).toEqual([{ toolCallId: 't1', toolName: 'shell', status: 'error' }]);
  });

  it('finalizes the streamed response into the transcript and captures usage on agent:end', async () => {
    const usage = {
      provider: 'anthropic',
      modelId: 'claude',
      thinkingLevel: 'medium',
      tokens: { input: 10, output: 20, cacheRead: 0, cacheWrite: 0, total: 30 },
      cost: 0.01,
      context: { percent: 5, window: 200000 },
    };
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:text', { conversationId: 'c1', text: 'Hello there' });
    });
    await act(async () => {
      fake.serverEmit('agent:end', { conversationId: 'c1', usage });
    });

    expect(latest?.state.streaming).toBe(false);
    expect(latest?.state.text).toBe('');
    expect(latest?.state.usage).toEqual(usage);
    expect(latest?.state.messages.at(-1)).toMatchObject({ role: 'assistant', text: 'Hello there' });
  });

  it('records session:info including thinking controls and routing decision', async () => {
    const sessionInfo = {
      conversationId: 'c1',
      provider: 'anthropic',
      modelId: 'claude',
      thinkingLevel: 'medium',
      availableThinkingLevels: ['low', 'medium', 'high'],
      routingDecision: {
        model: 'claude',
        provider: 'anthropic',
        ruleName: 'default',
        reason: 'default route',
      },
    };
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      fake.serverEmit('session:info', sessionInfo);
    });

    expect(latest?.state.sessionInfo).toEqual(sessionInfo);
  });

  it('records the commands manifest regardless of active conversation', async () => {
    const manifest = {
      commands: [],
      skills: [],
      version: 1,
    };
    await act(async () => {
      fake.serverEmit('commands:manifest', { manifest });
    });

    expect(latest?.state.manifest).toEqual(manifest);
  });

  it('records a system:reload broadcast regardless of active conversation', async () => {
    const reload = {
      commands: [],
      skills: [],
      providers: ['anthropic'],
      message: 'Commands reloaded',
    };
    await act(async () => {
      fake.serverEmit('system:reload', reload);
    });

    expect(latest?.state.systemReload).toEqual(reload);
  });

  it('surfaces an error for the active conversation and filters one for another conversation', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      fake.serverEmit('error', { conversationId: 'other', error: 'ignored' });
    });
    expect(latest?.state.error).toBe(null);

    await act(async () => {
      fake.serverEmit('error', { conversationId: 'c1', error: 'boom' });
    });
    expect(latest?.state.error).toBe('boom');
  });

  it('records a failed command:result for the active conversation', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      fake.serverEmit('command:result', {
        conversationId: 'c1',
        command: 'model',
        success: false,
        message: 'unknown model',
      });
    });

    expect(latest?.state.commandResults).toEqual([
      { conversationId: 'c1', command: 'model', success: false, message: 'unknown model' },
    ]);
  });

  it('bounds an oversized command:result message to a fixed cap before it ever reaches state', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    const hostileMessage = 'x'.repeat(50_000);
    await act(async () => {
      fake.serverEmit('command:result', {
        conversationId: 'c1',
        command: 'model',
        success: false,
        message: hostileMessage,
      });
    });

    const stored = latest?.state.commandResults.at(-1)?.message ?? '';
    expect(stored.length).toBeLessThan(hostileMessage.length);
    expect(stored.length).toBeLessThanOrEqual(1000);
  });

  it('pairs a successful command:approval with the pending request so it can be run with its approvalId', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
    });

    expect(fake.emitted).toContainEqual({
      event: 'command:approve',
      payload: { conversationId: 'c1', command: 'deploy', args: 'prod' },
    });

    await act(async () => {
      fake.serverEmit('command:approval', {
        conversationId: 'c1',
        command: 'deploy',
        success: true,
        approvalId: 'ap1',
        expiresAt: '2026-01-01T00:00:00.000Z',
      });
    });

    expect(latest?.state.approval?.approvalId).toBe('ap1');

    await act(async () => {
      latest?.actions.runApprovedCommand();
    });

    expect(fake.emitted).toContainEqual({
      event: 'command:execute',
      payload: { conversationId: 'c1', command: 'deploy', args: 'prod', approvalId: 'ap1' },
    });
  });

  it('sendMessage emits optional conversationId/provider/modelId and appends an optimistic user turn', async () => {
    await act(async () => {
      latest?.actions.sendMessage({
        content: 'hello',
        selection: { harnessId: 'pi', providerId: 'anthropic', modelId: 'claude' },
      });
    });

    expect(fake.emitted).toContainEqual({
      event: 'message',
      payload: {
        conversationId: undefined,
        content: 'hello',
        provider: 'anthropic',
        modelId: 'claude',
      },
    });
    expect(latest?.state.messages.at(-1)).toMatchObject({ role: 'user', text: 'hello' });
  });

  it('sendMessage includes the active conversationId once established', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.sendMessage({ content: 'again' });
    });

    expect(fake.emitted).toContainEqual({
      event: 'message',
      payload: { conversationId: 'c1', content: 'again', provider: undefined, modelId: undefined },
    });
  });

  describe('turn:send harness routing (Task Five, Step Two red-first)', () => {
    const selection: HarnessSelection = {
      harnessId: 'pi',
      providerId: 'anthropic',
      modelId: 'claude',
    };
    const UUID = 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa';

    // The pi turn-runtime routes sends through `turn:send`. Reset the generation
    // (clearing the outer `legacy-message` advertisement + first-wins lock) and
    // advertise `turn-send` for this exact connection, so every send below takes
    // the turn-runtime branch.
    beforeEach(async () => {
      await act(async () => {
        fake.simulateReconnect();
      });
      await act(async () => {
        advertiseCapability('turn-send', fake.socket.id);
      });
    });

    async function establishConversation(): Promise<void> {
      await act(async () => {
        fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      });
    }

    it('emits a single turn:send with the nested selection tuple and a UUID idempotencyKey — never the legacy message event', async () => {
      const restore = installRandomUUID(() => UUID);
      try {
        await establishConversation();
        await act(async () => {
          harnessSend()({ content: 'hello', selection });
        });
      } finally {
        restore();
      }

      const sends = fake.emitted.filter((e) => e.event === 'turn:send');
      expect(sends).toHaveLength(1);
      expect(sends[0]?.payload).toEqual({
        conversationId: 'c1',
        content: 'hello',
        selection,
        idempotencyKey: UUID,
      });
      // The pi-rpc sender must not fall back to the embedded `message` event.
      expect(fake.emitted.some((e) => e.event === 'message')).toBe(false);
    });

    it('generates the idempotencyKey with exactly one crypto.randomUUID() call per accepted send', async () => {
      const gen = vi.fn(() => UUID);
      const restore = installRandomUUID(gen);
      try {
        await establishConversation();
        await act(async () => {
          harnessSend()({ content: 'first', selection });
        });
        await act(async () => {
          harnessSend()({ content: 'second', selection });
        });
      } finally {
        restore();
      }

      expect(gen).toHaveBeenCalledTimes(2);
      const keys = fake.emitted
        .filter((e) => e.event === 'turn:send')
        .map((e) => (e.payload as { idempotencyKey: string }).idempotencyKey);
      expect(keys).toEqual([UUID, UUID]);
    });

    it('does not send before an active conversation id exists (no first-send auto-create)', async () => {
      const restore = installRandomUUID(() => UUID);
      let returned: boolean | undefined;
      try {
        await act(async () => {
          returned = harnessSend()({ content: 'too early', selection });
        });
      } finally {
        restore();
      }

      expect(returned).toBe(false);
      expect(fake.emitted.some((e) => e.event === 'turn:send')).toBe(false);
      expect(fake.emitted.some((e) => e.event === 'message')).toBe(false);
      // Nothing optimistically appended when the send is refused.
      expect(latest?.state.messages.some((m) => m.text === 'too early')).toBe(false);
    });

    it('returns true when it emits and false when the send is refused', async () => {
      const restore = installRandomUUID(() => UUID);
      let refusedEarly: boolean | undefined;
      let acceptedAfter: boolean | undefined;
      try {
        await act(async () => {
          refusedEarly = harnessSend()({ content: 'early', selection });
        });
        await establishConversation();
        await act(async () => {
          acceptedAfter = harnessSend()({ content: 'now', selection });
        });
      } finally {
        restore();
      }

      expect(refusedEarly).toBe(false);
      expect(acceptedAfter).toBe(true);
    });

    it('when secure UUID generation throws: emits nothing, appends nothing, releases the lock, and a later send succeeds', async () => {
      await establishConversation();

      const failing = installRandomUUID(() => {
        throw new Error('secure random unavailable');
      });
      let firstReturn: boolean | undefined;
      try {
        await act(async () => {
          firstReturn = harnessSend()({ content: 'blocked', selection });
        });
      } finally {
        failing();
      }

      expect(firstReturn).toBe(false);
      expect(fake.emitted.some((e) => e.event === 'turn:send')).toBe(false);
      expect(latest?.state.messages.some((m) => m.text === 'blocked')).toBe(false);

      // The send lock must have been released, so a subsequent valid send works.
      const restore = installRandomUUID(() => UUID);
      let secondReturn: boolean | undefined;
      try {
        await act(async () => {
          secondReturn = harnessSend()({ content: 'retry', selection });
        });
      } finally {
        restore();
      }

      expect(secondReturn).toBe(true);
      expect(fake.emitted.some((e) => e.event === 'turn:send')).toBe(true);
    });
  });

  describe('turn:ack receipt + rejection contract (Task Five, Step Two group 4)', () => {
    const selection: HarnessSelection = {
      harnessId: 'pi',
      providerId: 'anthropic',
      modelId: 'claude',
    };
    const UUID = 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa';

    // turn:ack is the receipt for a `turn:send`, so these establish under the pi
    // turn-runtime: reset the generation (clearing the outer `legacy-message`
    // advertisement + lock) and advertise `turn-send` for this connection.
    beforeEach(async () => {
      await act(async () => {
        fake.simulateReconnect();
      });
      await act(async () => {
        advertiseCapability('turn-send', fake.socket.id);
      });
    });

    // Establish the conversation and send one accepted turn under a controlled
    // idempotency key. Returns the crypto restore fn so callers unwind it.
    async function establishAndSend(): Promise<() => void> {
      const restore = installRandomUUID(() => UUID);
      await act(async () => {
        fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      });
      await act(async () => {
        harnessSend()({ content: 'hello', selection });
      });
      return restore;
    }

    it('surfaces a turn:ack receipt echoing the exact idempotencyKey, server receiptId, and requested selection tuple', async () => {
      const restore = await establishAndSend();
      try {
        await act(async () => {
          serverEmitTurnAck({
            conversationId: 'c1',
            idempotencyKey: UUID,
            receiptId: 'r1',
            selection,
          });
        });
      } finally {
        restore();
      }

      // RED anchor: no turn:ack handler exists, so nothing is recorded. Green
      // only when Step Three echoes the exact tuple back into state — never a
      // substituted or fabricated one.
      expect(harnessTurnState().turnReceipt).toEqual({
        idempotencyKey: UUID,
        receiptId: 'r1',
        selection,
      });
    });

    it('on a rejected turn:ack surfaces a visible safe notice, never the raw internal error, and fabricates no receipt tuple', async () => {
      const restore = await establishAndSend();
      try {
        await act(async () => {
          serverEmitTurnAck({
            conversationId: 'c1',
            idempotencyKey: UUID,
            ok: false,
            code: 'runtime_unsupported',
            error: 'ADAPTER_BOOM internal stack: pi adapter unavailable at 0xdeadbeef',
          });
        });
      } finally {
        restore();
      }

      // RED anchor: a rejected ack must surface a visible notice; today no
      // handler runs, so state.error stays null.
      expect(harnessTurnState().error).toBeTruthy();
      // The raw internal exception text must never reach the browser surface.
      expect(harnessTurnState().error ?? '').not.toContain('ADAPTER_BOOM');
      expect(harnessTurnState().error ?? '').not.toContain('0xdeadbeef');
      // A rejection must not fabricate a success receipt tuple.
      expect(harnessTurnState().turnReceipt ?? null).toBeNull();
    });

    it('uses one fixed safe rejection notice regardless of the internal cause (frozen union, not a passthrough)', async () => {
      const firstRestore = await establishAndSend();
      try {
        await act(async () => {
          serverEmitTurnAck({
            conversationId: 'c1',
            idempotencyKey: UUID,
            ok: false,
            code: 'runtime_unsupported',
            error: 'cause-ALPHA adapter_unavailable',
          });
        });
      } finally {
        firstRestore();
      }
      const firstNotice = harnessTurnState().error;

      // A fresh turn on the same conversation, rejected for a DIFFERENT internal
      // reason, must surface the identical fixed notice.
      const secondRestore = installRandomUUID(() => UUID);
      try {
        await act(async () => {
          harnessSend()({ content: 'again', selection });
        });
        await act(async () => {
          serverEmitTurnAck({
            conversationId: 'c1',
            idempotencyKey: UUID,
            ok: false,
            code: 'runtime_unsupported',
            error: 'cause-BRAVO conversation_service_unavailable',
          });
        });
      } finally {
        secondRestore();
      }
      const secondNotice = harnessTurnState().error;

      // RED anchor: both are null today; green requires a single frozen safe
      // string surfaced for both distinct internal causes.
      expect(firstNotice).toBeTruthy();
      expect(secondNotice).toBeTruthy();
      expect(firstNotice).toBe(secondNotice);
      expect(firstNotice ?? '').not.toContain('ALPHA');
      expect(secondNotice ?? '').not.toContain('BRAVO');
    });
  });

  describe('idempotency-key failure semantics (Task Five, Step Two group 5)', () => {
    const selection: HarnessSelection = {
      harnessId: 'pi',
      providerId: 'anthropic',
      modelId: 'claude',
    };
    const UUID_A = '11111111-1111-4111-8111-111111111111';
    const UUID_B = '22222222-2222-4222-9222-222222222222';
    const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;

    // The idempotency key is minted only on the pi turn-runtime `turn:send`
    // branch: reset the generation (clearing the outer `legacy-message`
    // advertisement + lock) and advertise `turn-send` for this connection.
    beforeEach(async () => {
      await act(async () => {
        fake.simulateReconnect();
      });
      await act(async () => {
        advertiseCapability('turn-send', fake.socket.id);
      });
    });

    async function establish(): Promise<void> {
      await act(async () => {
        fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      });
    }

    it('mints a DISTINCT UUID-v4 idempotencyKey for each of two accepted turns — a key is never reused across turns', async () => {
      const keys = [UUID_A, UUID_B];
      let call = 0;
      const restore = installRandomUUID(() => keys[call++] ?? UUID_A);
      try {
        await establish();
        await act(async () => {
          harnessSend()({ content: 'first', selection });
        });
        await act(async () => {
          harnessSend()({ content: 'second', selection });
        });
      } finally {
        restore();
      }

      const sent = fake.emitted
        .filter((e) => e.event === 'turn:send')
        .map((e) => (e.payload as { idempotencyKey: string }).idempotencyKey);
      // RED anchor: current sendMessage emits the legacy `message`, so no
      // turn:send keys exist at all.
      expect(sent).toHaveLength(2);
      expect(sent[0]).toMatch(UUID_V4);
      expect(sent[1]).toMatch(UUID_V4);
      expect(sent[0]).not.toBe(sent[1]);
    });

    it('when crypto.randomUUID is ABSENT: surfaces a visible fixed idempotency-unavailable notice, emits nothing, appends nothing, releases the lock synchronously, and a later valid send succeeds', async () => {
      await establish();

      const restoreCrypto = removeRandomUUID();
      let firstReturn: boolean | undefined;
      try {
        await act(async () => {
          firstReturn = harnessSend()({ content: 'no-secure-random', selection });
        });
      } finally {
        restoreCrypto();
      }

      // RED anchors: a refused send returns false and surfaces a visible notice.
      expect(firstReturn).toBe(false);
      expect(harnessTurnState().error).toBeTruthy();
      expect(fake.emitted.some((e) => e.event === 'turn:send')).toBe(false);
      expect(latest?.state.messages.some((m) => m.text === 'no-secure-random')).toBe(false);

      // The lock released synchronously (no server event needed): a later valid
      // send goes through.
      const restore = installRandomUUID(() => UUID_A);
      let secondReturn: boolean | undefined;
      try {
        await act(async () => {
          secondReturn = harnessSend()({ content: 'recovered', selection });
        });
      } finally {
        restore();
      }
      expect(secondReturn).toBe(true);
      expect(fake.emitted.some((e) => e.event === 'turn:send')).toBe(true);
    });

    it('surfaces the SAME fixed idempotency-unavailable notice whether randomUUID is absent or throws, never leaking the thrown message', async () => {
      // Case 1: absent.
      await establish();
      const restoreAbsent = removeRandomUUID();
      try {
        await act(async () => {
          harnessSend()({ content: 'absent', selection });
        });
      } finally {
        restoreAbsent();
      }
      const absentNotice = harnessTurnState().error;

      // Case 2: throws with a distinctive internal message.
      const failing = installRandomUUID(() => {
        throw new Error('SECURE_RANDOM_BOOM entropy pool drained');
      });
      try {
        await act(async () => {
          harnessSend()({ content: 'throws', selection });
        });
      } finally {
        failing();
      }
      const throwNotice = harnessTurnState().error;

      // RED anchor: both are null today.
      expect(absentNotice).toBeTruthy();
      expect(throwNotice).toBeTruthy();
      expect(absentNotice).toBe(throwNotice);
      // The thrown internal detail must never reach the browser surface.
      expect(throwNotice ?? '').not.toContain('SECURE_RANDOM_BOOM');
      expect(throwNotice ?? '').not.toContain('entropy pool');
    });
  });

  it('abort emits abort with the active conversationId', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.abort();
    });

    expect(fake.emitted).toContainEqual({ event: 'abort', payload: { conversationId: 'c1' } });
  });

  it('setThinking emits set:thinking with the requested level and active conversationId', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.setThinking('high');
    });

    expect(fake.emitted).toContainEqual({
      event: 'set:thinking',
      payload: { conversationId: 'c1', level: 'high' },
    });
  });

  it('executeCommand emits command:execute with the exact command payload', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.executeCommand({ command: 'model', args: 'gpt-5' });
    });

    expect(fake.emitted).toContainEqual({
      event: 'command:execute',
      payload: { conversationId: 'c1', command: 'model', args: 'gpt-5' },
    });
  });

  it('adopts session:info as the active conversation when it arrives before message:ack, preserving it across the later ack', async () => {
    await act(async () => {
      latest?.actions.sendMessage({ content: 'hi' });
    });
    await act(async () => {
      fake.serverEmit('session:info', {
        conversationId: 'c1',
        provider: 'anthropic',
        modelId: 'claude',
        thinkingLevel: 'medium',
        availableThinkingLevels: ['low', 'medium', 'high'],
      });
    });

    expect(latest?.state.conversationId).toBe('c1');
    expect(latest?.state.sessionInfo?.provider).toBe('anthropic');

    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    expect(latest?.state.ack).toEqual({ conversationId: 'c1', messageId: 'm1' });
    expect(latest?.state.sessionInfo?.provider).toBe('anthropic');
  });

  it('adopts a pre-ack error as the active conversation, surfaces it, and does not leave streaming stuck', async () => {
    await act(async () => {
      latest?.actions.sendMessage({ content: 'hi' });
    });
    await act(async () => {
      fake.serverEmit('error', {
        conversationId: 'c1',
        error: 'Failed to start agent session. Please try again.',
      });
    });

    expect(latest?.state.conversationId).toBe('c1');
    expect(latest?.state.error).toBe('Failed to start agent session. Please try again.');
    expect(latest?.state.streaming).toBe(false);
    expect(latest?.state.sending).toBe(false);

    await act(async () => {
      latest?.actions.sendMessage({ content: 'retry' });
    });

    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(2);
    expect(latest?.state.messages.some((m) => m.text === 'retry')).toBe(true);
  });

  it('stops streaming when a typed error arrives mid-turn', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    expect(latest?.state.streaming).toBe(true);

    await act(async () => {
      fake.serverEmit('error', { conversationId: 'c1', error: 'boom' });
    });

    expect(latest?.state.streaming).toBe(false);
  });

  it('does not append an assistant message on agent:end when there is no text or thinking', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    const before = latest?.state.messages.length ?? 0;

    await act(async () => {
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });

    expect(latest?.state.messages.length).toBe(before);
    expect(latest?.state.streaming).toBe(false);
  });

  it('ignores a second approval request while the first is still outstanding, preserving the original command and args', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
    });
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'staging' });
    });

    expect(latest?.state.pendingApproval).toEqual({ command: 'deploy', args: 'prod' });
    expect(fake.emitted.filter((e) => e.event === 'command:approve')).toHaveLength(1);

    await act(async () => {
      fake.serverEmit('command:approval', {
        conversationId: 'c1',
        command: 'deploy',
        success: true,
        approvalId: 'ap1',
        expiresAt: '2026-01-01T00:00:00.000Z',
      });
    });

    await act(async () => {
      latest?.actions.runApprovedCommand();
    });

    expect(fake.emitted).toContainEqual({
      event: 'command:execute',
      payload: { conversationId: 'c1', command: 'deploy', args: 'prod', approvalId: 'ap1' },
    });
    expect(fake.emitted.filter((e) => e.event === 'command:execute')).toHaveLength(1);
  });

  it('ignores a stale command:approval response that does not match the pending request', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
    });
    await act(async () => {
      fake.serverEmit('command:approval', {
        conversationId: 'c1',
        command: 'rollback',
        success: true,
        approvalId: 'stale',
        expiresAt: '2026-01-01T00:00:00.000Z',
      });
    });

    expect(latest?.state.approval).toBeNull();
  });

  it('emits command:execute only once even when runApprovedCommand is invoked twice back to back', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
    });
    await act(async () => {
      fake.serverEmit('command:approval', {
        conversationId: 'c1',
        command: 'deploy',
        success: true,
        approvalId: 'ap1',
        expiresAt: '2026-01-01T00:00:00.000Z',
      });
    });

    await act(async () => {
      latest?.actions.runApprovedCommand();
      latest?.actions.runApprovedCommand();
    });

    expect(fake.emitted.filter((e) => e.event === 'command:execute')).toHaveLength(1);
    expect(latest?.state.approval).toBeNull();
    expect(latest?.state.pendingApproval).toBeNull();
  });

  it('ignores sendMessage while a turn is streaming', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });

    await act(async () => {
      latest?.actions.sendMessage({ content: 'too soon' });
    });

    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(0);
    expect(latest?.state.messages.some((m) => m.text === 'too soon')).toBe(false);
  });

  it('refreshes the manifest commands from a system:reload broadcast', async () => {
    await act(async () => {
      fake.serverEmit('commands:manifest', {
        manifest: {
          commands: [
            {
              name: 'model',
              aliases: [],
              description: 'old',
              scope: 'core',
              execution: 'socket',
              available: true,
            },
          ],
          skills: [],
          version: 1,
        },
      });
    });
    await act(async () => {
      fake.serverEmit('system:reload', {
        commands: [
          {
            name: 'deploy',
            aliases: [],
            description: 'new',
            scope: 'core',
            execution: 'socket',
            available: true,
          },
        ],
        skills: [],
        providers: ['anthropic'],
        message: 'Commands reloaded',
      });
    });

    expect(latest?.state.manifest?.commands.map((c) => c.name)).toEqual(['deploy']);
  });

  it('reconnects the same socket instance after a transient disconnect and accepts a subsequent ack/start/text stream', async () => {
    await act(async () => {
      fake.simulateDisconnect();
    });

    // Listeners must still be registered — a transient disconnect must not
    // tear anything down or force a fresh singleton.
    expect(fake.listeners.get('message:ack')?.size).toBeGreaterThan(0);

    await act(async () => {
      fake.simulateReconnect();
    });
    expect(fake.socket.connected).toBe(true);

    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm2' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:text', { conversationId: 'c1', text: 'reconnected' });
    });

    expect(latest?.state.ack).toEqual({ conversationId: 'c1', messageId: 'm2' });
    expect(latest?.state.streaming).toBe(true);
    expect(latest?.state.text).toBe('reconnected');
    expect(fake.listeners.get('message:ack')?.size).toBeGreaterThan(0);
    // No new fake singleton was created — getSocket() always resolved to the
    // same instance across the disconnect/reconnect cycle.
    expect(getSocketMock.mock.results.every((result) => result.value === fake.socket)).toBe(true);
  });

  it('resets streaming and pending-send/busy state on a mid-stream disconnect', async () => {
    await act(async () => {
      latest?.actions.sendMessage({ content: 'hi' });
    });
    expect(latest?.state.sending).toBe(true);
    expect(latest?.state.pendingSend).toBe(true);

    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    expect(latest?.state.streaming).toBe(true);
    expect(latest?.state.pendingSend).toBe(false);

    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
    });
    expect(latest?.state.approvalRequestPending).toBe(true);

    await act(async () => {
      fake.simulateDisconnect();
    });

    expect(latest?.state.streaming).toBe(false);
    expect(latest?.state.sending).toBe(false);
    expect(latest?.state.pendingSend).toBe(false);
    expect(latest?.state.approvalRequestPending).toBe(false);

    // The send lock must also be released — a subsequent sendMessage after
    // reconnect must not be permanently blocked by the interrupted turn. The
    // disconnect also voids the negotiated send protocol (MAJOR-1), so model the
    // reconnect handshake — the socket reconnects and the server re-advertises
    // how this connection may send — before probing the released lock.
    await act(async () => {
      fake.simulateReconnect();
    });
    await act(async () => {
      advertiseCapability('legacy-message', fake.socket.id);
    });
    await act(async () => {
      latest?.actions.sendMessage({ content: 'after reconnect' });
    });
    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(2);
    expect(fake.emitted.filter((e) => e.event === 'message').at(-1)).toEqual({
      event: 'message',
      payload: {
        conversationId: 'c1',
        content: 'after reconnect',
        provider: undefined,
        modelId: undefined,
      },
    });
  });

  it('emits and appends only one turn when sendMessage is called twice before agent:start, and cannot fork a new conversation', async () => {
    await act(async () => {
      latest?.actions.sendMessage({ content: 'first' });
      latest?.actions.sendMessage({ content: 'second' });
    });

    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(1);
    expect(latest?.state.messages).toHaveLength(1);
    expect(latest?.state.messages[0]).toMatchObject({ role: 'user', text: 'first' });

    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    expect(latest?.state.conversationId).toBe('c1');
  });

  it('appends a terminal anomaly entry when agent:tool:end references a toolCallId that was never started', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });

    await act(async () => {
      fake.serverEmit('agent:tool:end', {
        conversationId: 'c1',
        toolCallId: 'unseen',
        toolName: 'search',
        isError: false,
      });
    });

    expect(latest?.state.tools).toEqual([
      { toolCallId: 'unseen', toolName: 'search', status: 'anomaly' },
    ]);
  });

  it('assigns unique fallback IDs to multiple malformed tool:start events, and a subsequent malformed tool:end always appends a new anomaly without mutating either prior entry', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });

    await expect(
      act(async () => {
        fake.serverEmitRaw('agent:tool:start', {
          conversationId: 'c1',
          toolCallId: { bad: 'object' },
          toolName: 'search',
        });
        fake.serverEmitRaw('agent:tool:start', {
          conversationId: 'c1',
          toolCallId: '',
          toolName: 'shell',
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.tools).toHaveLength(2);
    const [first, second] = latest?.state.tools ?? [];
    expect(first?.status).toBe('running');
    expect(second?.status).toBe('running');
    expect(first?.toolCallId).not.toBe(second?.toolCallId);

    await expect(
      act(async () => {
        fake.serverEmitRaw('agent:tool:end', {
          conversationId: 'c1',
          toolCallId: null,
          toolName: 'unknown',
          isError: false,
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.tools).toHaveLength(3);
    // Neither malformed-start entry was mutated by the malformed end.
    expect(latest?.state.tools[0]).toEqual(first);
    expect(latest?.state.tools[1]).toEqual(second);
    // The malformed end always appends its own terminal anomaly rather than
    // colliding with (and silently flipping) an earlier fallback ID.
    const terminal = latest?.state.tools[2];
    expect(terminal?.status).toBe('anomaly');
    expect(terminal?.toolCallId).not.toBe(first?.toolCallId);
    expect(terminal?.toolCallId).not.toBe(second?.toolCallId);
  });

  it('updates only the first matching tool when a tool:end references a toolCallId shared by two tool:start entries', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:tool:start', {
        conversationId: 'c1',
        toolCallId: 'dup',
        toolName: 'search',
      });
      fake.serverEmit('agent:tool:start', {
        conversationId: 'c1',
        toolCallId: 'dup',
        toolName: 'search',
      });
    });

    await act(async () => {
      fake.serverEmit('agent:tool:end', {
        conversationId: 'c1',
        toolCallId: 'dup',
        toolName: 'search',
        isError: false,
      });
    });

    expect(latest?.state.tools).toEqual([
      { toolCallId: 'dup', toolName: 'search', status: 'success' },
      { toolCallId: 'dup', toolName: 'search', status: 'running' },
    ]);
  });

  it('caps the tools list at MAX_TOOLS when flooded with tool:start events', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });

    await act(async () => {
      for (let i = 0; i < MAX_TOOLS + 10; i += 1) {
        fake.serverEmit('agent:tool:start', {
          conversationId: 'c1',
          toolCallId: `t${i}`,
          toolName: 'search',
        });
      }
    });

    expect(latest?.state.tools).toHaveLength(MAX_TOOLS);
    // Oldest dropped deterministically — the most recent tool call survives.
    expect(latest?.state.tools.at(-1)?.toolCallId).toBe(`t${MAX_TOOLS + 9}`);
  });

  it('a stale agent:end for a foreign conversation cannot re-arm the send lock for a same-tick in-flight second turn', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });

    await act(async () => {
      latest?.actions.sendMessage({ content: 'second turn' });
    });
    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(1);

    // While the second turn's send is in flight (sent but agent:start not yet
    // received), a terminal event for an unrelated conversation arrives in the
    // same tick as a follow-up send attempt — it must not re-arm the lock.
    await act(async () => {
      fake.serverEmit('agent:end', { conversationId: 'other' });
      latest?.actions.sendMessage({ content: 'third turn attempt' });
    });

    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(1);
    expect(latest?.state.messages.some((m) => m.text === 'third turn attempt')).toBe(false);
  });

  it('a stale error for a foreign conversation cannot re-arm the send lock for a same-tick in-flight second turn', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });

    await act(async () => {
      latest?.actions.sendMessage({ content: 'second turn' });
    });
    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(1);

    await act(async () => {
      fake.serverEmit('error', { conversationId: 'other', error: 'unrelated failure' });
      latest?.actions.sendMessage({ content: 'third turn attempt' });
    });

    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(1);
    expect(latest?.state.messages.some((m) => m.text === 'third turn attempt')).toBe(false);
  });

  it('does not throw and normalizes to empty lists when commands:manifest arrives with null commands/skills', async () => {
    await expect(
      act(async () => {
        fake.serverEmitRaw('commands:manifest', {
          manifest: { commands: null, skills: null, version: 1 },
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.manifest?.commands).toEqual([]);
    expect(latest?.state.manifest?.skills).toEqual([]);
  });

  it('does not throw and normalizes to empty lists when system:reload arrives with non-array commands/skills', async () => {
    await expect(
      act(async () => {
        fake.serverEmitRaw('system:reload', {
          commands: 'not-an-array',
          skills: undefined,
          providers: ['anthropic'],
          message: 'Commands reloaded',
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.manifest?.commands).toEqual([]);
    expect(latest?.state.manifest?.skills).toEqual([]);
    // The raw stored reload must be normalized the same way as the manifest —
    // never left holding the malformed raw value.
    expect(latest?.state.systemReload?.commands).toEqual([]);
    expect(latest?.state.systemReload?.skills).toEqual([]);
  });

  it('falls back to a safe tool label when agent:tool:start carries a non-string toolName', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });

    await expect(
      act(async () => {
        fake.serverEmitRaw('agent:tool:start', {
          conversationId: 'c1',
          toolCallId: 't1',
          toolName: { evil: 'object' },
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.tools).toEqual([
      { toolCallId: 't1', toolName: 'Unknown tool', status: 'running' },
    ]);
  });

  it('ignores a session:info event whose entire payload is null, without throwing', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    await expect(
      act(async () => {
        fake.serverEmitRaw('session:info', null);
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.sessionInfo).toBeNull();
  });

  it('emits only one command:approve when approveCommand is called twice in the same tick, preserving the first frozen args', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
      latest?.actions.approveCommand({ command: 'deploy', args: 'staging' });
    });

    expect(fake.emitted.filter((e) => e.event === 'command:approve')).toHaveLength(1);
    expect(latest?.state.pendingApproval).toEqual({ command: 'deploy', args: 'prod' });
  });

  it('caps streamed agent:text at MAX_STREAM_CHARS behind a visible marker disclosing the honest dropped-character count across multiple appends', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });

    const firstChunk = 'a'.repeat(MAX_STREAM_CHARS);
    const secondChunk = 'b'.repeat(500);
    const thirdChunk = 'c'.repeat(300);

    await act(async () => {
      fake.serverEmit('agent:text', { conversationId: 'c1', text: firstChunk });
    });
    await act(async () => {
      fake.serverEmit('agent:text', { conversationId: 'c1', text: secondChunk });
    });
    await act(async () => {
      fake.serverEmit('agent:text', { conversationId: 'c1', text: thirdChunk });
    });

    const text = latest?.state.text ?? '';
    expect(text.length).toBeLessThanOrEqual(MAX_STREAM_CHARS);

    const match = text.match(/^…\[truncated (\d+) characters\]…/);
    expect(match).not.toBeNull();
    const markerLength = match?.[0].length ?? 0;
    const droppedCount = Number(match?.[1]);
    const tail = text.slice(markerLength);
    const totalStreamed = firstChunk.length + secondChunk.length + thirdChunk.length;

    // The marker's N must be the actual count of original characters no
    // longer visible — not an estimate — across all three appends.
    expect(droppedCount).toBe(totalStreamed - tail.length);
    expect(tail.endsWith(thirdChunk)).toBe(true);
  });

  it('caps streamed agent:thinking at MAX_STREAM_CHARS behind the same honest truncation marker as agent:text', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });

    const firstChunk = 'x'.repeat(MAX_STREAM_CHARS);
    const secondChunk = 'y'.repeat(500);
    const thirdChunk = 'z'.repeat(300);

    await act(async () => {
      fake.serverEmit('agent:thinking', { conversationId: 'c1', text: firstChunk });
    });
    await act(async () => {
      fake.serverEmit('agent:thinking', { conversationId: 'c1', text: secondChunk });
    });
    await act(async () => {
      fake.serverEmit('agent:thinking', { conversationId: 'c1', text: thirdChunk });
    });

    const thinking = latest?.state.thinking ?? '';
    expect(thinking.length).toBeLessThanOrEqual(MAX_STREAM_CHARS);

    const match = thinking.match(/^…\[truncated (\d+) characters\]…/);
    expect(match).not.toBeNull();
    const markerLength = match?.[0].length ?? 0;
    const droppedCount = Number(match?.[1]);
    const tail = thinking.slice(markerLength);
    const totalStreamed = firstChunk.length + secondChunk.length + thirdChunk.length;

    expect(droppedCount).toBe(totalStreamed - tail.length);
    expect(tail.endsWith(thirdChunk)).toBe(true);
  });

  it('caps commandResults at MAX_COMMAND_RESULTS when flooded with command:result events', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    await act(async () => {
      for (let i = 0; i < MAX_COMMAND_RESULTS + 5; i += 1) {
        fake.serverEmit('command:result', {
          conversationId: 'c1',
          command: `cmd${i}`,
          success: true,
        });
      }
    });

    expect(latest?.state.commandResults).toHaveLength(MAX_COMMAND_RESULTS);
    expect(latest?.state.commandResults.at(-1)?.command).toBe(`cmd${MAX_COMMAND_RESULTS + 4}`);
  });

  it('caps commands:manifest commands/skills at MAX_MANIFEST_ITEMS', async () => {
    const commands = Array.from({ length: MAX_MANIFEST_ITEMS + 5 }, (_, i) => ({
      name: `cmd${i}`,
      aliases: [],
      description: '',
      scope: 'core' as const,
      execution: 'socket' as const,
      available: true,
    }));

    await act(async () => {
      fake.serverEmit('commands:manifest', { manifest: { commands, skills: [], version: 1 } });
    });

    expect(latest?.state.manifest?.commands).toHaveLength(MAX_MANIFEST_ITEMS);
  });

  it('caps a system:reload manifest replacement at MAX_MANIFEST_ITEMS for commands, skills, and providers, and drops hostile extra fields instead of spreading the raw payload into state', async () => {
    const commands = Array.from({ length: MAX_MANIFEST_ITEMS + 5 }, (_, i) => ({
      name: `cmd${i}`,
      aliases: [],
      description: '',
      scope: 'core' as const,
      execution: 'socket' as const,
      available: true,
    }));
    const skills = Array.from({ length: MAX_MANIFEST_ITEMS + 5 }, (_, i) => ({
      name: `skill${i}`,
      description: '',
      available: true,
    }));
    const providers = Array.from({ length: 550 }, (_, i) => `provider-${i}`);

    await expect(
      act(async () => {
        fake.serverEmitRaw('system:reload', {
          commands,
          skills,
          providers,
          message: 'reloaded',
          // Hostile field not part of the SystemReloadPayload contract —
          // must never survive into state.systemReload.
          maliciousExtra: 'should-not-survive',
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.manifest?.commands).toHaveLength(MAX_MANIFEST_ITEMS);
    expect(latest?.state.manifest?.skills).toHaveLength(MAX_MANIFEST_ITEMS);
    // The raw stored reload (state.systemReload) must be bounded the same
    // way as the manifest derived from it — a hostile/oversized broadcast
    // must never leave the uncapped raw payload sitting in state.
    expect(latest?.state.systemReload?.commands).toHaveLength(MAX_MANIFEST_ITEMS);
    expect(latest?.state.systemReload?.skills).toHaveLength(MAX_MANIFEST_ITEMS);
    expect(latest?.state.systemReload?.providers).toHaveLength(500);
    expect(latest?.state.systemReload).not.toHaveProperty('maliciousExtra');
  });

  it('caps availableThinkingLevels before storing a hostile session:info payload', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    const hostileLevels = Array.from({ length: MAX_MANIFEST_ITEMS + 50 }, (_, i) => `level-${i}`);

    await act(async () => {
      fake.serverEmit('session:info', {
        conversationId: 'c1',
        provider: 'anthropic',
        modelId: 'claude',
        thinkingLevel: 'level-0',
        availableThinkingLevels: hostileLevels,
      });
    });

    expect(latest?.state.sessionInfo?.availableThinkingLevels).toHaveLength(MAX_MANIFEST_ITEMS);
  });

  it('ignores a malformed (object) conversationId on the establishing message:ack, leaving the turn recoverable for a later valid ack', async () => {
    await act(async () => {
      latest?.actions.sendMessage({ content: 'hi' });
    });
    expect(latest?.state.pendingSend).toBe(true);

    await expect(
      act(async () => {
        fake.serverEmitRaw('message:ack', { conversationId: { bad: 'object' }, messageId: 'm0' });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.conversationId).toBeNull();
    expect(latest?.state.pendingSend).toBe(true);
    expect(latest?.state.ack).toBeNull();

    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    expect(latest?.state.conversationId).toBe('c1');
    expect(latest?.state.ack).toEqual({ conversationId: 'c1', messageId: 'm1' });
  });

  it('ignores an empty-string and a null conversationId on the establishing message:ack', async () => {
    await expect(
      act(async () => {
        fake.serverEmitRaw('message:ack', { conversationId: '', messageId: 'm1' });
      }),
    ).resolves.not.toThrow();
    expect(latest?.state.conversationId).toBeNull();

    await expect(
      act(async () => {
        fake.serverEmitRaw('message:ack', { conversationId: null, messageId: 'm1' });
      }),
    ).resolves.not.toThrow();
    expect(latest?.state.conversationId).toBeNull();
  });

  it('sanitizes a malformed (non-string) ack messageId to a visible "unknown" fallback instead of storing the raw value', async () => {
    await expect(
      act(async () => {
        fake.serverEmitRaw('message:ack', { conversationId: 'c1', messageId: { bad: 'object' } });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.ack).toEqual({ conversationId: 'c1', messageId: 'unknown' });
  });

  it('treats a malformed-conversationId error as a terminal startup failure for a brand-new pending send, releasing the send lock for a retry', async () => {
    await act(async () => {
      latest?.actions.sendMessage({ content: 'hi' });
    });
    expect(latest?.state.pendingSend).toBe(true);
    expect(latest?.state.sending).toBe(true);

    await expect(
      act(async () => {
        fake.serverEmitRaw('error', { conversationId: { bad: 'object' }, error: 'boom' });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.conversationId).toBeNull();
    expect(latest?.state.pendingSend).toBe(false);
    expect(latest?.state.sending).toBe(false);
    expect(latest?.state.streaming).toBe(false);
    expect(latest?.state.approvalRequestPending).toBe(false);
    expect(latest?.state.error).toBe('Unable to start this conversation. Please try again.');

    await act(async () => {
      latest?.actions.sendMessage({ content: 'retry' });
    });

    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(2);
    expect(latest?.state.messages.some((m) => m.text === 'retry')).toBe(true);
  });

  it('treats a malformed-conversationId agent:end as a terminal startup failure for a brand-new pending send, releasing the send lock for a retry', async () => {
    await act(async () => {
      latest?.actions.sendMessage({ content: 'hi' });
    });
    expect(latest?.state.pendingSend).toBe(true);

    await expect(
      act(async () => {
        fake.serverEmitRaw('agent:end', { conversationId: '' });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.conversationId).toBeNull();
    expect(latest?.state.pendingSend).toBe(false);
    expect(latest?.state.sending).toBe(false);
    expect(latest?.state.streaming).toBe(false);
    expect(latest?.state.approvalRequestPending).toBe(false);
    expect(latest?.state.error).toBe('Unable to start this conversation. Please try again.');

    await act(async () => {
      latest?.actions.sendMessage({ content: 'retry again' });
    });

    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(2);
    expect(latest?.state.messages.some((m) => m.text === 'retry again')).toBe(true);
  });

  it('a foreign valid-conversationId error after a conversation is already active remains ignored and cannot unlock anything', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    expect(latest?.state.streaming).toBe(true);

    await act(async () => {
      fake.serverEmit('error', { conversationId: 'other', error: 'unrelated' });
    });

    expect(latest?.state.conversationId).toBe('c1');
    expect(latest?.state.streaming).toBe(true);
    expect(latest?.state.error).toBeNull();
  });

  it('ignores a malformed (null) conversationId on an establishing agent:start via resolveScopedConversation, leaving the turn recoverable for a later valid one', async () => {
    await act(async () => {
      latest?.actions.sendMessage({ content: 'hi' });
    });

    await expect(
      act(async () => {
        fake.serverEmitRaw('agent:start', { conversationId: null });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.conversationId).toBeNull();
    expect(latest?.state.pendingSend).toBe(true);
    expect(latest?.state.streaming).toBe(false);

    await act(async () => {
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });

    expect(latest?.state.conversationId).toBe('c1');
    expect(latest?.state.streaming).toBe(true);
  });

  it('normalizes a command:approval with a truthy but non-literal-true success into a denial, releasing the pending lock without enabling execution', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
    });

    await expect(
      act(async () => {
        fake.serverEmitRaw('command:approval', {
          conversationId: 'c1',
          command: 'deploy',
          success: { truthy: 'object' },
          approvalId: 'ap1',
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.approval?.success).toBe(false);
    expect(latest?.state.approvalRequestPending).toBe(false);

    await act(async () => {
      latest?.actions.runApprovedCommand();
    });
    expect(fake.emitted.filter((e) => e.event === 'command:execute')).toHaveLength(0);
  });

  it('normalizes a command:approval with success: true but a malformed (object) approvalId into a denial that cannot be run', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
    });

    await expect(
      act(async () => {
        fake.serverEmitRaw('command:approval', {
          conversationId: 'c1',
          command: 'deploy',
          success: true,
          approvalId: { bad: 'object' },
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.approval?.success).toBe(false);
    expect(latest?.state.approval?.approvalId).toBeUndefined();
    expect(latest?.state.approvalRequestPending).toBe(false);

    await act(async () => {
      latest?.actions.runApprovedCommand();
    });
    expect(fake.emitted.filter((e) => e.event === 'command:execute')).toHaveLength(0);
  });

  it('normalizes command:result.success to a literal boolean, never displaying a truthy non-boolean value as success', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    await expect(
      act(async () => {
        fake.serverEmitRaw('command:result', {
          conversationId: 'c1',
          command: 'model',
          success: { truthy: 'object' },
        });
      }),
    ).resolves.not.toThrow();

    expect(latest?.state.commandResults.at(-1)?.success).toBe(false);
  });

  it('caps messages at MAX_MESSAGES when flooded with agent:start/text/end cycles on an established conversation', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    await act(async () => {
      for (let i = 0; i < MAX_MESSAGES + 5; i += 1) {
        fake.serverEmit('agent:start', { conversationId: 'c1' });
        fake.serverEmit('agent:text', { conversationId: 'c1', text: `reply ${i}` });
        fake.serverEmit('agent:end', { conversationId: 'c1' });
      }
    });

    expect(latest?.state.messages).toHaveLength(MAX_MESSAGES);
    expect(latest?.state.messages.at(-1)?.text).toBe(`reply ${MAX_MESSAGES + 4}`);
    // Every retained message.id must stay unique across the cap boundary — a
    // length-derived id would collide once the array plateaus at MAX_MESSAGES.
    const ids = latest?.state.messages.map((m) => m.id) ?? [];
    expect(new Set(ids).size).toBe(ids.length);
  });

  it('fails closed after the consumed approval cache saturates and rejects replay of the ID the old eviction policy forgot', async () => {
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
    });

    // Fill the bounded dedup set to capacity with genuinely distinct,
    // legitimately approved and executed IDs. Each step of approve/respond/
    // run gets its own `act()` so a render (and the ref-syncing effects)
    // lands between them — combining approve+respond in one act would let
    // `approvalRequestPending` flip true-then-false within a single commit,
    // skipping the render the lock-sync effect depends on.
    for (let i = 0; i < MAX_EXECUTED_APPROVAL_IDS; i += 1) {
      await act(async () => {
        latest?.actions.approveCommand({ command: 'deploy' });
      });
      await act(async () => {
        fake.serverEmit('command:approval', {
          conversationId: 'c1',
          command: 'deploy',
          success: true,
          approvalId: `ap-${i}`,
        });
      });
      await act(async () => {
        latest?.actions.runApprovedCommand();
      });
    }

    // One more distinct approval once the set is already full. The old
    // eviction policy would delete the oldest entry (ap-0) to make room and
    // let this execute; the fixed behavior must deny it instead.
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy' });
    });
    await act(async () => {
      fake.serverEmit('command:approval', {
        conversationId: 'c1',
        command: 'deploy',
        success: true,
        approvalId: 'ap-overflow',
      });
    });
    await act(async () => {
      latest?.actions.runApprovedCommand();
    });

    // The rejected 201st approval is not silently dropped — it must be
    // consumed but also surface a stable, visible notice so the user knows
    // why the command did not run. ChatPage renders state.error as
    // role="alert".
    expect(latest?.state.error).toBe(
      'Approval limit reached for this session. This command was not run.',
    );
    expect(latest?.state.approval).toBeNull();
    expect(latest?.state.pendingApproval).toBeNull();

    // A fresh local approval request, replaying the very first approvalId —
    // this is the replay the old eviction policy would have let through a
    // second time because it had forgotten ap-0 ever ran.
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy' });
    });
    await act(async () => {
      fake.serverEmit('command:approval', {
        conversationId: 'c1',
        command: 'deploy',
        success: true,
        approvalId: 'ap-0',
      });
    });
    await act(async () => {
      latest?.actions.runApprovedCommand();
    });

    const executes = fake.emitted.filter(
      (e): e is EmittedEvent<'command:execute'> => e.event === 'command:execute',
    );
    // Only the original MAX_EXECUTED_APPROVAL_IDS executions ever happened —
    // neither the overflow ID nor the replay of ap-0 produced a new one.
    expect(executes).toHaveLength(MAX_EXECUTED_APPROVAL_IDS);
    expect(executes.filter((e) => e.payload.approvalId === 'ap-0')).toHaveLength(1);
    expect(executes.some((e) => e.payload.approvalId === 'ap-overflow')).toBe(false);
  });

  it('does not unlock turn B when a stale same-conversation agent:end from turn A arrives', async () => {
    // Turn A completes normally on c1.
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });
    expect(latest?.state.sending).toBe(false);

    // Turn B is sent (same conversation — the wire gives it no distinct
    // turn id, only the same conversationId as turn A).
    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn B' });
    });
    expect(latest?.state.sending).toBe(true);

    // Turn A's agent:end arrives late (network reordering) for the SAME
    // conversation, before turn B's own ack/start ever arrived. A
    // conversationId-only check cannot tell this apart from turn B's own
    // terminal event, so this must not unlock — turn B has not yet been
    // armed by its own accepted ack/start.
    await act(async () => {
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });
    expect(latest?.state.sending).toBe(true);
    // A recognized-stale terminal must be a true no-op — it must not touch
    // streaming/error, which legitimately belong to the still in-flight
    // turn B.
    expect(latest?.state.streaming).toBe(false);
    expect(latest?.state.error).toBeNull();

    // An attempted turn C must still be rejected — the lock is still held.
    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn C attempt' });
    });
    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(1);
    expect(latest?.state.messages.some((m) => m.text === 'turn C attempt')).toBe(false);

    // Turn B's own, current ack/start arms the lock, and its own terminal
    // event can then legitimately release it, allowing a later send.
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm2' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    await act(async () => {
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });
    expect(latest?.state.sending).toBe(false);

    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn D' });
    });
    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(2);
  });

  it('settles turn B and releases its lock when a pre-ack error arrives on an already-established conversation, allowing a later send', async () => {
    // Turn A completes normally on c1.
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });
    expect(latest?.state.sending).toBe(false);

    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn B' });
    });
    expect(latest?.state.sending).toBe(true);

    // A same-conversation error arrives before turn B's own ack/start. Once
    // turn A has already fully settled via its own terminal event, ordered
    // Socket.IO delivery means this cannot be a leftover of A — the Gateway
    // has nothing left in flight to emit for a turn it already finished. It
    // can only be a genuine error for the newly sent turn B (e.g. a
    // session-creation failure emitted before ack), so it must settle B.
    await act(async () => {
      fake.serverEmit('error', { conversationId: 'c1', error: 'turn B session failure' });
    });
    expect(latest?.state.sending).toBe(false);
    expect(latest?.state.streaming).toBe(false);
    expect(latest?.state.error).toBe('turn B session failure');

    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn C' });
    });
    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(2);
    expect(latest?.state.messages.some((m) => m.text === 'turn C')).toBe(true);
  });

  it('invalidates an outstanding approval request when a pre-ack error settles turn B on an already-established conversation', async () => {
    // Turn A completes normally on c1.
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });
    expect(latest?.state.sending).toBe(false);

    // Turn B is sent but has not yet received its own ack/start.
    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn B' });
    });
    expect(latest?.state.sending).toBe(true);

    // An approval request is outstanding on c1 — approveCommand has no
    // dependency on `sending`/`streaming`, so this is legitimate even while
    // turn B has not yet started.
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'prod' });
    });
    expect(latest?.state.approvalRequestPending).toBe(true);

    // A genuine pre-ack error for turn B is terminal — same as an
    // active-turn error, it invalidates any approval request still awaiting
    // a response, since the Gateway that just errored is unlikely to still
    // answer it.
    await act(async () => {
      fake.serverEmit('error', { conversationId: 'c1', error: 'turn B session failure' });
    });

    expect(latest?.state.sending).toBe(false);
    expect(latest?.state.approvalRequestPending).toBe(false);
    expect(latest?.state.error).toBe('turn B session failure');

    // A fresh approval request can be issued again after the invalidation.
    await act(async () => {
      latest?.actions.approveCommand({ command: 'deploy', args: 'staging' });
    });
    expect(fake.emitted.filter((e) => e.event === 'command:approve')).toHaveLength(2);
  });

  it("P3-5c: locks the achievable pre-start boundary — turn A settled, turn B sent and acked but before B's own start, a stale/duplicate agent:end from A does not release B (a third send stays blocked), and only B's own start/end sequence legitimately releases it", async () => {
    // This is the provable boundary: in-order Socket.IO delivery guarantees
    // a same-conversation agent:end arriving before this turn's own
    // agent:start can only be a stale straggler. Once a turn is 'active',
    // AgentEndPayload/ErrorPayload carry no turn identity to further
    // distinguish a genuine end from a duplicate — that residual is not,
    // and cannot be, asserted here; full correlation needs a wire turnId
    // (deferred to P5). See the reducer comments in use-chat-connection.ts.
    // Turn A completes normally on c1.
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      fake.serverEmit('agent:start', { conversationId: 'c1' });
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });
    expect(latest?.state.sending).toBe(false);

    // Turn B is sent and its own ack arrives. Under the old
    // ack-arms-the-lock design this alone made the lock releasable by any
    // same-conversation terminal — the precise bug: it could not yet
    // distinguish B's own eventual agent:end from a late duplicate delivery
    // of A's already-consumed one.
    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn B' });
    });
    await act(async () => {
      fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm2' });
    });
    expect(latest?.state.sending).toBe(true);

    // A duplicate/straggler agent:end for turn A (already fully settled
    // above) is redelivered for the same conversation before B's own
    // agent:start ever arrived. Only B's own accepted agent:start may move
    // it into the active phase that a real agent:end may settle — this
    // duplicate must be a true no-op.
    await act(async () => {
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });
    expect(latest?.state.sending).toBe(true);
    expect(latest?.state.streaming).toBe(false);

    // Turn C must still be blocked — the lock is still genuinely held by B.
    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn C attempt' });
    });
    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(1);
    expect(latest?.state.messages.some((m) => m.text === 'turn C attempt')).toBe(false);

    // B's own start, then its own end, legitimately unlocks it.
    await act(async () => {
      fake.serverEmit('agent:start', { conversationId: 'c1' });
    });
    expect(latest?.state.streaming).toBe(true);

    await act(async () => {
      fake.serverEmit('agent:end', { conversationId: 'c1' });
    });
    expect(latest?.state.sending).toBe(false);

    await act(async () => {
      latest?.actions.sendMessage({ content: 'turn D' });
    });
    expect(fake.emitted.filter((e) => e.event === 'message')).toHaveLength(2);
  });

  it('removes every listener and tears down the socket on cleanup, using no network', async () => {
    const registeredEvents = [...fake.listeners.keys()];
    expect(registeredEvents.length).toBeGreaterThan(0);

    await act(async () => {
      root?.unmount();
    });
    root = null;

    for (const [, handlers] of fake.listeners) {
      expect(handlers.size).toBe(0);
    }
    expect(destroySocketMock).toHaveBeenCalledOnce();
  });

  describe('chat:send-capability protocol negotiation (Task Five MAJOR-1, red-first)', () => {
    const capSelection: HarnessSelection = {
      harnessId: 'pi',
      providerId: 'anthropic',
      modelId: 'claude',
    };
    const UUID = 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb';
    // The one fixed, safe user-facing notice the hook must surface (code
    // `send_protocol_unavailable`) when a send is attempted on a connection whose
    // advertised protocol is `unavailable`/unknown/absent. Contract-frozen string.
    const UNAVAILABLE_NOTICE = 'Chat sending is unavailable on this connection.';

    // These tests each drive the protocol negotiation themselves, so they must
    // start from a clean, unadvertised generation. Reconnect resets protocolRef
    // to `unavailable` and clears the outer `legacy-message` first-wins lock
    // WITHOUT advertising — no client emit, so `fake.emitted` stays empty and the
    // "starts unavailable" premise holds.
    beforeEach(async () => {
      await act(async () => {
        fake.simulateReconnect();
      });
    });

    async function establishConversation(): Promise<void> {
      await act(async () => {
        fake.serverEmit('message:ack', { conversationId: 'c1', messageId: 'm1' });
      });
    }

    function connectCalls(): number {
      return (fake.socket.connect as unknown as { mock: { calls: unknown[] } }).mock.calls.length;
    }

    it('starts with no advertised protocol: a send is refused, emits nothing, mints no key, and surfaces the fixed unavailable notice', async () => {
      // No `chat:send-capability` has arrived, so the connection has not been told
      // it may send at all. The current impl infers "selection + no conversation +
      // no flat provider/model → return false" but SURFACES NOTHING — the red is
      // that the fixed `send_protocol_unavailable` notice is never set.
      let uuidCalls = 0;
      const restore = installRandomUUID(() => {
        uuidCalls += 1;
        return UUID;
      });
      let returned: boolean | undefined;
      try {
        await act(async () => {
          returned = harnessSend()({ content: 'hi', selection: capSelection });
        });
      } finally {
        restore();
      }

      expect(returned).toBe(false);
      expect(fake.emitted).toHaveLength(0);
      expect(latest?.state.error).toBe(UNAVAILABLE_NOTICE);
      // The test's name promises "mints no key": the unavailable branch must not
      // reach the idempotency mint at all. Without this assertion a defect that
      // mints a key before refusing survives.
      expect(uuidCalls).toBe(0);
      // ...and no user content may be optimistically appended on refusal.
      expect(latest?.state.messages.some((m) => m.text === 'hi')).toBe(false);
    });

    it('legacy-message advertised overrides conversation-inference: an established conversation still routes the legacy message event, never turn:send', async () => {
      // Same inputs the inference impl routes to `turn:send` (selection + active
      // conversation). The advertised protocol is authoritative: it must emit the
      // legacy `message` event instead. Red: current impl emits turn:send.
      const restore = installRandomUUID(() => UUID);
      try {
        await establishConversation();
        await act(async () => {
          advertiseCapability('legacy-message', fake.socket.id);
        });
        await act(async () => {
          harnessSend()({ content: 'hi', selection: capSelection });
        });
      } finally {
        restore();
      }

      expect(fake.emitted.filter((e) => e.event === 'turn:send')).toHaveLength(0);
      expect(fake.emitted).toContainEqual({
        event: 'message',
        payload: { conversationId: 'c1', content: 'hi', provider: 'anthropic', modelId: 'claude' },
      });
    });

    it('legacy-message advertised with no conversation: derives provider/model from the selection tuple and emits one message', async () => {
      // The flat provider/modelId caller inputs are gone; the legacy branch must
      // source them from the confirmed persisted selection. Red: current impl
      // refuses a bare harness send (selection + no flat fields → return false).
      let returned: boolean | undefined;
      const restore = installRandomUUID(() => UUID);
      try {
        await act(async () => {
          advertiseCapability('legacy-message', fake.socket.id);
        });
        await act(async () => {
          returned = harnessSend()({ content: 'first', selection: capSelection });
        });
      } finally {
        restore();
      }

      expect(returned).toBe(true);
      expect(fake.emitted).toContainEqual({
        event: 'message',
        payload: {
          conversationId: undefined,
          content: 'first',
          provider: 'anthropic',
          modelId: 'claude',
        },
      });
      expect(fake.emitted.some((e) => e.event === 'turn:send')).toBe(false);
    });

    it('unavailable advertised: refuses even with an active conversation and selection, emits nothing, surfaces the fixed notice', async () => {
      // Red: current impl ignores the advertisement and emits turn:send.
      let uuidCalls = 0;
      const restore = installRandomUUID(() => {
        uuidCalls += 1;
        return UUID;
      });
      let returned: boolean | undefined;
      try {
        await establishConversation();
        await act(async () => {
          advertiseCapability('unavailable', fake.socket.id);
        });
        await act(async () => {
          returned = harnessSend()({ content: 'nope', selection: capSelection });
        });
      } finally {
        restore();
      }

      expect(returned).toBe(false);
      expect(fake.emitted).toHaveLength(0);
      expect(latest?.state.error).toBe(UNAVAILABLE_NOTICE);
      // Refusal must not optimistically append the user's turn to the transcript
      // (a distinct leak from the emit): the unavailable branch appends nothing.
      expect(latest?.state.messages.some((m) => m.text === 'nope')).toBe(false);
      // ...and must not mint an idempotency key on the refused path.
      expect(uuidCalls).toBe(0);
    });

    it('ignores an advertisement whose connectionId does not match the socket id: protocol stays unavailable and the send is refused', async () => {
      // A capability minted for a different (stale/foreign) connection must never
      // arm this one. Red: current impl has no connection-id gate and emits
      // turn:send off the inferred path.
      const restore = installRandomUUID(() => UUID);
      let returned: boolean | undefined;
      try {
        await establishConversation();
        await act(async () => {
          advertiseCapability('legacy-message', 'a-different-connection');
        });
        await act(async () => {
          returned = harnessSend()({ content: 'spoof', selection: capSelection });
        });
      } finally {
        restore();
      }

      expect(returned).toBe(false);
      expect(fake.emitted).toHaveLength(0);
      expect(latest?.state.error).toBe(UNAVAILABLE_NOTICE);
    });

    it('accepts only the first advertisement for the generation: a later conflicting protocol is ignored', async () => {
      // legacy-message wins; the subsequent turn-send is a replay/conflict and is
      // dropped. Red: current impl ignores both and infers turn:send.
      const restore = installRandomUUID(() => UUID);
      try {
        await establishConversation();
        await act(async () => {
          advertiseCapability('legacy-message', fake.socket.id);
        });
        await act(async () => {
          advertiseCapability('turn-send', fake.socket.id);
        });
        await act(async () => {
          harnessSend()({ content: 'hi', selection: capSelection });
        });
      } finally {
        restore();
      }

      expect(fake.emitted.filter((e) => e.event === 'turn:send')).toHaveLength(0);
      expect(fake.emitted).toContainEqual({
        event: 'message',
        payload: { conversationId: 'c1', content: 'hi', provider: 'anthropic', modelId: 'claude' },
      });
    });

    it('resets to unavailable on disconnect: a later send is refused and never reconnects the socket', async () => {
      // Disconnect voids the advertised protocol for the generation. The send must
      // refuse and MUST NOT call socket.connect() to force a reconnection. Red:
      // current impl keeps the conversation, infers turn:send, and its turn:send
      // branch calls socket.connect() when the socket is disconnected.
      const restore = installRandomUUID(() => UUID);
      let returned: boolean | undefined;
      let connectsDuringSend = 0;
      try {
        await establishConversation();
        await act(async () => {
          advertiseCapability('legacy-message', fake.socket.id);
        });
        await act(async () => {
          fake.simulateDisconnect();
        });
        const before = connectCalls();
        await act(async () => {
          returned = harnessSend()({ content: 'after-drop', selection: capSelection });
        });
        connectsDuringSend = connectCalls() - before;
      } finally {
        restore();
      }

      expect(returned).toBe(false);
      expect(fake.emitted).toHaveLength(0);
      expect(latest?.state.error).toBe(UNAVAILABLE_NOTICE);
      expect(connectsDuringSend).toBe(0);
    });

    it('resets on reconnect to a fresh generation: refuses until re-advertised, then honors the new advertisement', async () => {
      // A reconnect mints a new Socket.id and a new generation; the prior
      // advertisement (bound to the old id) is stale and must not carry over. The
      // hook only trusts a fresh advertisement for the new connection. Red:
      // current impl has no connect listener and keeps inferring turn:send.
      const restore = installRandomUUID(() => UUID);
      let refusedAfterReconnect: boolean | undefined;
      try {
        await establishConversation();
        await act(async () => {
          advertiseCapability('legacy-message', fake.socket.id);
        });
        await act(async () => {
          fake.simulateReconnect('socket-b');
        });
        await act(async () => {
          refusedAfterReconnect = harnessSend()({ content: 'stale', selection: capSelection });
        });
      } finally {
        restore();
      }

      expect(refusedAfterReconnect).toBe(false);
      expect(fake.emitted).toHaveLength(0);
      expect(latest?.state.error).toBe(UNAVAILABLE_NOTICE);

      // A fresh advertisement for the reconnected id (socket-b) re-arms sending.
      const restore2 = installRandomUUID(() => UUID);
      try {
        await act(async () => {
          advertiseCapability('legacy-message', 'socket-b');
        });
        await act(async () => {
          harnessSend()({ content: 'welcome-back', selection: capSelection });
        });
      } finally {
        restore2();
      }

      expect(fake.emitted).toContainEqual({
        event: 'message',
        payload: {
          conversationId: 'c1',
          content: 'welcome-back',
          provider: 'anthropic',
          modelId: 'claude',
        },
      });
      expect(fake.emitted.some((e) => e.event === 'turn:send')).toBe(false);
    });

    it('routes on the synchronous protocol ref, not the batched reducer mirror: an advertisement and a send in the SAME tick still route by the just-advertised protocol', async () => {
      // An advertisement lands and a send is issued within one synchronous tick,
      // before React commits the reducer's `sendProtocol` mirror. The send is
      // captured from the pre-advertisement render, so its closed-over reducer
      // state still reads `sendProtocol === 'unavailable'`; the capability
      // handler, however, has already set the synchronous `protocolRef` to
      // `legacy-message`. The hook must route on that ref. Red (against a
      // stale-mirror routing that reads `state.sendProtocol`): the send reads the
      // pre-advertisement `unavailable` and refuses instead of emitting `message`.
      const restore = installRandomUUID(() => UUID);
      try {
        await act(async () => {
          // Bound to the CURRENT (pre-advertisement) render — its closure still
          // sees the reset `unavailable` mirror even after the advert dispatches.
          const sendBeforeCommit = harnessSend();
          advertiseCapability('legacy-message', fake.socket.id);
          // Same tick, no await: React has not committed the new mirror yet, so
          // only `protocolRef` reflects `legacy-message`.
          sendBeforeCommit({ content: 'same-tick', selection: capSelection });
        });
      } finally {
        restore();
      }

      expect(fake.emitted).toContainEqual({
        event: 'message',
        payload: {
          conversationId: undefined,
          content: 'same-tick',
          provider: 'anthropic',
          modelId: 'claude',
        },
      });
      expect(fake.emitted.some((e) => e.event === 'turn:send')).toBe(false);
    });
  });
});
