// @vitest-environment jsdom import { act, renderHook, waitFor } from "@testing-library/react"; import { renderToString } from "react-dom/server"; import { describe, expect, it, vi } from "vitest"; import { type ApplicationResult, useApplicationMutation, } from "../../src/presentation/adapters/query/application-query.ts"; import { createFailure } from "../../src/contracts/errors.ts"; import { MUTATION_COORDINATOR_BOUNDS } from "../../src/contracts/server-state.ts"; import { RESOURCE_INVALIDATION_TOPIC, queryClient, scopeSnapshot, wrapper, } from "./application-query-fixture.tsx"; describe("application mutation reconciliation bridge", () => { it.each([ ["NOT_STARTED", ["existing"], 0, null], ["NOT_APPLIED", ["existing"], 0, null], ["APPLIED_CONFIRMED", ["existing", "created"], 1, null], [ "MAYBE_APPLIED", ["existing", "created"], 0, "mutation-effect-unknown", ], ] as const)( "settles an optimistic failure with %s certainty", async (effect, expectedData, expectedInvalidations, expectedIndicator) => { const client = queryClient(); const key = ["resource", `certainty-${effect}`]; client.setQueryData(key, ["existing"]); const invalidateQueries = vi.spyOn(client, "invalidateQueries"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect, }); const hook = renderHook( () => useApplicationMutation({ execute: async () => ({ ok: false, error: failure }), invalidate: [RESOURCE_INVALIDATION_TOPIC], currentData: client.getQueryData(key), optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); let outcome: ApplicationResult | undefined; await act(async () => { outcome = await hook.result.current.submit("created"); }); expect(outcome).toMatchObject({ ok: false, error: { kind: failure.kind, effect }, }); expect(client.getQueryData(key)).toEqual([...expectedData]); expect(invalidateQueries).toHaveBeenCalledTimes(expectedInvalidations); expect(hook.result.current.state.indicator).toBe(expectedIndicator); if (effect === "MAYBE_APPLIED") { expect(outcome).toMatchObject({ ok: false, error: { retryable: false, action: "contact-support" }, }); expect(hook.result.current.state.overlay).toMatchObject({ mutationEffectUnknown: true, mutationPending: false, mutationConflict: false, }); } if (effect === "APPLIED_CONFIRMED") { expect(outcome).toMatchObject({ ok: false, error: { retryable: false, action: "none" }, }); } }, ); it("keeps an applied-confirmed layer committed when invalidation fails", async () => { const client = queryClient(); const key = ["resource", "applied-invalidation-failure"]; client.setQueryData(key, ["base"]); const invalidateQueries = vi .spyOn(client, "invalidateQueries") .mockImplementation(async () => { expect(client.getQueryData(key)).toEqual(["base", "created"]); throw new Error("refresh failed"); }); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "APPLIED_CONFIRMED", }); const hook = renderHook( () => useApplicationMutation({ definitionId: "legacy-applied-invalidation-failure-v1", execute: async () => ({ ok: false, error: failure }), invalidate: [RESOURCE_INVALIDATION_TOPIC], currentData: client.getQueryData(key), optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); let outcome: ApplicationResult | undefined; await act(async () => { outcome = await hook.result.current.submit("created"); }); expect(outcome).toMatchObject({ ok: false, error: { effect: "APPLIED_CONFIRMED", retryable: false, action: "none", }, }); expect(invalidateQueries).toHaveBeenCalledOnce(); expect(client.getQueryData(key)).toEqual(["base", "created"]); }); it("treats a command failure with missing effect certainty as maybe applied", async () => { const client = queryClient(); const key = ["resource", "missing-effect"]; client.setQueryData(key, ["existing"]); const invalidateQueries = vi.spyOn(client, "invalidateQueries"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0); const execute = vi.fn(async () => ({ ok: false as const, error: failure })); const hook = renderHook( () => useApplicationMutation({ execute, invalidate: [RESOURCE_INVALIDATION_TOPIC], currentData: client.getQueryData(key), optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); let outcome: ApplicationResult | undefined; await act(async () => { outcome = await hook.result.current.submit("created"); }); expect(execute).toHaveBeenCalledOnce(); expect(outcome).toMatchObject({ ok: false, error: { effect: "MAYBE_APPLIED", retryable: false, action: "contact-support", }, }); expect(client.getQueryData(key)).toEqual(["existing", "created"]); expect(invalidateQueries).not.toHaveBeenCalled(); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); }); it.each([ ["APPLIED", ["existing", "created"], 1], ["NOT_APPLIED", ["existing"], 0], ] as const)( "reconciles an unknown optimistic effect as %s exactly once", async (resolution, expectedData, expectedInvalidations) => { const client = queryClient(); const scope = scopeSnapshot(); const key = ["resource", `reconcile-${resolution}`]; client.setQueryData(key, ["existing"]); const invalidateQueries = vi.spyOn(client, "invalidateQueries"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const hook = renderHook( () => useApplicationMutation({ definitionId: `reconcile-${resolution}-v1`, definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "REJECT_WHILE_ACTIVE", scope, execute: async () => ({ ok: false, error: failure }), invalidate: [RESOURCE_INVALIDATION_TOPIC], optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); await act(() => hook.result.current.submit("created")); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => hook.result.current.reconcileUnknownEffect(resolution)); await act(() => hook.result.current.reconcileUnknownEffect( resolution === "APPLIED" ? "NOT_APPLIED" : "APPLIED", ), ); expect(client.getQueryData(key)).toEqual([...expectedData]); expect(invalidateQueries).toHaveBeenCalledTimes(expectedInvalidations); expect(hook.result.current.state.indicator).toBeNull(); }, ); it("reconciles parallel unknown effects without losing either lease", async () => { const client = queryClient(); const scope = scopeSnapshot(); const key = ["resource", "parallel-unknown"]; client.setQueryData(key, ["base"]); const invalidateQueries = vi.spyOn(client, "invalidateQueries"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const resolvers: Array<(value: ApplicationResult) => void> = []; const execute = vi.fn( (_input: string) => new Promise>((resolve) => { resolvers.push(resolve); }), ); const hook = renderHook( () => useApplicationMutation({ definitionId: "parallel-unknown-v1", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "ALLOW_PARALLEL", scope, execute, invalidate: [RESOURCE_INVALIDATION_TOPIC], optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); let first: Promise> | undefined; let second: Promise> | undefined; act(() => { first = hook.result.current.submit("created"); second = hook.result.current.submit("created"); }); await waitFor(() => expect(resolvers).toHaveLength(2)); act(() => resolvers[0]?.({ ok: false, error: failure })); if (!first) throw new Error("expected first mutation"); await act(() => first); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); act(() => resolvers[1]?.({ ok: false, error: failure })); if (!second) throw new Error("expected second mutation"); await act(() => second); expect(client.getQueryData(key)).toEqual(["base", "created", "created"]); await act(() => hook.result.current.reconcileUnknownEffect("NOT_APPLIED")); expect(client.getQueryData(key)).toEqual(["base", "created"]); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => hook.result.current.reconcileUnknownEffect("APPLIED")); expect(client.getQueryData(key)).toEqual(["base", "created"]); expect(invalidateQueries).toHaveBeenCalledOnce(); expect(hook.result.current.state.indicator).toBeNull(); }); it("closes an unknown optimistic effect safely after scope expiry", async () => { const client = queryClient(); const scope = scopeSnapshot(); const key = ["resource", "expired-unknown"]; client.setQueryData(key, ["existing"]); const invalidateQueries = vi.spyOn(client, "invalidateQueries"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const hook = renderHook( () => useApplicationMutation({ definitionId: "expired-unknown-v1", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "REJECT_WHILE_ACTIVE", scope, execute: async () => ({ ok: false, error: failure }), invalidate: [RESOURCE_INVALIDATION_TOPIC], optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); await act(() => hook.result.current.submit("created")); scope.fence(); await act(() => hook.result.current.reconcileUnknownEffect("APPLIED")); expect(client.getQueryState(key)).toBeUndefined(); expect(invalidateQueries).not.toHaveBeenCalled(); expect(hook.result.current.state.indicator).toBeNull(); }); it("reconciles a legacy unknown effect without an optimistic layer", async () => { const client = queryClient(); const invalidateQueries = vi.spyOn(client, "invalidateQueries"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const hook = renderHook( () => useApplicationMutation({ definitionId: "legacy-no-layer-reconcile-v1", execute: async () => ({ ok: false, error: failure }), invalidate: [RESOURCE_INVALIDATION_TOPIC], }), { wrapper: wrapper(client) }, ); await act(() => hook.result.current.submit("created")); expect(invalidateQueries).not.toHaveBeenCalled(); await act(() => hook.result.current.reconcileUnknownEffect("APPLIED")); expect(invalidateQueries).toHaveBeenCalledOnce(); expect(hook.result.current.state.indicator).toBeNull(); }); it("preserves a later legacy commit when an earlier unknown effect is not applied", async () => { const client = queryClient(); const key = ["resource", "legacy-ordered-unknown"]; client.setQueryData(key, ["base"]); const uncertainFailure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const resolvers = new Map< string, (value: ApplicationResult) => void >(); const execute = vi.fn( (input: string) => new Promise>((resolve) => { resolvers.set(input, resolve); }), ); const hook = renderHook( () => useApplicationMutation({ definitionId: "legacy-active-after-unknown-v1", duplicatePolicy: "ALLOW_PARALLEL", execute, currentData: client.getQueryData(key), optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); let first: Promise> | undefined; let second: Promise> | undefined; act(() => { first = hook.result.current.submit("first"); second = hook.result.current.submit("second"); }); await waitFor(() => expect(resolvers.size).toBe(2)); act(() => resolvers.get("first")?.({ ok: false, error: uncertainFailure }), ); if (!first) throw new Error("expected first mutation"); await act(() => first); act(() => resolvers.get("second")?.({ ok: true, value: "second" }), ); if (!second) throw new Error("expected second mutation"); await act(() => second); expect(client.getQueryData(key)).toEqual(["base", "first", "second"]); await act(() => hook.result.current.reconcileUnknownEffect("NOT_APPLIED")); expect(client.getQueryData(key)).toEqual(["base", "second"]); }); it("keeps a newer submit pending while reconciling an older unknown effect", async () => { const client = queryClient(); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); let completeSecond: (value: ApplicationResult) => void = () => {}; const execute = vi.fn((input: string) => input === "first" ? Promise.resolve({ ok: false as const, error: failure }) : new Promise>((resolve) => { completeSecond = resolve; }), ); const hook = renderHook( () => useApplicationMutation({ definitionId: "legacy-active-after-unknown-no-layer-v1", duplicatePolicy: "ALLOW_PARALLEL", execute, }), { wrapper: wrapper(client) }, ); await act(() => hook.result.current.submit("first")); let second: Promise> | undefined; act(() => { second = hook.result.current.submit("second"); }); await waitFor(() => expect(execute).toHaveBeenCalledTimes(2)); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => hook.result.current.reconcileUnknownEffect("NOT_APPLIED")); expect(hook.result.current.state.indicator).toBe("mutation-pending"); completeSecond({ ok: true, value: "second" }); if (!second) throw new Error("expected second mutation"); await act(() => second); await waitFor(() => expect(hook.result.current.state.indicator).toBeNull()); }); it("serializes reconciliation so a double action cannot settle the next intent", async () => { const client = queryClient(); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); let finishInvalidation: () => void = () => {}; const invalidation = new Promise((resolve) => { finishInvalidation = resolve; }); vi.spyOn(client, "invalidateQueries").mockImplementation( async () => invalidation, ); const hook = renderHook( () => useApplicationMutation({ definitionId: "legacy-applied-double-action-v1", duplicatePolicy: "ALLOW_PARALLEL", execute: async () => ({ ok: false, error: failure }), invalidate: [RESOURCE_INVALIDATION_TOPIC], }), { wrapper: wrapper(client) }, ); await act(async () => { await Promise.all([ hook.result.current.submit("first"), hook.result.current.submit("second"), ]); }); let firstResolution: Promise | undefined; let duplicateResolution: Promise | undefined; act(() => { firstResolution = hook.result.current.reconcileUnknownEffect("APPLIED"); duplicateResolution = hook.result.current.reconcileUnknownEffect( "NOT_APPLIED", ); }); await expect(duplicateResolution).resolves.toBeUndefined(); expect(hook.result.current.state.indicator).toBe("mutation-pending"); finishInvalidation(); if (!firstResolution) throw new Error("expected reconciliation"); await act(() => firstResolution); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => hook.result.current.reconcileUnknownEffect("NOT_APPLIED")); expect(hook.result.current.state.indicator).toBeNull(); }); it("keeps the next intent unresolved after a synchronous not-applied double action", async () => { const client = queryClient(); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const hook = renderHook( () => useApplicationMutation({ definitionId: "legacy-not-applied-double-action-v1", duplicatePolicy: "ALLOW_PARALLEL", execute: async () => ({ ok: false, error: failure }), }), { wrapper: wrapper(client) }, ); await act(async () => { await Promise.all([ hook.result.current.submit("first"), hook.result.current.submit("second"), ]); }); let firstResolution: Promise | undefined; let duplicateResolution: Promise | undefined; act(() => { firstResolution = hook.result.current.reconcileUnknownEffect( "NOT_APPLIED", ); duplicateResolution = hook.result.current.reconcileUnknownEffect( "APPLIED", ); }); await expect(duplicateResolution).resolves.toBeUndefined(); if (!firstResolution) throw new Error("expected reconciliation"); await act(() => firstResolution); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => hook.result.current.reconcileUnknownEffect("NOT_APPLIED")); expect(hook.result.current.state.indicator).toBeNull(); }); it("clears every stale-scope unknown effect without touching new data", async () => { const client = queryClient(); const scope = scopeSnapshot(); const key = ["resource", "scope-unknown-queue"]; client.setQueryData(key, ["base"]); const invalidateQueries = vi.spyOn(client, "invalidateQueries"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const hook = renderHook( () => useApplicationMutation({ definitionId: "scope-unknown-queue-v1", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "ALLOW_PARALLEL", scope, execute: async () => ({ ok: false, error: failure }), invalidate: [RESOURCE_INVALIDATION_TOPIC], optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); await act(async () => { await Promise.all([ hook.result.current.submit("created"), hook.result.current.submit("created"), ]); }); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); act(() => scope.fence()); await waitFor(() => expect(hook.result.current.state.indicator).toBeNull()); expect(client.getQueryState(key)).toBeUndefined(); client.setQueryData(key, ["new-generation"]); await act(() => hook.result.current.reconcileUnknownEffect("APPLIED")); expect(client.getQueryData(key)).toEqual(["new-generation"]); expect(invalidateQueries).not.toHaveBeenCalled(); }); it("restores a bound unknown-effect head after controller remount", async () => { const client = queryClient(); const scope = scopeSnapshot(); const key = ["resource", "durable-unknown"]; client.setQueryData(key, ["base"]); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const mutationOptions = { definitionId: "durable-unknown-v1", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "REJECT_WHILE_ACTIVE" as const, scope, execute: vi.fn(async () => ({ ok: false as const, error: failure })), invalidate: [] as const, optimistic: { queryKey: key, update: (previous: unknown, input: string) => [ ...(previous as string[]), input, ], }, }; const first = renderHook( () => useApplicationMutation(mutationOptions), { wrapper: wrapper(client) }, ); await act(() => first.result.current.submit("created")); expect(first.result.current.state.indicator).toBe( "mutation-effect-unknown", ); first.unmount(); const remounted = renderHook( () => useApplicationMutation(mutationOptions), { wrapper: wrapper(client) }, ); expect(remounted.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => remounted.result.current.reconcileUnknownEffect("NOT_APPLIED"), ); expect(client.getQueryData(key)).toEqual(["base"]); expect(remounted.result.current.state.indicator).toBeNull(); expect(mutationOptions.execute).toHaveBeenCalledOnce(); }); it("restores a non-optimistic legacy unknown effect by stable definition after remount", async () => { const client = queryClient(); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const mutationOptions = { definitionId: "legacy-durable-create-v1", execute: vi.fn(async () => ({ ok: false as const, error: failure })), }; const first = renderHook( () => useApplicationMutation(mutationOptions), { wrapper: wrapper(client) }, ); await act(() => first.result.current.submit("created")); expect(first.result.current.state.indicator).toBe( "mutation-effect-unknown", ); first.unmount(); const remounted = renderHook( () => useApplicationMutation(mutationOptions), { wrapper: wrapper(client) }, ); expect(remounted.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => remounted.result.current.reconcileUnknownEffect("NOT_APPLIED"), ); expect(remounted.result.current.state.indicator).toBeNull(); expect(mutationOptions.execute).toHaveBeenCalledOnce(); }); it("does not allocate unknown-effect channels for abandoned server renders", async () => { const client = queryClient(); const selectedScopes = Array.from( { length: MUTATION_COORDINATOR_BOUNDS.activeDefinitionsPerRuntime }, (_, index) => scopeSnapshot(1, `server-render-scope-${index}`), ); function AbandonedMutation({ index }: Readonly<{ index: number }>) { useApplicationMutation({ definitionId: `server-render-abandoned-${index}`, definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "REJECT_WHILE_ACTIVE", scope: selectedScopes[index]!, execute: async (input) => ({ ok: true, value: input }), invalidate: [], }); return null; } const ServerWrapper = wrapper(client); renderToString( {selectedScopes.map((_, index) => ( ))} , ); const scope = scopeSnapshot(1, "committed-after-server-render"); const execute = vi.fn(async (input: string) => ({ ok: true as const, value: input, })); const committed = renderHook( () => useApplicationMutation({ definitionId: "committed-after-server-render", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "REJECT_WHILE_ACTIVE", scope, execute, invalidate: [], }), { wrapper: wrapper(client) }, ); await expect(committed.result.current.submit("created")).resolves.toEqual({ ok: true, value: "created", }); expect(execute).toHaveBeenCalledOnce(); }); it("isolates channels when a reused fingerprint advances generation", async () => { const client = queryClient(); const firstScope = scopeSnapshot(1, "reused-scope-fingerprint"); const secondScope = scopeSnapshot(2, "reused-scope-fingerprint"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const definition = { definitionId: "generation-channel-v1", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "REJECT_WHILE_ACTIVE" as const, invalidate: [] as const, }; const first = renderHook( () => useApplicationMutation({ ...definition, scope: firstScope, execute: async () => ({ ok: false, error: failure }), }), { wrapper: wrapper(client) }, ); await act(() => first.result.current.submit("first")); expect(first.result.current.state.indicator).toBe( "mutation-effect-unknown", ); const secondExecute = vi.fn(async () => ({ ok: true as const, value: "second", })); const second = renderHook( () => useApplicationMutation({ ...definition, scope: secondScope, execute: secondExecute, }), { wrapper: wrapper(client) }, ); expect(second.result.current.state.indicator).toBeNull(); await expect(second.result.current.submit("second")).resolves.toEqual({ ok: true, value: "second", }); expect(secondExecute).toHaveBeenCalledOnce(); expect(first.result.current.state.indicator).toBe( "mutation-effect-unknown", ); }); it("isolates unrelated non-optimistic legacy controllers", async () => { const client = queryClient(); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const first = renderHook( () => useApplicationMutation({ definitionId: "legacy-isolation-first-v1", execute: async () => ({ ok: false, error: failure }), }), { wrapper: wrapper(client) }, ); const second = renderHook( () => useApplicationMutation({ definitionId: "legacy-isolation-second-v1", execute: async (input) => ({ ok: true, value: input }), }), { wrapper: wrapper(client) }, ); await act(() => first.result.current.submit("first")); expect(first.result.current.state.indicator).toBe( "mutation-effect-unknown", ); expect(second.result.current.state.indicator).toBeNull(); await act(() => second.result.current.reconcileUnknownEffect("APPLIED")); expect(first.result.current.state.indicator).toBe( "mutation-effect-unknown", ); }); it("fails closed when identical bound metadata is mounted with a different scope owner", async () => { const client = queryClient(); const firstScope = scopeSnapshot(1, "same-owner-fingerprint"); const secondScope = scopeSnapshot(1, "same-owner-fingerprint"); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const definition = { definitionId: "scope-owner-channel-v1", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "REJECT_WHILE_ACTIVE" as const, invalidate: [] as const, }; const first = renderHook( () => useApplicationMutation({ ...definition, scope: firstScope, execute: async () => ({ ok: false, error: failure }), }), { wrapper: wrapper(client) }, ); await act(() => first.result.current.submit("first")); const secondExecute = vi.fn(async () => ({ ok: true as const, value: "second", })); const second = renderHook( () => useApplicationMutation({ ...definition, scope: secondScope, execute: secondExecute, }), { wrapper: wrapper(client) }, ); expect(second.result.current.state.indicator).toBeNull(); await expect(second.result.current.submit("second")).resolves.toMatchObject({ ok: false, error: { kind: "IDENTITY_INTERN_LIMIT_EXCEEDED", code: "UNKNOWN_EFFECT_CHANNEL_LIMIT_EXCEEDED", effect: "NOT_STARTED", }, }); expect(secondExecute).not.toHaveBeenCalled(); expect(first.result.current.state.indicator).toBe( "mutation-effect-unknown", ); }); it("releases empty unmounted channels after their active mutation settles", async () => { const client = queryClient(); const firstScope = scopeSnapshot(1, "release-owner-fingerprint"); const secondScope = scopeSnapshot(1, "release-owner-fingerprint"); let resolveFirst: (value: ApplicationResult) => void = () => {}; const definition = { definitionId: "release-channel-v1", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "ALLOW_PARALLEL" as const, invalidate: [] as const, }; const first = renderHook( () => useApplicationMutation({ ...definition, scope: firstScope, execute: () => new Promise((resolve) => { resolveFirst = resolve; }), }), { wrapper: wrapper(client) }, ); let pending: Promise> | undefined; act(() => { pending = first.result.current.submit("created"); }); await waitFor(() => expect(first.result.current.state.indicator).toBe("mutation-pending"), ); first.unmount(); resolveFirst({ ok: true, value: "created" }); if (!pending) throw new Error("expected active mutation"); await act(() => pending); const execute = vi.fn(async () => ({ ok: true as const, value: "after-release", })); const afterRelease = renderHook( () => useApplicationMutation({ ...definition, scope: secondScope, execute, }), { wrapper: wrapper(client) }, ); await expect(afterRelease.result.current.submit("created")).resolves.toEqual({ ok: true, value: "after-release", }); expect(execute).toHaveBeenCalledOnce(); }); it("enforces the active intent bound across all QueryClient channels", async () => { const client = queryClient(); const scope = scopeSnapshot(); const never = () => new Promise>(() => {}); const options = (definitionId: string) => ({ definitionId, definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "ALLOW_PARALLEL" as const, scope, execute: never, invalidate: [] as const, }); const first = renderHook( () => useApplicationMutation(options("bound-a")), { wrapper: wrapper(client) }, ); const second = renderHook( () => useApplicationMutation(options("bound-b")), { wrapper: wrapper(client) }, ); const half = MUTATION_COORDINATOR_BOUNDS.activeIntentsTotal / 2; act(() => { for (let index = 0; index < half; index += 1) { void first.result.current.submit("same-input"); void second.result.current.submit("same-input"); } }); await expect(first.result.current.submit("same-input")).resolves.toMatchObject({ ok: false, error: { kind: "IDENTITY_INTERN_LIMIT_EXCEEDED", code: "UNKNOWN_EFFECT_CHANNEL_LIMIT_EXCEEDED", effect: "NOT_STARTED", }, }); act(() => scope.fence()); }); it("reconciles parallel unknown effects in submit order after reverse completion", async () => { const client = queryClient(); const key = ["resource", "reverse-completion"]; client.setQueryData(key, ["base"]); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const resolvers = new Map< string, (value: ApplicationResult) => void >(); const hook = renderHook( () => useApplicationMutation({ duplicatePolicy: "ALLOW_PARALLEL", execute: (input) => new Promise((resolve) => { resolvers.set(input, resolve); }), currentData: client.getQueryData(key), optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); let first: Promise> | undefined; let second: Promise> | undefined; act(() => { first = hook.result.current.submit("first"); second = hook.result.current.submit("second"); }); await waitFor(() => expect(resolvers.size).toBe(2)); act(() => resolvers.get("second")?.({ ok: false, error: failure })); if (!second) throw new Error("expected second mutation"); await act(() => second); expect(hook.result.current.state.indicator).toBe("mutation-pending"); act(() => resolvers.get("first")?.({ ok: false, error: failure })); if (!first) throw new Error("expected first mutation"); await act(() => first); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => hook.result.current.reconcileUnknownEffect("NOT_APPLIED")); expect(client.getQueryData(key)).toEqual(["base", "second"]); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); await act(() => hook.result.current.reconcileUnknownEffect("APPLIED")); expect(client.getQueryData(key)).toEqual(["base", "second"]); expect(hook.result.current.state.indicator).toBeNull(); }); it("removes committed old-scope data when scope fences during reconciliation invalidation", async () => { const client = queryClient(); const scope = scopeSnapshot(); const key = ["resource", "reconcile-fence-race"]; client.setQueryData(key, ["base"]); let finishInvalidation: () => void = () => {}; const invalidation = new Promise((resolve) => { finishInvalidation = resolve; }); const invalidateQueries = vi .spyOn(client, "invalidateQueries") .mockImplementation(async () => invalidation); const failure = createFailure("SERVER_FAILURE", "CREATE", 0, { effect: "MAYBE_APPLIED", }); const hook = renderHook( () => useApplicationMutation({ definitionId: "reconcile-fence-race-v1", definitionVersion: 1, operationId: "CREATE", requiresIdempotencyKey: true, owner: "platform-test", duplicatePolicy: "REJECT_WHILE_ACTIVE", scope, execute: async () => ({ ok: false, error: failure }), invalidate: [RESOURCE_INVALIDATION_TOPIC], optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); await act(() => hook.result.current.submit("created")); let reconciliation: Promise | undefined; act(() => { reconciliation = hook.result.current.reconcileUnknownEffect("APPLIED"); }); await waitFor(() => expect(invalidateQueries).toHaveBeenCalledOnce()); act(() => scope.fence()); finishInvalidation(); if (!reconciliation) throw new Error("expected reconciliation"); await act(() => reconciliation); expect(client.getQueryState(key)).toBeUndefined(); expect(hook.result.current.state.indicator).toBeNull(); }); it.each(["NOT_APPLICABLE", undefined] as const)( "treats %s conflict effect certainty as unknown without conflict retry", async (effect) => { const client = queryClient(); const key = ["resource", `ambiguous-conflict-${String(effect)}`]; client.setQueryData(key, ["base"]); const conflict = createFailure("CONFLICT", "CREATE", 0, { ...(effect ? { effect } : {}), }); const hook = renderHook( () => useApplicationMutation({ execute: async () => ({ ok: false, error: conflict }), currentData: client.getQueryData(key), optimistic: { queryKey: key, update: (previous, input) => [ ...(previous as string[]), input, ], }, }), { wrapper: wrapper(client) }, ); let outcome: ApplicationResult | undefined; await act(async () => { outcome = await hook.result.current.submit("created"); }); expect(outcome).toMatchObject({ ok: false, error: { effect: "MAYBE_APPLIED", retryable: false, action: "contact-support", }, }); expect(client.getQueryData(key)).toEqual(["base", "created"]); expect(hook.result.current.state.indicator).toBe( "mutation-effect-unknown", ); }, ); });