chore: sync the frontend template from 4dc033c to 8157ad4
The product was materialized from the template at `4dc033c` and has stayed on it through 43 template commits, so it was missing all three rounds of adapter remediation — including files it never had, such as the shared `abortable-operation` primitive and the `exact-snapshot` decoder that later fixes are written against. Taking only the newest round was not possible for that reason: the delta is coherent only as a whole. The product had not touched `src/adapters` at all since materialization, so the 140-file delta applied with a three-way merge and no conflicts. `package.json` was the single overlap and merged cleanly: the product owns `name`, the template contributed `check:adapter-inventory`, `check:remediation-ledger` and the image-resolve-signal type fixture. All 24 product-owned files — README, index.html, CI workflow, i18n catalog, home page, generated schemas, evidence scripts, component and visual snapshots — are byte-identical to `main`. `template.lock.json` now pins the synced revision and tree. Verified in this repository, not inherited from the template: six type projects, lint, nine gates (adapter inventory, remediation ledger, registries, diagnostics, realtime boundaries, architecture, browser file/storage boundaries, optional recipes, documentation), the production build, and 2,054 of 2,073 tests. The 19 failures are all in `tests/unit/ci-artifact-contract.test.ts` and are the same pre-existing sandbox RLIMIT, EMFILE, umask and `/tmp` permission behaviour the template records; four suites that failed once under parallel load pass in isolation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
002ba3624e
commit
4bff9ca151
@@ -10,6 +10,8 @@ import {
|
||||
const installed: InstalledHttpContract<unknown, unknown, unknown> =
|
||||
TEST_LIST_HTTP_CONTRACT;
|
||||
|
||||
const ROUTE_ID = "TEST_ROUTE";
|
||||
|
||||
const scope = Object.freeze({
|
||||
generation: 1,
|
||||
fingerprint: "scope-1",
|
||||
@@ -72,7 +74,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher: async () =>
|
||||
Response.json(
|
||||
@@ -82,7 +83,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
});
|
||||
|
||||
await expect(
|
||||
executor.execute(installed, { limit: 20 }, { scope }),
|
||||
executor.execute(installed, { limit: 20 }, { routeId: ROUTE_ID, scope }),
|
||||
).resolves.toMatchObject({
|
||||
kind: "RATE_LIMITED",
|
||||
effect: "NOT_APPLICABLE",
|
||||
@@ -104,7 +105,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
const attachCredentials = vi.fn(() => ({
|
||||
kind: "READY" as const,
|
||||
headers: {},
|
||||
credentials: "omit" as const,
|
||||
}));
|
||||
const fetcher = vi.fn();
|
||||
const executor = createContractHttpExecutor({
|
||||
@@ -119,7 +119,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
executor.execute(
|
||||
createInstalled,
|
||||
{ name: "created" },
|
||||
{ scope, ...(intent === undefined ? {} : { intent }) },
|
||||
{ routeId: ROUTE_ID, scope, ...(intent === undefined ? {} : { intent }) },
|
||||
),
|
||||
).resolves.toMatchObject({
|
||||
kind: "CONTRACT_VIOLATION",
|
||||
@@ -143,7 +143,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
const attachCredentials = vi.fn(() => ({
|
||||
kind: "READY" as const,
|
||||
headers: {},
|
||||
credentials: "omit" as const,
|
||||
}));
|
||||
const fetcher = vi.fn();
|
||||
const executor = createContractHttpExecutor({
|
||||
@@ -154,7 +153,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
});
|
||||
|
||||
await expect(
|
||||
executor.execute(installed, { limit: 20 }, { scope, intent }),
|
||||
executor.execute(installed, { limit: 20 }, { routeId: ROUTE_ID, scope, intent }),
|
||||
).resolves.toMatchObject({
|
||||
kind: "CONTRACT_VIOLATION",
|
||||
violation: {
|
||||
@@ -173,14 +172,14 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
label: "query with the canonical reserved header",
|
||||
operation: installed,
|
||||
input: { limit: 20 },
|
||||
context: { scope },
|
||||
context: { routeId: ROUTE_ID, scope },
|
||||
headerName: "Idempotency-Key",
|
||||
},
|
||||
{
|
||||
label: "valid KEYED command with a case-variant reserved header",
|
||||
operation: createInstalled,
|
||||
input: { name: "created" },
|
||||
context: { scope, intent: mutationIntent() },
|
||||
context: { routeId: ROUTE_ID, scope, intent: mutationIntent() },
|
||||
headerName: "iDeMpOtEnCy-KeY",
|
||||
},
|
||||
])(
|
||||
@@ -189,7 +188,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
const attachCredentials = vi.fn(() => ({
|
||||
kind: "READY" as const,
|
||||
headers: { [headerName]: "credential-owned-key" },
|
||||
credentials: "omit" as const,
|
||||
}));
|
||||
const fetcher = vi.fn();
|
||||
const executor = createContractHttpExecutor({
|
||||
@@ -234,7 +232,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher,
|
||||
sleep: async () => {},
|
||||
@@ -252,7 +249,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
executor.execute(
|
||||
retryingCreate,
|
||||
{ name: "created" },
|
||||
{ scope, intent: mutationIntent({ idempotencyKey: "logical-key" }) },
|
||||
{ routeId: ROUTE_ID, scope, intent: mutationIntent({ idempotencyKey: "logical-key" }) },
|
||||
),
|
||||
).resolves.toMatchObject({ kind: "SUCCESS" });
|
||||
expect(fetcher).toHaveBeenCalledTimes(2);
|
||||
@@ -275,7 +272,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher,
|
||||
});
|
||||
@@ -284,7 +280,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
executor.execute(
|
||||
installed,
|
||||
{ limit: 20 },
|
||||
{ scope },
|
||||
{ routeId: ROUTE_ID, scope },
|
||||
),
|
||||
).resolves.toMatchObject({ kind: "SUCCESS" });
|
||||
expect(fetcher).toHaveBeenCalledOnce();
|
||||
@@ -300,7 +296,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher: vi.fn(async (input) => {
|
||||
urls.push(String(input));
|
||||
@@ -317,6 +312,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
createInstalled,
|
||||
{ name: "created" },
|
||||
{
|
||||
routeId: ROUTE_ID,
|
||||
scope,
|
||||
intent: Object.freeze({
|
||||
intentId: "private-intent-id",
|
||||
@@ -348,12 +344,11 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher,
|
||||
});
|
||||
|
||||
await expect(executor.execute(installed, input, { scope })).resolves.toMatchObject({
|
||||
await expect(executor.execute(installed, input, { routeId: ROUTE_ID, scope })).resolves.toMatchObject({
|
||||
kind: "SUCCESS",
|
||||
});
|
||||
expect(String((fetcher.mock.calls as unknown[][])[0]?.[0])).toContain(
|
||||
@@ -368,7 +363,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher: vi.fn(),
|
||||
});
|
||||
@@ -389,11 +383,11 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
},
|
||||
} as unknown as typeof installed;
|
||||
|
||||
await expect(executor.execute(throwing, { limit: 20 }, { scope })).resolves.toMatchObject({
|
||||
await expect(executor.execute(throwing, { limit: 20 }, { routeId: ROUTE_ID, scope })).resolves.toMatchObject({
|
||||
kind: "CONTRACT_VIOLATION",
|
||||
effect: "NOT_APPLICABLE",
|
||||
});
|
||||
await expect(executor.execute(malformed, { limit: 20 }, { scope })).resolves.toMatchObject({
|
||||
await expect(executor.execute(malformed, { limit: 20 }, { routeId: ROUTE_ID, scope })).resolves.toMatchObject({
|
||||
kind: "CONTRACT_VIOLATION",
|
||||
effect: "NOT_APPLICABLE",
|
||||
});
|
||||
@@ -406,7 +400,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher: vi.fn(async () => Response.json({ malformed: true }, { status: 201 })),
|
||||
});
|
||||
@@ -416,6 +409,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
createInstalled,
|
||||
{ name: "created" },
|
||||
{
|
||||
routeId: ROUTE_ID,
|
||||
scope,
|
||||
intent: mutationIntent(),
|
||||
},
|
||||
@@ -441,7 +435,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher: vi.fn(async () => {
|
||||
current = false;
|
||||
@@ -458,6 +451,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
createInstalled,
|
||||
{ name: "created" },
|
||||
{
|
||||
routeId: ROUTE_ID,
|
||||
scope: fencedScope,
|
||||
intent: mutationIntent({ intentId: "intent-2", idempotencyKey: "key-2" }),
|
||||
},
|
||||
@@ -469,6 +463,64 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps a dispatched command MAYBE_APPLIED when a retry-time fence lands between scope checks", async () => {
|
||||
// Attempt 1 dispatches an idempotent command and receives 429. The retry
|
||||
// sleep resolves, the loop-entry scope check is still current, and only the
|
||||
// pre-dispatch final invariant observes the fence.
|
||||
let armed = false;
|
||||
let checksAfterArming = 0;
|
||||
const idempotentCommand: InstalledHttpContract<unknown, unknown, unknown> = {
|
||||
...createInstalled,
|
||||
contract: {
|
||||
...createInstalled.contract,
|
||||
retrySemantics: "IDEMPOTENT" as const,
|
||||
},
|
||||
frontend: { ...createInstalled.frontend, retryBudget: 1 as const },
|
||||
};
|
||||
const racingScope = Object.freeze({
|
||||
...scope,
|
||||
isCurrent: () => {
|
||||
if (!armed) return true;
|
||||
checksAfterArming += 1;
|
||||
// The retry loop entry still observes a current scope; the pre-dispatch
|
||||
// final invariant is the first observation of the fence.
|
||||
return checksAfterArming <= 1;
|
||||
},
|
||||
});
|
||||
const fetcher = vi.fn(async () =>
|
||||
Response.json({ type: "about:blank", title: "slow down", status: 429 }, {
|
||||
status: 429,
|
||||
}),
|
||||
);
|
||||
const executor = createContractHttpExecutor({
|
||||
baseUrl: "https://api.example/",
|
||||
maxRetryAttempts: 1,
|
||||
attachCredentials: () => ({ kind: "READY", headers: {} }),
|
||||
fetcher,
|
||||
sleep: async () => {
|
||||
armed = true;
|
||||
},
|
||||
random: () => 0,
|
||||
});
|
||||
|
||||
const outcome = await executor.execute(
|
||||
idempotentCommand,
|
||||
{ name: "created" },
|
||||
{
|
||||
routeId: ROUTE_ID,
|
||||
scope: racingScope,
|
||||
intent: mutationIntent({ idempotencyKey: null }),
|
||||
},
|
||||
);
|
||||
|
||||
expect(fetcher).toHaveBeenCalledTimes(1);
|
||||
expect(outcome).toMatchObject({
|
||||
kind: "CONTRACT_VIOLATION",
|
||||
violation: { kind: "SCOPE_FENCED" },
|
||||
effect: "MAYBE_APPLIED",
|
||||
});
|
||||
});
|
||||
|
||||
it("settles a credential hang at the total operation deadline", async () => {
|
||||
vi.useFakeTimers();
|
||||
let settled = false;
|
||||
@@ -479,7 +531,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
});
|
||||
|
||||
const result = executor
|
||||
.execute(operation({ deadlineMs: 5 }), { limit: 20 }, { scope })
|
||||
.execute(operation({ deadlineMs: 5 }), { limit: 20 }, { routeId: ROUTE_ID, scope })
|
||||
.then((outcome) => {
|
||||
settled = true;
|
||||
return outcome;
|
||||
@@ -519,7 +571,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher,
|
||||
monotonicNow: () => 0,
|
||||
@@ -532,7 +583,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
const result = executor.execute(
|
||||
operation({ deadlineMs: 5 }),
|
||||
{ limit: 20 },
|
||||
{ scope },
|
||||
{ routeId: ROUTE_ID, scope },
|
||||
);
|
||||
await vi.advanceTimersByTimeAsync(5);
|
||||
await flushMicrotasks();
|
||||
@@ -548,7 +599,14 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
expect(observe).toHaveBeenCalledTimes(iterationCount);
|
||||
for (const [observation] of observe.mock.calls) {
|
||||
expect(observation).toEqual(
|
||||
expect.objectContaining({ attempts: 1, certainty: "TIMEOUT" }),
|
||||
expect.objectContaining({
|
||||
attemptCount: 1,
|
||||
errorKind: "TIMEOUT",
|
||||
terminalReason: "TIMEOUT",
|
||||
cancellationOwner: "DEADLINE",
|
||||
routeId: ROUTE_ID,
|
||||
operationId: "TEST_LIST_ENTITIES",
|
||||
}),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -566,7 +624,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher: vi.fn(async () =>
|
||||
Response.json(
|
||||
@@ -582,7 +639,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
});
|
||||
|
||||
const result = executor
|
||||
.execute(installed, { limit: 20 }, { scope, signal: caller.signal })
|
||||
.execute(installed, { limit: 20 }, { routeId: ROUTE_ID, scope, signal: caller.signal })
|
||||
.then((outcome) => {
|
||||
settled = true;
|
||||
return outcome;
|
||||
@@ -608,7 +665,6 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
attachCredentials: () => ({
|
||||
kind: "READY",
|
||||
headers: {},
|
||||
credentials: "omit",
|
||||
}),
|
||||
fetcher: vi.fn(async () => new Response(body, { status: 200 })),
|
||||
});
|
||||
@@ -617,7 +673,7 @@ describe("descriptor-driven HTTP execution lifetime", () => {
|
||||
executor.execute(
|
||||
operation({ responseBody: "NONE" }),
|
||||
{ limit: 20 },
|
||||
{ scope },
|
||||
{ routeId: ROUTE_ID, scope },
|
||||
),
|
||||
).resolves.toMatchObject({
|
||||
kind: "TRANSPORT_FAILURE",
|
||||
|
||||
Reference in New Issue
Block a user