Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 17 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,23 @@ 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);
});

it("does not let a caller-provided minimum shorten the default budget", () => {
expect(resolveDiagnosticNavigationTimeoutMs({}, 3_000)).toBe(10_000);
});

it("does not let a caller-provided minimum shorten the environment override", () => {
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