Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/packages/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ Word-level transcripts (whisper output) are grouped into readable caption cues o
| `--snapshots` | Write overview frames (annotated with labeled finding boxes when there are errors) plus `finding-NN-<code>.png` crops |
| `--samples` / `--at` / `--at-transitions` | Control the seek grid (default 9 samples; `--at-transitions` adds tween boundaries) |
| `--tolerance` | Allowed overflow in px before reporting (default 2) |
| `--timeout` | Initial settle budget in ms (default 3000) |
| `--timeout` | Initial render-ready budget in ms; also raises the page-navigation budget above its 10s floor (default 3000) |
| `--no-contrast` | Skip the WCAG audit while iterating |
| `--strict` | Exit non-zero on warnings too (default: only errors) |
| `--caption-zone "<x0=..;y0=..;x1=..;y1=..>"` | Opt-in band gate: flags content whose center sits inside the fractional band (optional `severity`, `seek`) |
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/capture/captureCompositionFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export interface SettledCompositionPage {
}

export interface OpenSettledCompositionPageOptions {
// Separate from the post-navigation render-ready budget. Diagnostic callers
// without their own navigation knob keep the historical 10-second minimum.
navigationTimeoutMs?: number;
renderReadyTimeoutMs: number;
renderReadyWarningSuffix: string;
// Screenshot paths take the engine's software-GPU default; validate/check
Expand Down Expand Up @@ -182,7 +185,7 @@ export async function openSettledCompositionPage(
await options.beforeNavigate?.(page);
await page.goto(url, {
waitUntil: "domcontentloaded",
timeout: resolveDiagnosticNavigationTimeoutMs(),
timeout: resolveDiagnosticNavigationTimeoutMs(process.env, options.navigationTimeoutMs),
});
const renderReadyTimedOut = !(await waitForCompositionSettle(page, options));
return { browser: chromeBrowser, page, renderReadyTimedOut };
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/commands/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ export function createCheckCommand(
},
timeout: {
type: "string",
description: "Ms to wait for scripts and media to settle initially (default: 3000)",
description:
"Initial render-ready timeout in ms; also sets the navigation minimum (10s floor, default: 3000)",
default: "3000",
},
contrast: {
Expand Down
22 changes: 22 additions & 0 deletions packages/cli/src/utils/checkBrowser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,28 @@ it("carries raw browser geometry through the page driver and pipeline", async ()
expect(mocks.serverClose).toHaveBeenCalledOnce();
});

it("uses check --timeout for both navigation and render-ready settling", async () => {
mountCanvasFixture();
const page = fakePage();
installSessionMock(page);

await runBrowserCheck(
PROJECT,
{ ...DEFAULT_CHECK_OPTIONS, samples: 1, contrast: false, timeout: 30_000 },
{ kind: "none" },
runAuditGrid,
);

expect(openSettledCompositionPage).toHaveBeenCalledWith(
"<html></html>",
"http://127.0.0.1:3000",
expect.objectContaining({
navigationTimeoutMs: 30_000,
renderReadyTimeoutMs: 30_000,
}),
);
});

it("round-trips the browser script's raw contrast candidates back into finish", async () => {
// The U2 regression class: Node parses prepare's candidates for reporting,
// but must hand the UNTOUCHED objects back to __contrastAuditFinish — the
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/utils/checkBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export async function runBrowserCheck(
try {
const launchSettleStart = Date.now();
const session = await openSettledCompositionPage(html, server.url, {
navigationTimeoutMs: options.timeout,
renderReadyTimeoutMs: options.timeout,
renderReadyWarningSuffix: "checking the current page state",
browserGpuMode: resolveCliChromeGpuMode(),
Expand Down Expand Up @@ -225,6 +226,7 @@ export async function captureFindingCrops(
const written: string[] = [];
try {
const session = await openSettledCompositionPage(html, server.url, {
navigationTimeoutMs: options.timeout,
renderReadyTimeoutMs: options.timeout,
renderReadyWarningSuffix: "capturing finding crops",
browserGpuMode: resolveCliChromeGpuMode(),
Expand Down
11 changes: 11 additions & 0 deletions packages/cli/src/utils/renderArgs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ describe("resolveDiagnosticNavigationTimeoutMs", () => {
resolveDiagnosticNavigationTimeoutMs({ PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS: "invalid" }),
).toBe(10_000);
});

it("raises the diagnostic navigation budget to a larger caller-provided minimum", () => {
expect(resolveDiagnosticNavigationTimeoutMs({}, 30_000)).toBe(30_000);
expect(resolveDiagnosticNavigationTimeoutMs({}, 3_000)).toBe(10_000);
expect(
resolveDiagnosticNavigationTimeoutMs(
{ PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS: "90000" },
30_000,
),
).toBe(90_000);
});
});

describe("parseCompositionEntryArg", () => {
Expand Down
12 changes: 10 additions & 2 deletions packages/cli/src/utils/renderArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,20 @@ export function resolveBrowserTimeoutMsArg(raw: string | undefined): number | un
return result.value;
}

/** Navigation budget shared by snapshot/check/inspect browser diagnostics. */
/**
* Navigation budget shared by snapshot/check/inspect browser diagnostics.
*
* The environment variable remains the historical global override. Callers
* with their own timeout knob can supply a minimum without shortening that
* override or the existing 10-second default.
*/
export function resolveDiagnosticNavigationTimeoutMs(
env: Record<string, string | undefined> = process.env,
minimumTimeoutMs = 0,
): number {
const parsed = Number(env.PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS);
return Number.isFinite(parsed) && parsed > 0 ? parsed : 10_000;
const configured = Number.isFinite(parsed) && parsed > 0 ? parsed : 10_000;
return Math.max(configured, minimumTimeoutMs);
}

// ── --composition ──────────────────────────────────────────────────────
Expand Down
2 changes: 1 addition & 1 deletion skills-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"files": 121
},
"hyperframes-cli": {
"hash": "966972db5ab8f932",
"hash": "42b621ca580541b6",
"files": 11
},
"hyperframes-core": {
Expand Down
2 changes: 1 addition & 1 deletion skills/hyperframes-cli/references/lint-validate-inspect.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ npx hyperframes check --samples 15 # denser timeline sweep (default 9)
npx hyperframes check --at 1.5,4,7.25 # explicit hero-frame timestamps
npx hyperframes check --at-transitions # also sample every tween start/end boundary
npx hyperframes check --tolerance 4 # allowed overflow px before reporting (default 2)
npx hyperframes check --timeout 5000 # ms for the initial settle (default 3000)
npx hyperframes check --timeout 30000 # initial render-ready + navigation minimum in ms (defaults: 3000 / 10000)
npx hyperframes check --no-contrast # skip the WCAG audit while iterating
npx hyperframes check --strict # exit non-zero on warnings too (default: only errors)
```
Expand Down
Loading