From ee138e41c472bd9ccdce1e44834eff790517cafa Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Fri, 30 Oct 2026 14:04:29 +0100 Subject: [PATCH 1/5] test(sdk): fast-forward retry backoff in two capability outcome tests The Hub enrollment and Compute Optimizer region-failure cases waited through the SDK's real 0.5+1+2+4+8s retry backoff, about 16s each. Run them on fake timers like the status probe retry tests: waitFor advances the admission waits before the first request, then the test advances past the backoff. Assertions, including all six attempts, are unchanged. Locally 15.5s -> 0.3s and 16.6s -> 1.4s. --- packages/sdk/test/discovery-http-capabilities.test.ts | 10 +++++++++- .../sdk/test/discovery-http-compute-optimizer.test.ts | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/sdk/test/discovery-http-capabilities.test.ts b/packages/sdk/test/discovery-http-capabilities.test.ts index e28a905..96b5d68 100644 --- a/packages/sdk/test/discovery-http-capabilities.test.ts +++ b/packages/sdk/test/discovery-http-capabilities.test.ts @@ -82,8 +82,16 @@ describe('live capability outcomes', () => { it('reports Hub enrollment as error when the enrollment status keeps failing', async () => { vi.spyOn(Math, 'random').mockReturnValue(0); + vi.useFakeTimers(); scenario.transientOperation = 'ListEnrollmentStatuses'; - const result = await discoverRules(['CLDBRN-AWS-COSTOPTIMIZATIONHUB-1']); + const pending = discoverRules(['CLDBRN-AWS-COSTOPTIMIZATIONHUB-1']); + // With fake timers, each waitFor check also advances the admission waits that precede the first request. + await vi.waitFor( + () => expect(requests.some((request) => request.operation === 'ListEnrollmentStatuses')).toBe(true), + { timeout: 10_000 }, + ); + await vi.advanceTimersByTimeAsync(120_000); + const result = await pending; expect(capabilitiesOf(result)).toEqual([ { diff --git a/packages/sdk/test/discovery-http-compute-optimizer.test.ts b/packages/sdk/test/discovery-http-compute-optimizer.test.ts index a9f4a9b..dfff7d7 100644 --- a/packages/sdk/test/discovery-http-compute-optimizer.test.ts +++ b/packages/sdk/test/discovery-http-compute-optimizer.test.ts @@ -78,10 +78,18 @@ describe('live capability outcomes', () => { }; scenario.transientOperation = 'GetLambdaFunctionRecommendations'; scenario.transientHostname = 'compute-optimizer.us-east-1.amazonaws.com'; - const result = await discoverRules(['CLDBRN-AWS-LAMBDA-4'], { + vi.useFakeTimers(); + const pending = discoverRules(['CLDBRN-AWS-LAMBDA-4'], { mode: 'regions', regions: ['eu-west-1', 'us-east-1'], }); + // With fake timers, each waitFor check also advances the admission waits that precede the regional request. + await vi.waitFor( + () => expect(requests.some((request) => request.operation === 'GetLambdaFunctionRecommendations')).toBe(true), + { timeout: 10_000 }, + ); + await vi.advanceTimersByTimeAsync(120_000); + const result = await pending; expect(capabilitiesOf(result)).toEqual([ { From dc1878e801371f272aca5f127c1e6eb34542f431 Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Fri, 30 Oct 2026 14:06:59 +0100 Subject: [PATCH 2/5] fix(docs): skip generated build output in the documentation check docs:check walked every directory except .git and node_modules, so after a VS Code build it failed on packages/vscode/dist/vscode/media/README.md, a staged copy whose links resolve only in the published extension. Skip the Git-ignored dist, .turbo and coverage directories as well. --- docs/TESTING.md | 3 ++- scripts/check-docs.mjs | 6 +++++- test/docs-check.test.mjs | 10 ++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/TESTING.md b/docs/TESTING.md index e1d2b06..e79eb24 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -238,7 +238,8 @@ pnpm verify and `scripts/check-owning-pages.mjs` against temporary Git branches and pull request descriptions. The live `docs:check` validates required entry points, root and package instruction aliases, repository-contained local links, heading fragments, reference-style definitions and uses, code-example exclusion, canonical page reachability, and the root -`AGENTS.md` line budget. +`AGENTS.md` line budget. It skips Git-ignored `dist`, `.turbo`, and `coverage` output, whose staged copies such as the +packaged VS Code README carry links that resolve only after publishing. ## CI and task caching diff --git a/scripts/check-docs.mjs b/scripts/check-docs.mjs index 9136c5f..d0666f8 100644 --- a/scripts/check-docs.mjs +++ b/scripts/check-docs.mjs @@ -21,10 +21,14 @@ const exists = async (path) => { } }; +// Dependencies and generated output are Git-ignored; staged copies such as a packaged README carry links that resolve +// only after publishing. +const skippedDirectories = new Set(['.git', 'node_modules', 'dist', '.turbo', 'coverage']); + const walk = async (directory) => { const paths = []; for (const entry of await readdir(directory, { withFileTypes: true })) { - if (entry.name === '.git' || entry.name === 'node_modules') continue; + if (skippedDirectories.has(entry.name)) continue; const path = resolve(directory, entry.name); paths.push(path); if (entry.isDirectory()) paths.push(...(await walk(path))); diff --git a/test/docs-check.test.mjs b/test/docs-check.test.mjs index e27b4b2..69a4b22 100644 --- a/test/docs-check.test.mjs +++ b/test/docs-check.test.mjs @@ -51,6 +51,16 @@ test('accepts a valid repository and its root and package aliases', async () => assert.match(result.stdout, /Documentation check passed/); }); +test('ignores generated build output such as a staged package README', async () => { + const root = await createFixtureRepository(); + await mkdir(join(root, 'packages/example/dist/media'), { recursive: true }); + await writeFile(join(root, 'packages/example/dist/media/README.md'), '[Guide](../../../docs/missing.md)\n'); + + const result = await runChecker(root); + + assert.equal(result.code, 0, result.stderr); +}); + test('rejects a missing required documentation entry point', async () => { const root = await createFixtureRepository(); await rm(join(root, 'docs/README.md')); From 2160a0f5bb8167895246e82bc05de6b489ba7692 Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Fri, 30 Oct 2026 14:15:09 +0100 Subject: [PATCH 3/5] test(sdk): run more Vitest workers than CPUs Vitest defaults to one worker fewer than the CPU count, three on the 4-vCPU CI runners. The discovery HTTP suites spend most of their time waiting on admission timers, so the CPU-bound files queue behind them. Use 1.5x the CPU count; Vitest caps percentage values at the CPU count, so compute it. --- packages/sdk/vitest.config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/sdk/vitest.config.ts b/packages/sdk/vitest.config.ts index 10699d0..6f0f8fe 100644 --- a/packages/sdk/vitest.config.ts +++ b/packages/sdk/vitest.config.ts @@ -1,3 +1,4 @@ +import { availableParallelism } from 'node:os'; import { fileURLToPath } from 'node:url'; import { defineConfig } from 'vitest/config'; @@ -13,6 +14,9 @@ export default defineConfig({ // Loaded CI runners stretch them several times over; keep budgets above that instead of Vitest's 5s default. testTimeout: 30_000, hookTimeout: 30_000, + // Those suites mostly wait on timers, so more workers than CPUs keep the other files moving beside them. Vitest caps + // percentage values at the CPU count, so compute the number. + maxWorkers: Math.ceil(availableParallelism() * 1.5), coverage: { provider: 'v8', }, From 5461d10b8da6d5392117d88ed8ab774400c14fc3 Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Fri, 30 Oct 2026 14:23:20 +0100 Subject: [PATCH 4/5] test(sdk): share the fake-timer settle step between retry tests --- .../sdk/test/discovery-http-capabilities.test.ts | 9 ++------- .../discovery-http-compute-optimizer.test.ts | 9 ++------- packages/sdk/test/helpers/discovery-http.ts | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/sdk/test/discovery-http-capabilities.test.ts b/packages/sdk/test/discovery-http-capabilities.test.ts index 96b5d68..fb42bab 100644 --- a/packages/sdk/test/discovery-http-capabilities.test.ts +++ b/packages/sdk/test/discovery-http-capabilities.test.ts @@ -9,6 +9,7 @@ import { region, requests, scenario, + settleOnFakeTimers, useDiscoveryHttpHarness, } from './helpers/discovery-http.js'; @@ -85,13 +86,7 @@ describe('live capability outcomes', () => { vi.useFakeTimers(); scenario.transientOperation = 'ListEnrollmentStatuses'; const pending = discoverRules(['CLDBRN-AWS-COSTOPTIMIZATIONHUB-1']); - // With fake timers, each waitFor check also advances the admission waits that precede the first request. - await vi.waitFor( - () => expect(requests.some((request) => request.operation === 'ListEnrollmentStatuses')).toBe(true), - { timeout: 10_000 }, - ); - await vi.advanceTimersByTimeAsync(120_000); - const result = await pending; + const result = await settleOnFakeTimers(pending, 'ListEnrollmentStatuses'); expect(capabilitiesOf(result)).toEqual([ { diff --git a/packages/sdk/test/discovery-http-compute-optimizer.test.ts b/packages/sdk/test/discovery-http-compute-optimizer.test.ts index dfff7d7..9996937 100644 --- a/packages/sdk/test/discovery-http-compute-optimizer.test.ts +++ b/packages/sdk/test/discovery-http-compute-optimizer.test.ts @@ -6,6 +6,7 @@ import { expectReadOnlyRequests, requests, scenario, + settleOnFakeTimers, useDiscoveryHttpHarness, useLambdaScenario, } from './helpers/discovery-http.js'; @@ -83,13 +84,7 @@ describe('live capability outcomes', () => { mode: 'regions', regions: ['eu-west-1', 'us-east-1'], }); - // With fake timers, each waitFor check also advances the admission waits that precede the regional request. - await vi.waitFor( - () => expect(requests.some((request) => request.operation === 'GetLambdaFunctionRecommendations')).toBe(true), - { timeout: 10_000 }, - ); - await vi.advanceTimersByTimeAsync(120_000); - const result = await pending; + const result = await settleOnFakeTimers(pending, 'GetLambdaFunctionRecommendations'); expect(capabilitiesOf(result)).toEqual([ { diff --git a/packages/sdk/test/helpers/discovery-http.ts b/packages/sdk/test/helpers/discovery-http.ts index 71e9b3a..8766671 100644 --- a/packages/sdk/test/helpers/discovery-http.ts +++ b/packages/sdk/test/helpers/discovery-http.ts @@ -544,6 +544,22 @@ export const volumeAttempt = () => // Public cancellation rejects promptly; let the detached request release its // SQLite lease before this fixture deletes its private admission directory. +/** + * Settles discovery started under fake timers, skipping its admission waits and retry backoff. + * + * @param pending - Discovery started after `vi.useFakeTimers()`. + * @param operation - The AWS operation whose first request precedes the backoff. + * @returns The settled discovery result. + */ +export const settleOnFakeTimers = async (pending: Promise, operation: string): Promise => { + // Each waitFor check also advances fake timers, moving the admission waits that precede the request. + await vi.waitFor(() => expect(requests.some((request) => request.operation === operation)).toBe(true), { + timeout: 10_000, + }); + await vi.advanceTimersByTimeAsync(120_000); + return pending; +}; + /** Waits until a cancelled catalog request releases its admission lease. */ export const waitForCancelledCatalogCleanup = async () => { if (held.length === 0) return; From c98c71b17c0631f43ba260aab855fab6dee69ef8 Mon Sep 17 00:00:00 2001 From: Axon Stone Date: Fri, 30 Oct 2026 14:24:50 +0100 Subject: [PATCH 5/5] test(sdk): keep the lease cleanup comment on its helper --- packages/sdk/test/helpers/discovery-http.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk/test/helpers/discovery-http.ts b/packages/sdk/test/helpers/discovery-http.ts index 8766671..5d395d9 100644 --- a/packages/sdk/test/helpers/discovery-http.ts +++ b/packages/sdk/test/helpers/discovery-http.ts @@ -542,8 +542,6 @@ export const volumeAttempt = () => .map((message) => JSON.parse(message.slice(13))) .find((attempt) => attempt.operation === 'DescribeVolumes'); -// Public cancellation rejects promptly; let the detached request release its -// SQLite lease before this fixture deletes its private admission directory. /** * Settles discovery started under fake timers, skipping its admission waits and retry backoff. * @@ -560,6 +558,8 @@ export const settleOnFakeTimers = async (pending: Promise, operation: stri return pending; }; +// Public cancellation rejects promptly; let the detached request release its +// SQLite lease before this fixture deletes its private admission directory. /** Waits until a cancelled catalog request releases its admission lease. */ export const waitForCancelledCatalogCleanup = async () => { if (held.length === 0) return;