fix: close the live V3 authority findings from the adapter re-review

LIVE-01. A credential collaborator that returns UNAVAILABLE, throws, rejects
or answers off-contract is an outage of the auth integration, not evidence
about the user's session. Each of those now closes as AUTH_INTEGRATION_FAILURE
with zero fetches, so the composition root's logout path stays reserved for a
genuinely absent session. The synchronous and asynchronous failure sites share
one classifier.

LIVE-02 / LIVE-03. Object.freeze(new Map(...)) freezes the wrapper, not the
backing store, so an exported registry could still be cleared or replaced after
composition. Both the installed REST auth profile registry and the composed
HTTP/event lookups are now read facades over private stores, and every composed
row is an exact own-data snapshot that rejects accessors, inherited and
symbol-keyed fields.

LIVE-04. The total deadline now bounds the physical waits rather than being
checked between them: dispatch and response admission race the attempt signal,
the bounded reader takes that signal, and an abandoned operation is still
observed once so a late native rejection cannot surface unhandled. A body that
completes after the deadline or the caller owns the execution is no longer
admitted; a stale generation keeps its more specific SCOPE_FENCED verdict.

LIVE-05. DEADLINE is no longer treated as a caller-owned cancellation, so a
timeout reaches api.request.failed exactly once while caller, route, scope and
shutdown aborts stay excluded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-08-14 13:43:59 +09:00
co-authored by Claude Opus 5
parent 3b481eb4cf
commit f4bfdf0365
9 changed files with 2172 additions and 28 deletions
@@ -0,0 +1,412 @@
import { describe, expect, it, vi } from "vitest";
import {
createContractHttpExecutor,
type HttpExecutionObservation,
} from "../../src/adapters/http/http-execution-v3.ts";
import { createHttpObservationProjector } from "../../src/bootstrap/runtime-adapters.ts";
import { installRestAuthProfileRegistry } from "../../src/contracts/rest-profiles.ts";
import { TEST_LIST_HTTP_CONTRACT } from "../helpers/external-contract-fixture.ts";
const ROUTE_ID = "TEST_ROUTE";
const TEST_PROFILES = installRestAuthProfileRegistry({
TEST_AUTH: {
authProfileId: "TEST_AUTH",
transport: "BEARER_HEADER",
credentials: "omit",
allowedCredentialHeaders: ["authorization"],
requiredCredentialHeaders: ["authorization"],
},
});
function scopeSnapshot(signal: AbortSignal = new AbortController().signal) {
return Object.freeze({
generation: 1,
fingerprint: "scope-1",
identities: Object.freeze({}) as never,
signal,
isCurrent: () => true,
});
}
function bearerOperation(deadlineMs = 10_000) {
return {
...TEST_LIST_HTTP_CONTRACT,
frontend: {
...TEST_LIST_HTTP_CONTRACT.frontend,
authProfileId: "TEST_AUTH",
totalDeadlineMs: deadlineMs,
},
};
}
function jsonResponse(body: unknown): Response {
return new Response(JSON.stringify(body), {
status: 200,
headers: { "content-type": "application/json" },
});
}
/**
* LIVE-01. A credential collaborator that is broken, unavailable or throwing is
* an integration failure of the auth system. Reporting it as `UNAUTHENTICATED`
* makes the composition root run its logout path, so an auth outage would sign
* every user out.
*/
describe("LIVE-01 credential integration failures are not user session failures", () => {
const brokenOwners = [
{
label: "returns UNAVAILABLE",
attach: () => Object.freeze({ kind: "UNAVAILABLE" as const }),
},
{
label: "throws synchronously",
attach: () => {
throw new Error("credential owner exploded");
},
},
{
label: "rejects asynchronously",
attach: () => Promise.reject(new Error("credential owner exploded")),
},
{
label: "returns a malformed outcome",
attach: () => ({ kind: "TOTALLY_UNKNOWN" }) as never,
},
];
for (const owner of brokenOwners) {
it(`closes as AUTH_INTEGRATION_FAILURE when the owner ${owner.label}`, async () => {
const fetcher = vi.fn(async () => jsonResponse([]));
const executor = createContractHttpExecutor({
baseUrl: "https://api.example/",
maxRetryAttempts: 0,
authProfiles: TEST_PROFILES,
attachCredentials: owner.attach,
fetcher: fetcher as unknown as typeof fetch,
});
const outcome = await executor.execute(
bearerOperation(),
{ limit: 1 },
{ routeId: ROUTE_ID, scope: scopeSnapshot() },
);
expect(outcome.kind).toBe("AUTH_INTEGRATION_FAILURE");
expect(outcome.effect).toBe("NOT_APPLICABLE");
expect(fetcher).toHaveBeenCalledTimes(0);
});
}
it("still reports a real absent session as UNAUTHENTICATED", async () => {
const fetcher = vi.fn(async () => jsonResponse([]));
const executor = createContractHttpExecutor({
baseUrl: "https://api.example/",
maxRetryAttempts: 0,
authProfiles: TEST_PROFILES,
attachCredentials: () =>
Object.freeze({ kind: "UNAUTHENTICATED" as const }),
fetcher: fetcher as unknown as typeof fetch,
});
const outcome = await executor.execute(
bearerOperation(),
{ limit: 1 },
{ routeId: ROUTE_ID, scope: scopeSnapshot() },
);
expect(outcome.kind).toBe("UNAUTHENTICATED");
expect(fetcher).toHaveBeenCalledTimes(0);
});
});
/**
* LIVE-04. The total deadline must bound the physical wait, not merely be
* checked between awaits. A non-cooperative `fetch` or body reader that ignores
* the abort signal cannot hold the port result open, and a value that arrives
* after the deadline already owns the execution must not be admitted.
*/
describe("LIVE-04 the total deadline owns every physical wait", () => {
it("does not wait for a non-cooperative fetch past the deadline", async () => {
const executor = createContractHttpExecutor({
baseUrl: "https://api.example/",
maxRetryAttempts: 0,
authProfiles: TEST_PROFILES,
attachCredentials: () =>
Object.freeze({
kind: "READY" as const,
headers: { authorization: "Bearer t" },
}),
fetcher: (() => new Promise<Response>(() => {})) as unknown as typeof fetch,
});
const outcome = await executor.execute(
bearerOperation(5),
{ limit: 1 },
{ routeId: ROUTE_ID, scope: scopeSnapshot() },
);
expect(outcome.kind).toBe("TRANSPORT_FAILURE");
expect(
outcome.kind === "TRANSPORT_FAILURE" ? outcome.failure.kind : null,
).toBe("TIMEOUT");
});
it("does not wait for a non-cooperative body reader past the deadline", async () => {
const neverEndingBody = new ReadableStream<Uint8Array>({
pull() {
return new Promise<void>(() => {});
},
});
const executor = createContractHttpExecutor({
baseUrl: "https://api.example/",
maxRetryAttempts: 0,
authProfiles: TEST_PROFILES,
attachCredentials: () =>
Object.freeze({
kind: "READY" as const,
headers: { authorization: "Bearer t" },
}),
fetcher: (async () =>
new Response(neverEndingBody, {
status: 200,
headers: { "content-type": "application/json" },
})) as unknown as typeof fetch,
});
const outcome = await executor.execute(
bearerOperation(20),
{ limit: 1 },
{ routeId: ROUTE_ID, scope: scopeSnapshot() },
);
expect(outcome.kind).toBe("TRANSPORT_FAILURE");
expect(
outcome.kind === "TRANSPORT_FAILURE" ? outcome.failure.kind : null,
).toBe("TIMEOUT");
});
it("does not admit a body that completes after the deadline owns the execution", async () => {
let releaseBody: (() => void) | undefined;
const lateBody = new ReadableStream<Uint8Array>({
pull(controller) {
return new Promise<void>((resolve) => {
releaseBody = () => {
// The executor is expected to have cancelled this reader already;
// enqueueing into the closed controller then throws, which is the
// late producer this scenario is about.
try {
controller.enqueue(new TextEncoder().encode("[]"));
controller.close();
} catch {
// The stream was already cancelled by the deadline owner.
}
resolve();
};
});
},
});
const executor = createContractHttpExecutor({
baseUrl: "https://api.example/",
maxRetryAttempts: 0,
authProfiles: TEST_PROFILES,
attachCredentials: () =>
Object.freeze({
kind: "READY" as const,
headers: { authorization: "Bearer t" },
}),
fetcher: (async () =>
new Response(lateBody, {
status: 200,
headers: { "content-type": "application/json" },
})) as unknown as typeof fetch,
});
const pending = executor.execute(
bearerOperation(10),
{ limit: 1 },
{ routeId: ROUTE_ID, scope: scopeSnapshot() },
);
setTimeout(() => releaseBody?.(), 40);
const outcome = await pending;
expect(outcome.kind).toBe("TRANSPORT_FAILURE");
expect(
outcome.kind === "TRANSPORT_FAILURE" ? outcome.failure.kind : null,
).toBe("TIMEOUT");
});
it("preserves the caller and the scope as distinct cancellation owners", async () => {
const observations: HttpExecutionObservation[] = [];
const makeExecutor = () =>
createContractHttpExecutor({
baseUrl: "https://api.example/",
maxRetryAttempts: 0,
authProfiles: TEST_PROFILES,
attachCredentials: () =>
Object.freeze({
kind: "READY" as const,
headers: { authorization: "Bearer t" },
}),
fetcher: (() =>
new Promise<Response>(() => {})) as unknown as typeof fetch,
observe: (observation) => observations.push(observation),
});
const callerController = new AbortController();
const callerPending = makeExecutor().execute(
bearerOperation(10_000),
{ limit: 1 },
{
routeId: ROUTE_ID,
scope: scopeSnapshot(),
signal: callerController.signal,
},
);
callerController.abort();
expect((await callerPending).kind).toBe("CANCELLED");
expect(observations.at(-1)?.cancellationOwner).toBe("CALLER");
const scopeController = new AbortController();
const scopePending = makeExecutor().execute(
bearerOperation(10_000),
{ limit: 1 },
{ routeId: ROUTE_ID, scope: scopeSnapshot(scopeController.signal) },
);
scopeController.abort();
expect((await scopePending).kind).toBe("TRANSPORT_FAILURE");
expect(observations.at(-1)?.cancellationOwner).toBe("SCOPE_FENCE");
});
it("observes a late native rejection without an unhandled rejection", async () => {
const rejections: unknown[] = [];
const onUnhandled = (event: PromiseRejectionEvent) => {
rejections.push(event.reason);
event.preventDefault();
};
globalThis.addEventListener?.(
"unhandledrejection",
onUnhandled as EventListener,
);
try {
const executor = createContractHttpExecutor({
baseUrl: "https://api.example/",
maxRetryAttempts: 0,
authProfiles: TEST_PROFILES,
attachCredentials: () =>
Object.freeze({
kind: "READY" as const,
headers: { authorization: "Bearer t" },
}),
fetcher: (() =>
new Promise<Response>((_resolve, reject) => {
setTimeout(() => reject(new Error("late native failure")), 30);
})) as unknown as typeof fetch,
});
const outcome = await executor.execute(
bearerOperation(5),
{ limit: 1 },
{ routeId: ROUTE_ID, scope: scopeSnapshot() },
);
expect(outcome.kind).toBe("TRANSPORT_FAILURE");
await new Promise((resolve) => setTimeout(resolve, 60));
expect(rejections).toEqual([]);
} finally {
globalThis.removeEventListener?.(
"unhandledrejection",
onUnhandled as EventListener,
);
}
});
});
/**
* LIVE-05. A deadline TIMEOUT is an operational failure of the API call, not a
* caller decision. Excluding it from `api.request.failed` hides exactly the
* class of outage the telemetry exists to surface.
*/
describe("LIVE-05 deadline timeouts reach failure telemetry", () => {
function projectorHarness() {
const emitted: string[] = [];
const recorded: string[] = [];
const project = createHttpObservationProjector({
diagnostics: {
record: (input) => recorded.push(input.eventId),
},
telemetry: {
emit: (eventName) => emitted.push(eventName),
},
});
return { emitted, recorded, project };
}
const base = Object.freeze({
routeId: ROUTE_ID,
operationId: "TEST_LIST_ENTITIES",
diagnosticsOperation: "test.read",
errorKind: "TIMEOUT",
attemptCount: 1,
durationMs: 10,
effect: "NOT_APPLICABLE" as const,
terminalReason: "TIMEOUT",
});
it("emits exactly one api.request.failed for a deadline timeout", () => {
const harness = projectorHarness();
harness.project(
Object.freeze({
...base,
outcome: "TRANSPORT_FAILURE" as const,
cancellationOwner: "DEADLINE" as const,
}),
);
expect(harness.emitted).toEqual(["api.request.failed"]);
expect(harness.recorded).toEqual(["http.request.completed"]);
});
it("emits nothing for caller, route and shutdown cancellation", () => {
for (const owner of [
"CALLER",
"ROUTE_TRANSITION",
"SCOPE_FENCE",
"APPLICATION_SHUTDOWN",
] as const) {
const harness = projectorHarness();
harness.project(
Object.freeze({
...base,
outcome: "CANCELLED" as const,
errorKind: "REQUEST_ABORTED",
cancellationOwner: owner,
}),
);
expect(harness.emitted).toEqual([]);
}
});
it("still emits for an ordinary network and auth integration failure", () => {
const network = projectorHarness();
network.project(
Object.freeze({
...base,
outcome: "TRANSPORT_FAILURE" as const,
errorKind: "NETWORK_FAILURE",
terminalReason: "NETWORK_FAILURE",
}),
);
expect(network.emitted).toEqual(["api.request.failed"]);
const auth = projectorHarness();
auth.project(
Object.freeze({
...base,
outcome: "AUTH_INTEGRATION_FAILURE" as const,
errorKind: "CREDENTIAL_OWNER_FAILED",
terminalReason: "AUTH_INTEGRATION_FAILURE",
}),
);
expect(auth.emitted).toEqual(["api.request.failed"]);
});
});