Files
wehub-resource-sync 85453da49f
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Docs / Validate docs (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Sync skills to ClawHub / Publish changed skills (push) Waiting to run
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:58:35 +08:00

177 lines
6.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Bundled-CLI smoke for `--page-side-compositing` (opt-in spike).
*
* Validates that:
* 1. The bundled CLI accepts the new flag.
* 2. The local `@hyperframes/shader-transitions` IIFE bundle carries the
* page-side compositor canary string (build is wired correctly).
* 3. Rendering the fixture WITH and WITHOUT the flag both produce valid
* MP4s with the same duration. (Pixel-equality is NOT a correctness
* property here — see the determinism note in the PR body.)
* 4. Wall-time pair is captured for the PR body.
*
* Per `feedback_validate_bundled_cli_not_dev_path.md`: the canonical
* execution path is the BUNDLED CLI at `packages/cli/dist/cli.js`, never
* `bun run` against raw TS sources. Do not "improve" this script to use
* `bun run` — bundle-specific bugs (path resolvers, env bootstrap, lazy
* modules) are invisible to the dev path.
*
* Usage from the repo root:
*
* node scripts/page-side-compositing-smoke/run.mjs
*
* Outputs:
*
* <tmpdir>/raw.mp4 (baseline path, flag off)
* <tmpdir>/page-side.mp4 (page-side path, flag on)
* <tmpdir>/wall-times.json (wall-time pair for the PR)
*/
import { execFileSync, spawnSync } from "node:child_process";
import {
copyFileSync,
existsSync,
mkdirSync,
mkdtempSync,
rmSync,
statSync,
writeFileSync,
} from "node:fs";
import { dirname, join, resolve } from "node:path";
import { tmpdir } from "node:os";
import { fileURLToPath } from "node:url";
const HERE = dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = resolve(HERE, "..", "..");
const FIXTURE_SRC = join(HERE, "fixture");
const WORK_DIR = mkdtempSync(join(tmpdir(), "hf-page-side-smoke-"));
const FIXTURE_RUN_DIR = join(WORK_DIR, "fixture");
const CLI_PATH = join(REPO_ROOT, "packages", "cli", "dist", "cli.js");
const SHADER_BUNDLE = join(REPO_ROOT, "packages", "shader-transitions", "dist", "index.global.js");
// Canary string defined in
// `packages/shader-transitions/src/engineModePageComposite.ts` —
// kept identical here on purpose. Test broken → engineModePageComposite.test
// fails first.
const PAGE_COMPOSITOR_CANARY = "__hf_page_compositor_v1__";
function note(line) {
process.stdout.write("[smoke] " + line + "\n");
}
function fail(msg) {
process.stderr.write("[smoke] FAIL: " + msg + "\n");
process.exit(1);
}
function assertExists(path, label) {
if (!existsSync(path)) fail(label + " missing at " + path);
}
function assertCanary() {
assertExists(SHADER_BUNDLE, "shader-transitions IIFE bundle");
const buf = execFileSync("grep", ["-c", PAGE_COMPOSITOR_CANARY, SHADER_BUNDLE]);
const count = Number(buf.toString().trim());
if (count < 1) {
fail(
"shader-transitions bundle is missing the page-side compositor canary " +
`("${PAGE_COMPOSITOR_CANARY}"). Rebuild @hyperframes/shader-transitions and re-run.`,
);
}
note(`canary present in ${SHADER_BUNDLE} (${count}× hit)`);
}
function assertCliCanary() {
assertExists(CLI_PATH, "bundled CLI");
// The CLI bundle should carry the env-var key for HF_PAGE_SIDE_COMPOSITING
// and the page-side flag name. Either confirms the engine + producer +
// CLI side of the change is wired through tsup.
const cliCanaries = ["HF_PAGE_SIDE_COMPOSITING", "page-side-compositing"];
for (const needle of cliCanaries) {
const buf = execFileSync("grep", ["-c", needle, CLI_PATH]);
const count = Number(buf.toString().trim());
if (count < 1) {
fail(`bundled CLI is missing canary "${needle}". Rebuild @hyperframes/cli and re-run.`);
}
note(`CLI bundle carries "${needle}" (${count}× hit)`);
}
}
function setupFixture() {
if (existsSync(WORK_DIR)) rmSync(WORK_DIR, { recursive: true, force: true });
mkdirSync(FIXTURE_RUN_DIR, { recursive: true });
copyFileSync(join(FIXTURE_SRC, "index.html"), join(FIXTURE_RUN_DIR, "index.html"));
copyFileSync(SHADER_BUNDLE, join(FIXTURE_RUN_DIR, "shader-transitions.global.js"));
note("fixture staged at " + FIXTURE_RUN_DIR);
}
function runRender(label, outputPath, extraArgs) {
note(`render: ${label}${outputPath}`);
const argv = [
CLI_PATH,
"render",
FIXTURE_RUN_DIR,
"-o",
outputPath,
"--fps",
"30",
"--workers",
"1",
"--quality",
"draft",
"--quiet",
...extraArgs,
];
const t0 = Date.now();
const res = spawnSync("node", argv, { stdio: "inherit", cwd: REPO_ROOT });
const wallMs = Date.now() - t0;
if (res.status !== 0) {
fail(`render "${label}" exited with status ${res.status}`);
}
if (!existsSync(outputPath)) {
fail(`render "${label}" did not produce ${outputPath}`);
}
const size = statSync(outputPath).size;
if (size < 1024) {
fail(`render "${label}" produced suspiciously small output (${size} bytes)`);
}
note(` wall=${(wallMs / 1000).toFixed(2)}s size=${(size / 1024).toFixed(1)}KB`);
return { label, wallMs, sizeBytes: size, outputPath };
}
function main() {
note(`repo root: ${REPO_ROOT}`);
assertExists(CLI_PATH, "bundled CLI (packages/cli/dist/cli.js)");
assertExists(SHADER_BUNDLE, "shader-transitions IIFE bundle");
assertCliCanary();
assertCanary();
setupFixture();
const baseline = runRender("baseline (flag OFF)", join(WORK_DIR, "raw.mp4"), []);
const pageSide = runRender("page-side (flag ON)", join(WORK_DIR, "page-side.mp4"), [
"--page-side-compositing",
]);
const summary = {
baseline: { wallMs: baseline.wallMs, sizeBytes: baseline.sizeBytes },
pageSide: { wallMs: pageSide.wallMs, sizeBytes: pageSide.sizeBytes },
walltimeRatio: baseline.wallMs / Math.max(1, pageSide.wallMs),
notes:
"fixture: 2s @ 30fps, 1280x720, single cross-warp-morph transition. " +
"Wall times include CLI startup + browser launch — for a perf signal, " +
"amortize over a longer fixture on the target host (Vance's Mac).",
};
writeFileSync(join(WORK_DIR, "wall-times.json"), JSON.stringify(summary, null, 2));
note("wrote " + join(WORK_DIR, "wall-times.json"));
note("baseline: " + (baseline.wallMs / 1000).toFixed(2) + "s");
note("page-side: " + (pageSide.wallMs / 1000).toFixed(2) + "s");
note(
`ratio (baseline/page-side): ${summary.walltimeRatio.toFixed(2)}× ` +
"(>1 means page-side faster, <1 means slower — sandbox is software " +
"WebGL, so a ratio near 1 here is expected and NOT predictive of Mac).",
);
note("OK");
}
main();